基于知识的推荐系统(案例学习)
1. 簡單的流程
knowledge-based推薦系統沒有考慮特殊用戶的偏好;也沒有嘗試去推斷不同電影之間的相似性。以Internet Movie Database (IMDB)為例,基本流程可以概述為:
- 選擇度量(或評分標準)為電影打分
- 決定電影在排行榜上出現的先決條件
- 計算每一部滿足條件的電影的得分
- 按照分數的遞減順序輸出電影列表
2. 度量 metric
以電影推薦為例:如果一部電影的評分高于另一部電影,那么它就被認為比另一部電影更好。魯棒而可靠的度量標準對于電影評分來說非常重要,是影響推薦結果的關鍵。
度量的選擇可以是任意的。例如,最簡單的指標之一是電影評分。然而,這也有許多缺點。首先,電影評分不考慮電影的受歡迎程度。因此,一部被10萬用戶評為9.0級的電影將低于一部被100用戶評為9.5級的電影。這是不可取的,因為一部只有100人觀看和評分的電影很有可能迎合(cater to...)一個非常特殊的細分市場(a very specific niche),對普通人的吸引力不如前者大。眾所周知,隨著投票者人數的增加,一部電影的評分具有一定的“權威性”,并且可以反映電影質量和大眾化的價值。換句話說,評分很低的電影并不十分可靠。一部由五位用戶評為10/10的電影并不一定意味著它是一部好電影。因此,我們需要的是一個能夠在某種程度上考慮電影評分和它獲得的投票數的指標。這將使10萬人觀看的大片(評分8)比100人觀看的藝術片(評分9)更受歡迎。這里,將直接使用IMDB的加權評分公式作為度量:
- v是電影獲得的票數
- m是電影在圖表中所需的最小投票數(前提條件)
- R是電影的平均得分
- C是數據庫中所有電影的平均得分
3. 先決條件 Prerequisties
在上面公式中,m明顯是先決條件,也就是說,只有投票數超過一定閾值的電影才有可能參與最終評分的計算。
和度量一樣,m值的選擇也是任意的。換言之,m沒有統一的取值原則。最好先嘗試m的不同取值,然后選擇能給出最佳推薦結果對應的m值。唯一需要記住的是,m值越高,對電影受歡迎程度的強調越高,因此被選擇的概率越高。
對于此處的推薦系統設計,我們將使用第80百分位電影獲得的票數作為m的值。換句話說,對于要在排名中考慮的電影,它必須獲得超過我們數據集中存在的電影的至少80%的選票。此外,第80百分位電影獲得的選票用前面描述的加權公式計算分數值。
import pandas as pd import numpy as np df = pd.read_csv('C:/Users/Administrator/Desktop/RecoSys/data/movies_metadata.csv') m = df['vote_count'].quantile(0.80) print(m) >>> 50.0另一個先決條件是電影的持續時間。這里只考慮長度大于45分鐘小于300分鐘的電影。因此,定義一個新的DataFrame,用它保存所有滿足條件的電影列表。
q_movie = df[ (df['runtime'] >= 45) & (df['runtime'] <= 300) ] q_movie = q_movie[ q_movie['vote_count'] >= m ] print(q_movie.shape) >>> (8963, 24)4. 計算得分 Score
在計算最終電影分數之前,需要計算最后一個值是C(數據集中所有電影的平均評分):
C = df[ 'vote_average' ].mean() print(C) >>> 5.618207215133889因此,我們可以根據上面的公式,對于滿足先決條件的電影計算得分:
def weighted_rating(x, m=m, C=C):v = x[ 'vote_count' ]R = x[ 'vote_average' ]return ( v/(v+m) * R ) + (m/(v+m) * C)q_movie['score'] = q_movie.apply(weighted_rating, axis = 1) print(q_movie['score'].head(5))>>> 0 7.680953 1 6.873979 2 6.189510 4 5.681661 5 7.646235 Name: score, dtype: float645. 排序和輸出 Sorting and Output
q_movie = q_movie.sort_values('score', ascending=False) q_movie[['title', 'vote_count', 'vote_average', 'score', 'runtime']].head(10)6. 總結與提升
在推薦系統設計中,往往還需要人機交互的功能。在前面設計基礎上,需要執行以下任務:
- 向用戶詢問他/她正在尋找的電影類型
- 向用戶詢問電影的持續時間
- 向用戶詢問推薦的電影時間表
- 使用收集的信息,向用戶推薦具有高評分(根據IMDB公式)且滿足上述條件的電影
查看原始數據集中包含的所有的特征:
import pandas as pd import numpy as np df = pd.read_csv('C:/Users/Administrator/Desktop/RecoSys/data/movies_metadata.csv') df.columns >>> Index(['adult', 'belongs_to_collection', 'budget', 'genres', 'homepage', 'id','imdb_id', 'original_language', 'original_title', 'overview','popularity', 'poster_path', 'production_companies','production_countries', 'release_date', 'revenue', 'runtime','spoken_languages', 'status', 'tagline', 'title', 'video','vote_average', 'vote_count'], dtype='object')削減DataFrame,使得新的數據結構僅僅包括我們需要的特征:
df = df[ ['title','genres', 'release_date', 'runtime', 'vote_average', 'vote_count'] ] df.head()從release_date特征中提取出year,并且提出year特征中的異常值(NAN):
# convert release_date into pandas datetime format df['release_date'] = pd.to_datetime(df['release_date'], errors = 'coerce') # Extract year from datetime df['year'] = df['release_date'].apply(lambda x: str(x).split('-')[0] if x != np.nan else np.nan)# conver object to int; and convert NAT to 0 def convert_int(x):try:return int(x)except:return 0df['year'] = df['year'].apply(convert_int) df['year']有了year特征,就不在需要release_date特征了,因此刪除:
df = df.drop('release_date', axis=1) df.head(5)從上面圖我們可以看出來,genres特征并不滿足交互處理的需求,首先看一下genres特征的內容:
type(df.iloc[0]['genres']) print(df.iloc[0]['genres']) >>> str [{'id': 16, 'name': 'Animation'}, {'id': 35, 'name': 'Comedy'}, {'id': 10751, 'name': 'Family'}]我們可以觀察到輸出是一個字符串化的字典。為了使這個特性可用,我們必須將這個字符串轉換成一個Python字典。幸運的是,python允許我們訪問一個名為literal_eval(在ast庫中可用)的函數,它正好做到了這一點。literal_eval解析傳入它的任何字符串,并將其轉換為相應的python對象。此外,應該注意的是,上面的genre輸出包括了id和name兩個要素。在我們實際應用上,我們僅僅需要name屬性:
from ast import literal_eval#Convert all NaN into stringified empty lists df['genres'] = df['genres'].fillna('[]') #Apply literal_eval to convert to the list object df['genres'] = df['genres'].apply(literal_eval) #Convert list of dictionaries to a list of strings df['genres'] = df['genres'].apply(lambda x: [i['name'] for i in x] if isinstance(x,list) else []) df.head()如果電影有多個流派,我們將創建該電影的多個副本,每個電影都有一個流派。例如, 電影Just Go With It 具有?romance 和
comedy 屬性, 這時候我們需要把它拆分成兩行:?一行是 Just Go With It (具有romance屬性);另一行是 Just Go With It (具有comedy 屬性)。
這樣,原始的DataFrame經過數據清洗后,就很方便進行推薦系統設計了。
===========================================================================================
設計人機交互式推薦系統功能,需要滿足三個功能子模塊:
- 獲得用戶偏好的輸入
- 提取電影庫中所有與用戶偏好相關的電影
- 利用前面的方法反饋推薦結果
測試結果:
?
總結
以上是生活随笔為你收集整理的基于知识的推荐系统(案例学习)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 推荐系统-应用Pandas进行数据处理
- 下一篇: 一个25岁董事长给程序员的18条忠告