<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        用Python實現協同過濾的教程

        來源:懂視網 責編:小采 時間:2020-11-27 14:39:54
        文檔

        用Python實現協同過濾的教程

        用Python實現協同過濾的教程:協同過濾 在 用戶 —— 物品(user - item)的數據關系下很容易收集到一些偏好信息(preference),比如評分。利用這些分散的偏好信息,基于其背后可能存在的關聯性,來為用戶推薦物品的方法,便是協同過濾,或稱協作型過濾(collaborative fil
        推薦度:
        導讀用Python實現協同過濾的教程:協同過濾 在 用戶 —— 物品(user - item)的數據關系下很容易收集到一些偏好信息(preference),比如評分。利用這些分散的偏好信息,基于其背后可能存在的關聯性,來為用戶推薦物品的方法,便是協同過濾,或稱協作型過濾(collaborative fil
        協同過濾

        在 用戶 —— 物品(user - item)的數據關系下很容易收集到一些偏好信息(preference),比如評分。利用這些分散的偏好信息,基于其背后可能存在的關聯性,來為用戶推薦物品的方法,便是協同過濾,或稱協作型過濾(collaborative filtering)。

        這種過濾算法的有效性基礎在于:

        用戶的偏好具有相似性,即用戶是可分類的。這種分類的特征越明顯,推薦的準確率就越高
        物品之間是存在關系的,即偏好某一物品的任何人,都很可能也同時偏好另一件物品

        不同環境下這兩種理論的有效性也不同,應用時需做相應調整。如豆瓣上的文藝作品,用戶對其的偏好程度與用戶自身的品位關聯性較強;而對于電子商務網站來說,商品之間的內在聯系對用戶的購買行為影響更為顯著。當用在推薦上,這兩種方向也被稱為基于用戶的和基于物品的。本文內容為基于用戶的。
        影評推薦實例

        本文主要內容為基于用戶偏好的相似性進行物品推薦,使用的數據集為 GroupLens Research 采集的一組從 20 世紀 90 年代末到 21 世紀初由 MovieLens 用戶提供的電影評分數據。數據中包含了約 6000 名用戶對約 4000 部電影的 100萬條評分,五分制。數據包可以從網上下載到,里面包含了三個數據表——users、movies、ratings。因為本文的主題是基于用戶偏好的,所以只使用 ratings 這一個文件。另兩個文件里分別包含用戶和電影的元信息。

        本文使用的數據分析包為 pandas,環境為 IPython,因此其實還默認攜帶了 Numpy 和 matplotlib。下面代碼中的提示符看起來不是 IPython 環境是因為 Idle 的格式發在博客上更好看一些。
        數據規整

        首先將評分數據從 ratings.dat 中讀出到一個 DataFrame 里:

        >>> import pandas as pd
        >>> from pandas import Series,DataFrame
        >>> rnames = ['user_id','movie_id','rating','timestamp']
        >>> ratings = pd.read_table(r'ratings.dat',sep='::',header=None,names=rnames)
        >>> ratings[:3]
         user_id movie_id rating timestamp
        0 1 1193 5 978300760
        1 1 661 3 978302109
        2 1 914 3 978301968
         
        [3 rows x 4 columns]
        
        

        ratings 表中對我們有用的僅是 user_id、movie_id 和 rating 這三列,因此我們將這三列取出,放到一個以 user 為行,movie 為列,rating 為值的表 data 里面。(其實將 user 與 movie 的行列關系對調是更加科學的方法,但因為重跑一遍太麻煩了,這里就沒改。)

        >>> data = ratings.pivot(index='user_id',columns='movie_id',values='rating')
        >>> data[:5]
        movie_id 1 2 3 4 5 6 
        user_id 
        1 5 NaN NaN NaN NaN NaN ...
        2 NaN NaN NaN NaN NaN NaN ...
        3 NaN NaN NaN NaN NaN NaN ...
        4 NaN NaN NaN NaN NaN NaN ...
        5 NaN NaN NaN NaN NaN 2 ...
        

        可以看到這個表相當得稀疏,填充率大約只有 5%,接下來要實現推薦的第一步是計算 user 之間的相關系數,DataFrame 對象有一個很親切的 .corr(method='pearson', min_periods=1) 方法,可以對所有列互相計算相關系數。method 默認為皮爾遜相關系數,這個 ok,我們就用這個。問題僅在于那個 min_periods 參數,這個參數的作用是設定計算相關系數時的最小樣本量,低于此值的一對列將不進行運算。這個值的取舍關系到相關系數計算的準確性,因此有必要先來確定一下這個參數。

        相關系數是用于評價兩個變量間線性關系的一個值,取值范圍為 [-1, 1],-1代表負相關,0 代表不相關,1 代表正相關。其中 0~0.1 一般被認為是弱相關,0.1~0.4 為相關,0.4~1 為強相關。

        min_periods 參數測定

        測定這樣一個參數的基本方法為統計在 min_periods 取不同值時,相關系數的標準差大小,越小越好;但同時又要考慮到,我們的樣本空間十分稀疏,min_periods 定得太高會導致出來的結果集太小,所以只能選定一個折中的值。

        這里我們測定評分系統標準差的方法為:在 data 中挑選一對重疊評分最多的用戶,用他們之間的相關系數的標準差去對整體標準差做點估計。在此前提下對這一對用戶在不同樣本量下的相關系數進行統計,觀察其標準差變化。

        首先,要找出重疊評分最多的一對用戶。我們新建一個以 user 為行列的方陣 foo,然后挨個填充不同用戶間重疊評分的個數:

        >>> foo = DataFrame(np.empty((len(data.index),len(data.index)),dtype=int),index=data.index,columns=data.index)
        >>> for i in foo.index:
         for j in foo.columns:
         foo.ix[i,j] = data.ix[i][data.ix[j].notnull()].dropna().count()
        

        這段代碼特別費時間,因為最后一行語句要執行 4000*4000 = 1600萬遍;(其中有一半是重復運算,因為 foo 這個方陣是對稱的)還有一個原因是 Python 的 GIL,使得其只能使用一個 CPU 線程。我在它執行了一個小時后,忍不住去測試了一下總時間,發現要三個多小時后就果斷 Ctrl + C 了,在算了一小半的 foo 中,我找到的最大值所對應的行列分別為 424 和 4169,這兩位用戶之間的重疊評分數為 998:



        >>> for i in foo.index:
         foo.ix[i,i]=0#先把對角線的值設為 0
         
        >>> ser = Series(np.zeros(len(foo.index)))
        >>> for i in foo.index:
         ser[i]=foo[i].max()#計算每行中的最大值
         
        >>> ser.idxmax()#返回 ser 的最大值所在的行號
        4169
         
        >>> ser[4169]#取得最大值
        998
         
        >>> foo[foo==998][4169].dropna()#取得另一個 user_id
        424 4169
        Name: user_id, dtype: float64
        

        我們把 424 和 4169 的評分數據單獨拿出來,放到一個名為 test 的表里,另外計算了一下這兩個用戶之間的相關系數為 0.456,還算不錯,另外通過柱狀圖了解一下他倆的評分分布情況:

        >>> data.ix[4169].corr(data.ix[424])
        0.45663851303413217
        >>> test = data.reindex([424,4169],columns=data.ix[4169][data.ix[424].notnull()].dropna().index)
        >>> test
        movie_id 2 6 10 11 12 17 ...
        424 4 4 4 4 1 5 ...
        4169 3 4 4 4 2 5 ...
         
        >>> test.ix[424].value_counts(sort=False).plot(kind='bar')
        >>> test.ix[4169].value_counts(sort=False).plot(kind='bar')
        
        

        201548154049025.png (371×261)

        201548154118207.png (370×261)

        對這倆用戶的相關系數統計,我們分別隨機抽取 20、50、100、200、500 和 998 個樣本值,各抽 20 次。并統計結果:

         >>> periods_test = DataFrame(np.zeros((20,7)),columns=[10,20,50,100,200,500,998])
        >>> for i in periods_test.index:
         for j in periods_test.columns:
         sample = test.reindex(columns=np.random.permutation(test.columns)[:j])
         periods_test.ix[i,j] = sample.iloc[0].corr(sample.iloc[1])
         
         
        >>> periods_test[:5]
         10 20 50 100 200 500 998
        0 -0.306719 0.709073 0.504374 0.376921 0.477140 0.426938 0.456639
        1 0.386658 0.607569 0.434761 0.471930 0.437222 0.430765 0.456639
        2 0.507415 0.585808 0.440619 0.634782 0.490574 0.436799 0.456639
        3 0.628112 0.628281 0.452331 0.380073 0.472045 0.444222 0.456639
        4 0.792533 0.641503 0.444989 0.499253 0.426420 0.441292 0.456639
         
        [5 rows x 7 columns]
        >>> periods_test.describe()
         10 20 50 100 200 500 #998略
        count 20.000000 20.000000 20.000000 20.000000 20.000000 20.000000 
        mean 0.346810 0.464726 0.458866 0.450155 0.467559 0.452448 
        std 0.398553 0.181743 0.103820 0.093663 0.036439 0.029758 
        min -0.444302 0.087370 0.192391 0.242112 0.412291 0.399875 
        25% 0.174531 0.320941 0.434744 0.375643 0.439228 0.435290 
        50% 0.487157 0.525217 0.476653 0.468850 0.472562 0.443772 
        75% 0.638685 0.616643 0.519827 0.500825 0.487389 0.465787 
        max 0.850963 0.709073 0.592040 0.634782 0.546001 0.513486 
         
        [8 rows x 7 columns]
        
        

        從 std 這一行來看,理想的 min_periods 參數值應當為 200 左右。可能有人會覺得 200 太大了,這個推薦算法對新用戶簡直沒意義。但是得說,隨便算出個有超大誤差的相關系數,然后拿去做不靠譜的推薦,又有什么意義呢。
        算法檢驗

        為了確認在 min_periods=200 下本推薦算法的靠譜程度,最好還是先做個檢驗。具體方法為:在評價數大于 200 的用戶中隨機抽取 1000 位用戶,每人隨機提取一個評價另存到一個數組里,并在數據表中刪除這個評價。然后基于閹割過的數據表計算被提取出的 1000 個評分的期望值,最后與真實評價數組進行相關性比較,看結果如何。

        >>> check_size = 1000
        >>> check = {}
        >>> check_data = data.copy()#復制一份 data 用于檢驗,以免篡改原數據
        >>> check_data = check_data.ix[check_data.count(axis=1)>200]#濾除評價數小于200的用戶
        >>> for user in np.random.permutation(check_data.index):
         movie = np.random.permutation(check_data.ix[user].dropna().index)[0]
         check[(user,movie)] = check_data.ix[user,movie]
         check_data.ix[user,movie] = np.nan
         check_size -= 1
         if not check_size:
         break
         
         
        >>> corr = check_data.T.corr(min_periods=200)
        >>> corr_clean = corr.dropna(how='all')
        >>> corr_clean = corr_clean.dropna(axis=1,how='all')#刪除全空的行和列
        >>> check_ser = Series(check)#這里是被提取出來的 1000 個真實評分
        >>> check_ser[:5]
        (15, 593) 4
        (23, 555) 3
        (33, 3363) 4
        (36, 2355) 5
        (53, 3605) 4
        dtype: float64
        

        接下來要基于 corr_clean 給 check_ser 中的 1000 個 用戶-影片 對計算評分期望。計算方法為:對與用戶相關系數大于 0.1 的其他用戶評分進行加權平均,權值為相關系數:

        >>> result = Series(np.nan,index=check_ser.index)
        >>> for user,movie in result.index:#這個循環看著很亂,實際內容就是加權平均而已
         prediction = []
         if user in corr_clean.index:
         corr_set = corr_clean[user][corr_clean[user]>0.1].dropna()#僅限大于 0.1 的用戶
         else:continue
         for other in corr_set.index:
         if not np.isnan(data.ix[other,movie]) and other != user:#注意bool(np.nan)==True
         prediction.append((data.ix[other,movie],corr_set[other]))
         if prediction:
         result[(user,movie)] = sum([value*weight for value,weight in prediction])/sum([pair[1] for pair in prediction])
         
         
        >>> result.dropna(inplace=True)
        >>> len(result)#隨機抽取的 1000 個用戶中也有被 min_periods=200 刷掉的
        862
        >>> result[:5]
        (23, 555) 3.967617
        (33, 3363) 4.073205
        (36, 2355) 3.903497
        (53, 3605) 2.948003
        (62, 1488) 2.606582
        dtype: float64
        >>> result.corr(check_ser.reindex(result.index))
        0.436227437429696
        >>> (result-check_ser.reindex(result.index)).abs().describe()#推薦期望與實際評價之差的絕對值
        count 862.000000
        mean 0.785337
        std 0.605865
        min 0.000000
        25% 0.290384
        50% 0.686033
        75% 1.132256
        max 3.629720
        dtype: float64
        

        862 的樣本量能達到 0.436 的相關系數,應該說結果還不錯。如果一開始沒有濾掉評價數小于 200 的用戶的話,那么首先在計算 corr 時會明顯感覺時間變長,其次 result 中的樣本量會很小,大約 200+ 個。但因為樣本量變小的緣故,相關系數可以提升到 0.5~0.6 。

        另外從期望與實際評價的差的絕對值的統計量上看,數據也比較理想。
        實現推薦

        在上面的檢驗,尤其是平均加權的部分做完后,推薦的實現就沒有什么新東西了。

        首先在原始未閹割的 data 數據上重做一份 corr 表:

        >>> corr = data.T.corr(min_periods=200)
        >>> corr_clean = corr.dropna(how='all')
        >>> corr_clean = corr_clean.dropna(axis=1,how='all')
        

        我們在 corr_clean 中隨機挑選一位用戶為他做一個推薦列表:

        >>> lucky = np.random.permutation(corr_clean.index)[0]
        >>> gift = data.ix[lucky]
        >>> gift = gift[gift.isnull()]#現在 gift 是一個全空的序列
        

        最后的任務就是填充這個 gift:

        >>> corr_lucky = corr_clean[lucky].drop(lucky)#lucky 與其他用戶的相關系數 Series,不包含 lucky 自身
        >>> corr_lucky = corr_lucky[corr_lucky>0.1].dropna()#篩選相關系數大于 0.1 的用戶
        >>> for movie in gift.index:#遍歷所有 lucky 沒看過的電影
         prediction = []
         for other in corr_lucky.index:#遍歷所有與 lucky 相關系數大于 0.1 的用戶
         if not np.isnan(data.ix[other,movie]):
         prediction.append((data.ix[other,movie],corr_clean[lucky][other]))
         if prediction:
         gift[movie] = sum([value*weight for value,weight in prediction])/sum([pair[1] for pair in prediction])
         
         
        >>> gift.dropna().order(ascending=False)#將 gift 的非空元素按降序排列
        movie_id
        3245 5.000000
        2930 5.000000
        2830 5.000000
        2569 5.000000
        1795 5.000000
        981 5.000000
        696 5.000000
        682 5.000000
        666 5.000000
        572 5.000000
        1420 5.000000
        3338 4.845331
        669 4.660464
        214 4.655798
        3410 4.624088
        ...
        2833 1
        2777 1
        2039 1
        1773 1
        1720 1
        1692 1
        1538 1
        1430 1
        1311 1
        1164 1
        843 1
        660 1
        634 1
        591 1
        56 1
        Name: 3945, Length: 2991, dtype: float64
        


        補充

        上面給出的示例都是些原型代碼,有很多可優化的空間。比如 data 的行列轉換;比如測定 min_periods 時的方陣 foo 只需計算一半;比如有些 for 循環和相應運算可以用數組對象方法來實現(方法版比用戶自己編寫的版本速度快很多);甚至肯定還有一些 bug。另外這個數據集的體積還不算太大,如果再增長一個數量級,那么就有必要針對計算密集的部分(如 corr)做進一步優化了,可以使用多進程,或者 Cython/C 代碼。(或者換更好的硬件)

        雖然協同過濾是一種比較省事的推薦方法,但在某些場合下并不如利用元信息推薦好用。協同過濾會遇到的兩個常見問題是

        1. 稀疏性問題——因用戶做出評價過少,導致算出的相關系數不準確
        2. 冷啟動問題——因物品獲得評價過少,導致無“權”進入推薦列表中

        都是樣本量太少導致的。(上例中也使用了至少 200 的有效重疊評價數)因此在對于新用戶和新物品進行推薦時,使用一些更一般性的方法效果可能會更好。比如給新用戶推薦更多平均得分超高的電影;把新電影推薦給喜歡類似電影(如具有相同導演或演員)的人。后面這種做法需要維護一個物品分類表,這個表既可以是基于物品元信息劃分的,也可是通過聚類得到的。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        用Python實現協同過濾的教程

        用Python實現協同過濾的教程:協同過濾 在 用戶 —— 物品(user - item)的數據關系下很容易收集到一些偏好信息(preference),比如評分。利用這些分散的偏好信息,基于其背后可能存在的關聯性,來為用戶推薦物品的方法,便是協同過濾,或稱協作型過濾(collaborative fil
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲综合一区无码精品| 亚洲午夜成人精品电影在线观看| 亚洲日韩中文字幕在线播放| 国产午夜亚洲精品不卡电影| 国产在线观看免费视频播放器| 亚洲熟妇av午夜无码不卡| 一二三四在线观看免费高清中文在线观看| 亚洲色图国产精品| 人妻无码一区二区三区免费 | 免费观看国产小粉嫩喷水| 亚洲熟妇无码AV| 日韩精品亚洲专区在线观看| 猫咪www免费人成网站| 精品亚洲一区二区三区在线观看 | 成人免费乱码大片A毛片| 亚洲另类少妇17p| 成年女人A毛片免费视频| 亚洲国产精品无码专区影院| 亚洲免费二区三区| 亚洲中文字幕无码久久| 亚洲成A人片在线观看中文| 中文字幕永久免费视频| 亚洲黄色高清视频| 青青青国产免费一夜七次郎| 一级特黄录像免费播放中文版| 亚洲国产精彩中文乱码AV| 老司机在线免费视频| 美女免费视频一区二区| 亚洲国产精品特色大片观看完整版| 最近中文字幕免费mv在线视频| 亚洲色无码国产精品网站可下载| 亚洲真人日本在线| 四虎精品视频在线永久免费观看| 欧美日韩亚洲精品| 亚洲成熟xxxxx电影| 全免费A级毛片免费看网站| 99久久精品毛片免费播放| 亚洲jizzjizz在线播放久| 亚洲一区视频在线播放| 在线看片无码永久免费视频| 国产成人无码精品久久久久免费 |