电影推荐系统kaggle
一、推薦系統的時代
數據收集的快速增長帶來了一個新的信息時代。數據正被用于創建更高效的系統,而這正是推薦系統發揮作用的地方。推薦系統是一種信息過濾系統,因為它們可以提高搜索結果的質量,并提供與搜索項目更相關或與用戶的搜索歷史更相關的項目。
它們用于預測用戶對某個項目的評分或偏好。幾乎每一家大型科技公司都以某種形式應用了它們:亞馬遜用它來向客戶推薦產品,YouTube用它來決定下一步在autoplay上播放哪個視頻,Facebook用它來推薦喜歡的頁面和關注的人。此外,像Netflix和Spotify這樣的公司在很大程度上依賴其推薦引擎的有效性來實現其業務和成功。
在這個內核中,我們將使用TMDB5000電影數據集構建一個基線電影推薦系統。對于像我這樣的新手來說,這個內核將在推薦系統中起到很好的基礎作用,并將為您提供一些東西。
那我們走吧!
推薦系統基本上有三種類型:-
人口統計過濾——根據電影人氣和/或類型,向每個用戶提供一般性建議。該系統向具有相似人口統計特征的用戶推薦相同的電影。由于每個用戶都是不同的,這種方法被認為太簡單了。這一體系背后的基本理念是,更受歡迎、更受好評的電影更容易受到普通觀眾的喜愛。
基于內容的過濾-他們建議基于特定項目的類似項目。該系統使用項目元數據,例如電影的類型、導演、描述、演員等,來提出這些建議。這些推薦系統背后的一般理念是,如果一個人喜歡某個特定的項目,他或她也會喜歡與之相似的項目。
協同過濾-此系統匹配具有相似興趣的人,并基于此匹配提供建議。與基于內容的過濾器不同,協作過濾器不需要項目元數據。
二、加載數據
數據來源:Getting Started with a Movie Recommendation System | KaggleExplore and run machine learning code with Kaggle Notebooks | Using data from TMDB 5000 Movie Datasethttps://www.kaggle.com/ibtesama/getting-started-with-a-movie-recommendation-system/data
import pandas as pd import numpy as np df1=pd.read_csv('../input/tmdb-movie-metadata/tmdb_5000_credits.csv') df2=pd.read_csv('../input/tmdb-movie-metadata/tmdb_5000_movies.csv')第一個數據集包含以下功能:-
電影id-每部電影的唯一標識符。
演員-主角和配角的名字。
劇組-導演、編輯、作曲家、作家等的姓名。
第二個數據集具有以下功能:-
預算-制作電影的預算。
類型-電影、動作片、喜劇、驚悚片等的類型。
主頁-電影主頁的鏈接。
id-這實際上是第一個數據集中的電影id。
關鍵詞-與電影相關的關鍵詞或標簽。
原創語言-電影制作時使用的語言。
原片名-翻譯或改編前的電影片名。
概述-電影的簡要描述。
流行度-指定電影流行度的數字量。
制片公司——電影的制片公司。
生產國-生產該產品的國家。
發布日期-發布的日期。
收入-電影產生的全球收入。
runtime—電影的運行時間(分鐘)。
狀態-“發布”或“傳聞”。
標語-電影的標語。
片名——電影的片名。
投票平均-電影的平均收視率。
計票-收到的票數。
讓我們將“id”列上的兩個數據集連接起來
df1.columns = ['id','tittle','cast','crew'] df2= df2.merge(df1,on='id')人口統計過濾-
在開始之前-
我們需要一個指標來評分或評價電影
計算每部電影的分數
對分數進行排序,并向用戶推薦評級最好的電影。
我們可以用電影的平均收視率作為分數,但這樣做是不夠公平的,因為平均收視率為8.9且只有3票的電影不能被認為比平均收視率為7.8但只有40票的電影更好。因此,我將使用IMDB的加權評級(wr),如下所示:-
哪里
v是電影的票數;
m是圖表中列出的最低票數;
R是電影的平均收視率;和
C是整個報告的平均投票數
我們已經有了v(投票計數)和R(投票平均數),C可以計算為
C= df2['vote_average'].mean()因此,所有電影的平均評分在10分制下約為6。下一步是確定m的適當值,即圖表中列出的最低投票數。我們將使用第90百分位作為我們的分界點。換句話說,要讓一部電影在排行榜上占據一席之地,它必須擁有比列表中至少90%的電影更多的選票。
m= df2['vote_count'].quantile(0.9)現在,我們可以篩選出符合圖表要求的電影
q_movies = df2.copy().loc[df2['vote_count'] >= m] q_movies.shape我們看到有481部電影符合這個名單。現在,我們需要計算每部合格電影的指標。為此,我們將定義一個函數,weighted_rating(),并定義一個新的功能評分,我們將通過將此函數應用于合格電影的數據幀來計算該值:
def weighted_rating(x, m=m, C=C):v = x['vote_count']R = x['vote_average']# 基于IMDB公式的計算return (v/(v+m) * R) + (m/(m+v) * C) # 定義一個新功能“分數”,并使用“加權評分”(weighted_rating)計算其值` q_movies['score'] = q_movies.apply(weighted_rating, axis=1)最后,讓我們根據分數特性對數據幀進行排序,并輸出前10部電影的標題、投票數、投票平均數和加權評級或分數
#根據上面計算的分數對電影進行排序 q_movies = q_movies.sort_values('score', ascending=False)#Print the top 15 movies q_movies[['title', 'vote_count', 'vote_average', 'score']].head(10)萬歲!我們已經做了我們的第一個(雖然很基本)推薦人。在這些系統的“現在趨勢”選項卡下,我們可以找到非常受歡迎的電影,只需按“受歡迎程度”列對數據集進行排序即可獲得。
pop= df2.sort_values('popularity', ascending=False) import matplotlib.pyplot as plt plt.figure(figsize=(12,4))plt.barh(pop['title'].head(6),pop['popularity'].head(6), align='center',color='skyblue') plt.gca().invert_yaxis() plt.xlabel("Popularity") plt.title("Popular Movies")現在需要記住的是,這些人口統計推薦人為所有用戶提供了一個推薦電影的通用圖表。他們對特定用戶的興趣和品味不敏感。這就是我們轉向更精細的系統——基于內容的過濾的時候了。
三、基于內容的過濾
在這個推薦系統中,電影的內容(概述、演員陣容、劇組、關鍵詞、標語等)被用來尋找與其他電影的相似之處。然后推薦最有可能相似的電影。
四、基于圖描述的推薦器
我們將根據情節描述計算所有電影的成對相似性分數,并根據該相似性分數推薦電影。數據集的概述功能中給出了繪圖描述。讓我們看一下數據…
df2['overview'].head(5)對于任何之前做過一點文本處理的人來說,都知道我們需要轉換每個概述的單詞向量。現在,我們將為每個概述計算術語頻率逆文檔頻率(TF-IDF)向量。
現在,如果您想知道什么是術語頻率,那么它是文檔中一個單詞的相對頻率,并以(術語實例/總實例)的形式給出。反向文檔頻率是包含術語的文檔的相對計數,以log(文檔數/包含術語的文檔數)的形式給出。每個單詞對其出現的文檔的總體重要性等于TF*IDF
這將為您提供一個矩陣,其中每列表示概述詞匯表中的一個單詞(至少在一個文檔中出現的所有單詞),每行表示一部電影,如前所述。這樣做是為了降低情節概述中經常出現的單詞的重要性,從而降低它們在計算最終相似性分數時的重要性。
幸運的是,scikit learn為您提供了一個內置的TfIdfVectorizer類,該類在幾行中生成TF-IDF矩陣。太好了,不是嗎?
?
我們發現,在我們的數據集中,有超過20000個不同的詞被用來描述4800部電影。
有了這個矩陣,我們現在可以計算相似性分數了。這方面有幾個候選人;例如歐幾里得、皮爾遜和余弦相似性分數。對于哪個分數最好,沒有正確的答案。不同的分數在不同的場景中效果很好,使用不同的指標進行實驗通常是一個好主意。
我們將使用余弦相似性來計算表示兩部電影之間相似性的數字量。我們使用余弦相似性分數,因為它與震級無關,并且計算起來相對簡單和快速。在數學上,其定義如下:
由于我們使用了TF-IDF矢量器,計算點積將直接得到余弦相似性分數。因此,我們將使用sklearn的線性內核()而不是余弦內核(),因為它速度更快。
# Import linear_kernel from sklearn.metrics.pairwise import linear_kernel# Compute the cosine similarity matrix cosine_sim = linear_kernel(tfidf_matrix, tfidf_matrix)我們將定義一個函數,該函數接收電影標題作為輸入,并輸出10部最相似電影的列表。首先,為此,我們需要電影標題和數據幀索引的反向映射。換句話說,我們需要一種機制來識別元數據數據框中給定電影標題的電影索引。
#Construct a reverse map of indices and movie titles indices = pd.Series(df2.index, index=df2['title']).drop_duplicates()我們現在可以很好地定義我們的推薦函數。以下是我們將遵循的步驟:-
獲取給定電影標題的電影索引。
獲取特定電影與所有電影的余弦相似性分數列表。將其轉換為元組列表,其中第一個元素是其位置,第二個元素是相似性分數。
根據相似度得分對上述元組列表進行排序;即第二個要素。
獲取此列表的前10個元素。忽略第一個元素,因為它指的是自我(與特定電影最相似的電影是電影本身)。
返回與頂部元素的索引相對應的標題。
# Function that takes in movie title as input and outputs most similar movies def get_recommendations(title, cosine_sim=cosine_sim):# Get the index of the movie that matches the titleidx = indices[title]# Get the pairwsie similarity scores of all movies with that moviesim_scores = list(enumerate(cosine_sim[idx]))# Sort the movies based on the similarity scoressim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)# Get the scores of the 10 most similar moviessim_scores = sim_scores[1:11]# Get the movie indicesmovie_indices = [i[0] for i in sim_scores]# Return the top 10 most similar moviesreturn df2['title'].iloc[movie_indices] get_recommendations('The Dark Knight Rises') get_recommendations('The Avengers')?
雖然我們的系統在尋找情節描述相似的電影方面做得不錯,但推薦的質量并不是很好。《黑暗騎士崛起》將返回所有蝙蝠俠電影,而喜歡該電影的人更有可能更喜歡克里斯托弗·諾蘭的其他電影。這是當前系統無法捕捉到的。
五、基于信用、類型和關鍵字的推薦器
不用說,隨著更好的元數據的使用,我們的推薦者的質量將會提高。這正是我們在本節要做的。我們將基于以下元數據構建一個推薦器:3位頂級演員、導演、相關類型和電影情節關鍵詞。
從演員、劇組和關鍵詞特征中,我們需要提取三個最重要的演員,導演和與該電影相關的關鍵詞。現在,我們的數據以“字符串化”列表的形式存在,我們需要將其轉換為安全和可用的結構
# Parse the stringified features into their corresponding python objects from ast import literal_evalfeatures = ['cast', 'crew', 'keywords', 'genres'] for feature in features:df2[feature] = df2[feature].apply(literal_eval)接下來,我們將編寫函數,幫助我們從每個特性中提取所需的信息。
# Get the director's name from the crew feature. If director is not listed, return NaN def get_director(x):for i in x:if i['job'] == 'Director':return i['name']return np.nan # Returns the list top 3 elements or entire list; whichever is more. def get_list(x):if isinstance(x, list):names = [i['name'] for i in x]#Check if more than 3 elements exist. If yes, return only first three. If no, return entire list.if len(names) > 3:names = names[:3]return names#Return empty list in case of missing/malformed datareturn [] # Define new director, cast, genres and keywords features that are in a suitable form. df2['director'] = df2['crew'].apply(get_director)features = ['cast', 'keywords', 'genres'] for feature in features:df2[feature] = df2[feature].apply(get_list) # Print the new features of the first 3 films df2[['title', 'cast', 'director', 'keywords', 'genres']].head(3)下一步是將名稱和關鍵字實例轉換為小寫,并去掉它們之間的所有空格。這樣做是為了我們的矢量器不會將“Johnny Depp”和“Johnny Galecki”中的Johnny計算為相同的值。
# Function to convert all strings to lower case and strip names of spaces def clean_data(x):if isinstance(x, list):return [str.lower(i.replace(" ", "")) for i in x]else:#Check if director exists. If not, return empty stringif isinstance(x, str):return str.lower(x.replace(" ", ""))else:return '' # Apply clean_data function to your features. features = ['cast', 'keywords', 'director', 'genres']for feature in features:df2[feature] = df2[feature].apply(clean_data)?我們現在可以創建我們的“元數據湯”,它是一個字符串,包含我們想要提供給向量器的所有元數據(即參與者、導演和關鍵字)。
def create_soup(x):return ' '.join(x['keywords']) + ' ' + ' '.join(x['cast']) + ' ' + x['director'] + ' ' + ' '.join(x['genres']) df2['soup'] = df2.apply(create_soup, axis=1)?接下來的步驟與我們使用基于情節描述的推薦器所做的步驟相同。一個重要的區別是我們使用CountVectorizer()而不是TF-IDF。這是因為,如果一個演員/導演在相對較多的電影中表演或導演,我們不想貶低他的存在。這沒有什么直觀的意義。
# Import CountVectorizer and create the count matrix from sklearn.feature_extraction.text import CountVectorizercount = CountVectorizer(stop_words='english') count_matrix = count.fit_transform(df2['soup']) # Compute the Cosine Similarity matrix based on the count_matrix from sklearn.metrics.pairwise import cosine_similaritycosine_sim2 = cosine_similarity(count_matrix, count_matrix) # Reset index of our main DataFrame and construct reverse mapping as before df2 = df2.reset_index() indices = pd.Series(df2.index, index=df2['title'])?現在,我們可以通過傳入新的cosine_sim2矩陣作為第二個參數來重用get_recommendations()函數。
get_recommendations('The Dark Knight Rises', cosine_sim2) get_recommendations('The Godfather', cosine_sim2)我們看到我們的推薦人由于更多的元數據而成功地捕獲了更多的信息,并且(可以說)給了我們更好的推薦。驚奇漫畫或DC漫畫迷更可能喜歡同一家制片公司的電影。因此,我們可以在上述功能的基礎上增加生產公司。我們還可以通過在湯中多次添加該功能來增加控制器的重量。
協同過濾
我們基于內容的引擎受到一些嚴重限制。它只能推薦與某部電影相近的電影。也就是說,它無法捕捉品味并提供跨流派的推薦。
此外,我們構建的引擎并不是真正的個性化引擎,因為它不能捕捉用戶的個人喜好和偏見。任何查詢我們的引擎以獲得基于某部電影的推薦的人,無論她/他是誰,都將收到與該電影相同的推薦。
因此,在本節中,我們將使用一種稱為協同過濾的技術向電影觀眾提出建議。它基本上有兩種類型:
基于用戶的過濾
-這些系統向類似用戶喜歡的用戶推薦產品。為了測量兩個用戶之間的相似性,我們可以使用皮爾遜相關或余弦相似性。這種過濾技術可以用一個例子來說明。在下面的矩陣中,每一行代表一個用戶,而列對應不同的電影,除了最后一個記錄該用戶和目標用戶之間的相似性的電影。每個單元格表示用戶對該電影的評級。假設用戶E是目標。
由于用戶A和F與用戶E沒有任何共同的電影評級,因此它們與用戶E的相似性在Pearson相關性中沒有定義。因此,我們只需要考慮基于皮爾森相關的用戶B、C和D,我們就可以計算出以下相似性。
從上表中我們可以看出,用戶D與用戶E之間的Pearson相關性為負,因此用戶D與用戶E非常不同。他在你之前給我的評分高于他的平均評分,而用戶E則相反。現在,我們可以開始填寫用戶沒有根據其他用戶評價的電影的空白。
雖然計算基于用戶的CF非常簡單,但它存在幾個問題。一個主要問題是用戶的偏好會隨著時間的推移而改變。這表明基于相鄰用戶預計算矩陣可能會導致性能下降。為了解決這個問題,我們可以應用基于項目的CF。
基于項目的協同過濾-
基于項目的CF根據項目與目標用戶評分的項目的相似性推薦項目,而不是測量用戶之間的相似性。同樣,相似性可以用皮爾遜相關或余弦相似性計算。主要區別在于,使用基于項目的協同過濾,我們垂直填充空白,與基于用戶的CF的水平方式相反。下表顯示了如何為電影“我在你面前”執行此操作。
它成功地避免了動態用戶偏好帶來的問題,因為基于項目的CF更加靜態。然而,這種方法仍然存在一些問題。首先,主要問題是可伸縮性。計算量隨著客戶和產品的增長而增長。最壞情況下的復雜度是O(mn),有m個用戶和n個項目。此外,稀疏性是另一個問題。再看一下上面的表格。雖然只有一個用戶同時對《黑客帝國》和《泰坦尼克號》進行了評級,但兩者之間的相似性為1。在極端情況下,我們可以擁有數百萬用戶,而兩部完全不同的電影之間的相似性可能非常高,這僅僅是因為只有一位用戶對這兩部電影進行了排名,而這兩部電影的排名相似。
單值分解
處理CF產生的可伸縮性和稀疏性問題的一種方法是利用潛在因素模型來捕獲用戶和項目之間的相似性。本質上,我們希望將推薦問題轉化為優化問題。我們可以將其視為我們在預測給定用戶的項目評級方面有多好。一個常見的度量是均方根誤差(RMSE)。RMSE越低,性能越好。
現在談到潛在因素,你可能會想知道它是什么?它是一個廣義的概念,描述了用戶或項目所具有的屬性或概念。例如,對于音樂,潛在因素可以指音樂所屬的流派。奇異值分解通過提取效用矩陣的潛在因子來降低效用矩陣的維數。本質上,我們將每個用戶和每個項目映射到一個維度為r的潛在空間。因此,它有助于我們更好地理解用戶和項目之間的關系,因為它們具有直接可比性。下圖說明了這一想法。
說得夠多了,讓我們看看如何實現這一點。因為我們以前使用的數據集沒有userId(這對于協作過濾是必需的),所以讓我們加載另一個數據集。我們將使用驚奇庫來實現SVD。?
?請注意,在這個數據集中,電影的評級為5級,與之前的不同。
data = Dataset.load_from_df(ratings[['userId', 'movieId', 'rating']], reader) data.split(n_folds=5) svd = SVD() evaluate(svd, data, measures=['RMSE', 'MAE'])我們得到的平均根平均平方誤差約為0.89,這對于我們的情況來說已經足夠好了。現在讓我們對數據集進行訓練,并得出預測。
trainset = data.build_full_trainset() svd.fit(trainset)讓我們選擇用戶Id為1的用戶,并檢查她/他給出的評分。
ratings[ratings['userId'] == 1] svd.predict(1, 302, 3)對于ID為302的電影,我們得到的估計預測值為2.618。這個推薦系統的一個驚人的特點是它不在乎電影是什么(或包含什么)。它完全基于指定的電影ID工作,并嘗試根據其他用戶對電影的預測來預測收視率。
結論
我們使用人口統計、基于內容和協作過濾創建推薦人。雖然人口統計過濾非常簡單,無法實際使用,但混合系統可以利用基于內容的過濾和協作過濾,因為這兩種方法幾乎是互補的。這個模型是非常基本的,只提供了一個基本的框架。
我想提一下我從中學到的一些很好的參考資料
https://hackernoon.com/introduction-to-recommender-system-part-1-collaborative-filtering-singular-value-decomposition-44c9659c5e75
https://www.kaggle.com/rounakbanik/movie-recommender-systems
http://trouvus.com/wp-content/uploads/2016/03/A-hybrid-movie-recommender-system-based-on-neural-networks.pdf
總結
以上是生活随笔為你收集整理的电影推荐系统kaggle的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDOJ 2526 HDU 2526 浪
- 下一篇: 【原创】StreamInsight查询系