前言叨B叨
嗯嗯枣购,又到了某些同學(xué)最愛的摳腚階段了嬉探,睜大眼睛跟我做哈
目錄
- 用戶和產(chǎn)品的潛在特征
- 編寫推薦系統(tǒng)
- 矩陣分解工作原理
- 使用潛在表征來找到類似的產(chǎn)品
1. 用戶和產(chǎn)品的潛在特征
我們可以通過為每個(gè)用戶和每部電影分配屬性,然后將它們相乘并合并結(jié)果來估計(jì)用戶喜歡電影的程度棉圈。相同的計(jì)算可以表示為矩陣乘法問題涩堤。首先,我們把用戶屬性放在一個(gè)名為U的矩陣中分瘾,在這個(gè)例子中是5胎围,-2,1德召,-5和5白魂。然后,我們把電影屬性放在一個(gè)名為M的矩陣中上岗,我們使用矩陣乘法來找出用戶的評(píng)分福荸。
但要做到這一點(diǎn),我們必須已經(jīng)知道用戶屬性和電影屬性肴掷。
為每個(gè)用戶和每部電影提供屬性評(píng)級(jí)并不容易敬锐。我們需要找到一種自動(dòng)的方法背传。我們來看看電影評(píng)分矩陣,
它顯示了我們數(shù)據(jù)集中的所有用戶如何評(píng)價(jià)電影台夺。這個(gè)矩陣非常稀疏径玖,但它給了我們很多信息。例如颤介,我們知道用戶ID2給電影1號(hào)五顆星梳星。所以,基于此滚朵,我們可以猜測(cè)丰泊,這個(gè)用戶的屬性可能類似于電影的屬性,因?yàn)樗鼈兤ヅ涞暮芎檬忌堋Q句話說,我們有一些線索可以使用话侄。
實(shí)際上童擎,我們可以使用目前為止我們所知道的電影評(píng)級(jí),然后逆向找到滿足該等式的U矩陣和M矩陣攻晒。當(dāng)然顾复,這才是最酷的部分。 當(dāng)我們將U和M相乘時(shí)鲁捏,他們實(shí)際上會(huì)給我們一個(gè)完整的矩陣芯砸,我們可以使用那個(gè)完成的矩陣來推薦電影。讓我們回顧一下我們將如何構(gòu)建這個(gè)推薦系統(tǒng)给梅。
首先假丧,我們創(chuàng)建了我們?cè)跀?shù)據(jù)集中所有用戶評(píng)論的矩陣。接下來动羽,我們從已知的評(píng)論中分解出一個(gè)U矩陣和一個(gè)M矩陣包帚。最后,我們將把我們找到的U和M矩陣相乘曹质,得到每個(gè)用戶和每部電影的評(píng)分婴噩。但是還有一個(gè)問題擎场。以前,當(dāng)我們?yōu)槊總€(gè)用戶和每部電影手工創(chuàng)建屬性時(shí)几莽,我們知道每個(gè)屬性的含義迅办。
我們知道第一個(gè)屬性代表動(dòng)作,第二個(gè)代表劇情章蚣,等等站欺。但是當(dāng)我們使用矩陣分解來提出U和M時(shí),我們不知道每個(gè)值是什么意思纤垂。我們所知道的是矾策,每個(gè)價(jià)值都代表了一些讓用戶感覺被某些電影吸引的特征。我們不知道如何用文字來描述這些特征峭沦。因此贾虽,U和M被稱為潛在向量。潛在的詞意味著隱藏吼鱼。換句話說蓬豁,這些向量是隱藏的信息,我們通過查看評(píng)論數(shù)據(jù)和反向推導(dǎo)菇肃。
2. 編寫推薦系統(tǒng)
我們來編寫推薦系統(tǒng)的主要代碼地粪。打開Chapter 5/factor_review_matrix.py。
首先琐谤,我將使用pandas read_csv函數(shù)將檢查數(shù)據(jù)集加載到名為raw_dataset_df的數(shù)據(jù)集中蟆技。
raw_dataset_df = pd.read_csv('movie_ratings_data_set.csv')
然后我們使用pandas數(shù)據(jù)透視表函數(shù)來構(gòu)建評(píng)論矩陣。在這一點(diǎn)上斗忌,ratings_df包含一個(gè)稀疏的評(píng)論陣列质礼。
ratings_df = pd.pivot_table(raw_dataset_df, index='user_id', columns='movie_id', aggfunc=np.max)
接下來,我們希望將數(shù)組分解以找到用戶屬性矩陣和我們可以重新乘回的電影屬性矩陣來重新創(chuàng)建收視率數(shù)據(jù)飞蹂。
為此几苍,我們將使用低秩矩陣分解算法。我已經(jīng)在matrix_factorization_utilities.py中包含了這個(gè)實(shí)現(xiàn)陈哑。我們將在下一個(gè)視頻中詳細(xì)討論它是如何工作的妻坝,但讓我們繼續(xù)使用它。首先惊窖,我們傳遞了評(píng)分?jǐn)?shù)據(jù)刽宪,但是我們將調(diào)用pandas的as_matrix()函數(shù),以確保我們作為一個(gè)numpy矩陣數(shù)據(jù)類型傳入界酒。
U, M = matrix_factorization_utilities.low_rank_matrix_factorization(ratings_df.as_matrix(),
num_features=15,
regularization_amount=0.1)
接下來圣拄,這個(gè)方法接受一個(gè)名為num_features的參數(shù)。 Num_features控制為每個(gè)用戶和每個(gè)電影生成多少個(gè)潛在特征毁欣。
我們將以15為起點(diǎn)庇谆。這個(gè)函數(shù)還有個(gè)參數(shù)regularization_amount≡榔現(xiàn)在讓我們傳入0.1。在后面的文章中我們將討論如何調(diào)整這個(gè)參數(shù)饭耳。
函數(shù)的結(jié)果是U矩陣和M矩陣串述,每個(gè)用戶和每個(gè)電影分別具有15個(gè)屬性。現(xiàn)在寞肖,我們可以通過將U和M相乘來得到每部電影的評(píng)分纲酗。但不是使用常規(guī)的乘法運(yùn)算符,而是使用numpy的matmul函數(shù)新蟆,所以它知道我們要做矩陣乘法觅赊。
predicted_ratings = np.matmul(U, M)
結(jié)果存儲(chǔ)在一個(gè)名為predicted_ratings的數(shù)組中。最后琼稻,我們將predict_ratings保存到一個(gè)csv文件吮螺。
predicted_ratings_df = pd.DataFrame(index=ratings_df.index,
columns=ratings_df.columns,
data=predicted_ratings)
predicted_ratings_df.to_csv("predicted_ratings.csv")
首先,我們將創(chuàng)建一個(gè)新的pandas數(shù)據(jù)框來保存數(shù)據(jù)帕翻。對(duì)于這個(gè)數(shù)據(jù)框规脸,我們會(huì)告訴pandas使用與ratings_df數(shù)據(jù)框中相同的行和列名稱。然后熊咽,我們將使用pandas csv函數(shù)將數(shù)據(jù)保存到文件。運(yùn)行這個(gè)程序后可以看到闹丐,它創(chuàng)建了一個(gè)名為predicted_ratings.csv的新文件横殴。我們可以使用任何電子表格應(yīng)用程序打開該文件。這個(gè)數(shù)據(jù)看起來就像我們?cè)瓉淼脑u(píng)論數(shù)據(jù)卿拴,現(xiàn)在每個(gè)單元格都填滿了∩缆兀現(xiàn)在我們?cè)u(píng)估下每個(gè)單個(gè)用戶會(huì)為每個(gè)單獨(dú)的電影評(píng)分。例如堕花,我們可以看到用戶3評(píng)級(jí)電影4岛啸,他們會(huì)給它一個(gè)四星級(jí)的評(píng)級(jí)⌒庥瘢現(xiàn)在我們知道所有這些評(píng)分,我們可以按照評(píng)分順序向用戶推薦電影。讓我們看看用戶1號(hào)荧缘,看看我們推薦給他們的電影。在所有這些電影中琳拨,如果我們排除了用戶以前評(píng)價(jià)過的電影寸齐,右邊34號(hào)電影是最高分的電影,所以這是我們應(yīng)該推薦給這個(gè)用戶的第一部電影腮郊。
當(dāng)用戶觀看這部電影時(shí)摹蘑,我們會(huì)要求他們?cè)u(píng)分。如果他們的評(píng)價(jià)與我們預(yù)測(cè)的不一致轧飞,我們將添加新評(píng)級(jí)并重新計(jì)算此矩陣衅鹿。這將有助于我們提高整體評(píng)分撒踪。我們從中獲得的評(píng)分越多,我們的評(píng)分陣列中就會(huì)出現(xiàn)的孔越少大渤,我們就有更好的機(jī)會(huì)為U和M矩陣提供準(zhǔn)確的值制妄。
3. 矩陣分解工作原理
因?yàn)樵u(píng)分矩陣等于將用戶屬性矩陣乘以電影屬性矩陣的結(jié)果,所以我們可以使用矩陣分解反向工作以找到U和M的值兼犯。在代碼中忍捡,我們使用稱為低秩矩陣分解的算法,去做這個(gè)切黔。我們來看看這個(gè)算法是如何工作的砸脊。矩陣分解是一個(gè)大矩陣可以分解成更小的矩陣的思想。所以纬霞,假設(shè)我們有一個(gè)大的數(shù)字矩陣凌埂,并且假設(shè)我們想要找到兩個(gè)更小的矩陣相乘來產(chǎn)生那個(gè)大的矩陣,我們的目標(biāo)是找到兩個(gè)更小的矩陣來滿足這個(gè)要求诗芜。
如果您碰巧是線性代數(shù)的專家瞳抓,您可能知道有一些標(biāo)準(zhǔn)的方法來對(duì)矩陣進(jìn)行因式分解,比如使用一個(gè)稱為奇異值分解的過程伏恐。但是孩哑,這是有這么一個(gè)特殊的情況下,將無法正常工作翠桦。問題是我們只知道大矩陣中的一些值横蜒。大矩陣中的許多條目是空白的,或者用戶還沒有檢查特定的電影销凑。所以丛晌,我們不是直接將評(píng)級(jí)數(shù)組分成兩個(gè)較小的矩陣,而是使用迭代算法估計(jì)較小的矩陣的值斗幼。我們會(huì)猜測(cè)和檢查澎蛛,直到我們接近正確的答案。
哎哎等等蜕窿, 咋回事呢谋逻?首先,我們將創(chuàng)建U和M矩陣桐经,但將所有值設(shè)置為隨機(jī)數(shù)斤贰。因?yàn)閁和M都是隨機(jī)數(shù),所以如果我們現(xiàn)在乘以U和M次询,結(jié)果是隨機(jī)的荧恍。下一步是檢查我們的計(jì)算評(píng)級(jí)矩陣與真實(shí)評(píng)級(jí)矩陣與U和M的當(dāng)前值有多不同。但是我們將忽略評(píng)級(jí)矩陣中所有沒有數(shù)據(jù)的點(diǎn),只看在我們有實(shí)際用戶評(píng)論的地方送巡。我們將這種差異稱為成本摹菠。成本就是錯(cuò)誤率。
接下來骗爆,我們將使用數(shù)字優(yōu)化算法來搜索最小成本次氨。數(shù)值優(yōu)化算法將一次調(diào)整U和M中的數(shù)字。目標(biāo)是讓每一步的成本函數(shù)更接近于零摘投。我們將使用的函數(shù)稱為fmin_cg煮寡。它搜索使函數(shù)返回最小可能輸出的輸入。它由SciPy庫提供犀呼。最后幸撕,fmin_cg函數(shù)將循環(huán)數(shù)百次,直到我們得到盡可能小的代價(jià)外臂。當(dāng)成本函數(shù)的價(jià)值如我們所能得到的那樣低坐儿,那么U和M的最終值就是我們將要使用的。
但是因?yàn)樗鼈冎皇墙浦邓喂猓运鼈儾粫?huì)完全完美貌矿。當(dāng)我們將這些U矩陣和M矩陣相乘來計(jì)算電影評(píng)級(jí)時(shí),將其與原始電影評(píng)級(jí)進(jìn)行比較罪佳,我們會(huì)看到還是有一些差異逛漫。但是只要我們接近,少量的差異就無關(guān)緊要了赘艳。
4. 使用潛在特征來找到類似的產(chǎn)品
搜索引擎是用戶發(fā)現(xiàn)新網(wǎng)站的常用方式尽楔。當(dāng)?shù)谝淮斡脩魪乃阉饕嬖L問您的網(wǎng)站時(shí),您對(duì)用戶尚不足以提供個(gè)性化推薦第练,直到用戶輸入一些產(chǎn)品評(píng)論時(shí),我們的推薦系統(tǒng)還不能推薦他們玛荞。在這種情況下娇掏,我們可以向用戶展示與他們已經(jīng)在查看的產(chǎn)品類似的產(chǎn)品。目標(biāo)是讓他們?cè)诰W(wǎng)站上勋眯,讓他們看更多的產(chǎn)品婴梧。你可能在網(wǎng)上購(gòu)物網(wǎng)站上看到過這個(gè)功能,如果你喜歡這個(gè)產(chǎn)品客蹋,你可能也會(huì)喜歡這些其他的產(chǎn)品塞蹭。
通過使用矩陣分解計(jì)算產(chǎn)品屬性,我們可以計(jì)算產(chǎn)品相似度讶坯。讓我們來看看find_similar_products.py番电。首先,我們將使用pandas的讀取CSV功能加載電影評(píng)級(jí)數(shù)據(jù)集。
df = pd.read_csv('movie_ratings_data_set.csv')
movies_df = pd.read_csv('movies.csv', index_col='movie_id')
我們還會(huì)使用read_csv將movies.csv加載到名為movies_df的數(shù)據(jù)框中漱办。
df = pd.read_csv('movie_ratings_data_set.csv')
ratings_df = pd.pivot_table(df, index='user_id', columns='movie_id', aggfunc=np.max)
U, M = matrix_factorization_utilities.low_rank_matrix_factorization(ratings_df.as_matrix(),
num_features=15,
regularization_amount=1.0)
然后这刷,我們將使用pandas的數(shù)據(jù)透視表函數(shù)(pivot_table)來創(chuàng)建評(píng)分矩陣,我們將使用矩陣分解來計(jì)算U和M矩陣∶渚現(xiàn)在暇屋,每個(gè)電影都由矩陣中的一列表示。
首先洞辣,我們使用numpy的轉(zhuǎn)置函數(shù)來觸發(fā)矩陣咐刨,使每一列變成一行。
M = np.transpose(M)
這只是使數(shù)據(jù)更容易處理扬霜,它不會(huì)改變數(shù)據(jù)本身定鸟。在矩陣中,每個(gè)電影有15個(gè)唯一的值代表該電影的特征畜挥。這意味著其他電影幾乎相同的電影應(yīng)該是非常相似的仔粥。要找到類似這個(gè)電影的其他電影,我們只需要找到其他電影的編號(hào)是最接近這部電影的數(shù)字蟹但。這只是一個(gè)減法問題躯泰。讓我們選擇用戶正在看的主要電影,讓我們選擇電影ID5华糖。
movie_id = 5
movie_information = movies_df.loc[movie_id]
如果你喜歡麦向,你可以選擇其他的電影。現(xiàn)在客叉,我們來看看電影ID5的標(biāo)題和流派诵竭。我們可以通過查看movies_df數(shù)據(jù)框并使用pandas的loc函數(shù)通過其索引查找行來做到這一點(diǎn)。讓我們打印出該電影的標(biāo)題和流派兼搏。
print("We are finding movies similar to this movie:")
print("Movie title: {}".format(movie_information.title))
print("Genre: {}".format(movie_information.genre))
接下來卵慰,讓我們從矩陣中獲取電影ID為5的電影屬性。我們必須在這里減去一個(gè)佛呻,因?yàn)镸是0索引裳朋,但電影ID從1開始。現(xiàn)在吓著,讓我們打印出這些電影屬性鲤嫡,以便我們看到它們,這些屬性我們準(zhǔn)備好找到類似的電影绑莺。
current_movie_features = M[movie_id - 1]
print("The attributes for this movie are:")
print(current_movie_features)
# The main logic for finding similar movies:
# 1. Subtract the current movie's features from every other movie's features
difference = M - current_movie_features
# 2. Take the absolute value of that difference (so all numbers are positive)
absolute_difference = np.abs(difference)
# 3. Each movie has 15 features. Sum those 15 features to get a total 'difference score' for each movie
total_difference = np.sum(absolute_difference, axis=1)
# 4. Create a new column in the movie list with the difference score for each movie
movies_df['difference_score'] = total_difference
# 5. Sort the movie list by difference score, from least different to most different
sorted_movie_list = movies_df.sort_values('difference_score')
# 6. Print the result, showing the 5 most similar movies to movie_id #1
print("The five most similar movies are:")
print(sorted_movie_list[['title', 'difference_score']][0:5])
第一步是從其他電影中減去這部電影的屬性暖眼。這一行代碼從矩陣的每一行中分別減去當(dāng)前的電影特征。這給了我們當(dāng)前電影和數(shù)據(jù)庫中其他電影之間的分?jǐn)?shù)差異纺裁。您也可以使用四個(gè)循環(huán)來一次減去一個(gè)電影诫肠,但使用numpy,我們可以在一行代碼中完成。第二步是取我們?cè)诘谝徊接?jì)算出的差值的絕對(duì)值区赵,numpy的ABS函數(shù)給我們絕對(duì)值惭缰,這只是確保任何負(fù)數(shù)出來都是正值。
接下來笼才,我們將每個(gè)電影的15個(gè)單獨(dú)的屬性差異合并為一個(gè)電影的總差異分?jǐn)?shù)漱受。 numpy的總和功能將做到這一點(diǎn)。我們還會(huì)傳入訪問權(quán)限等于一個(gè)來告訴numpy總結(jié)每行中的所有數(shù)字骡送,并為每行產(chǎn)生一個(gè)單獨(dú)的總和昂羡。在這一點(diǎn)上,我們完成了計(jì)算摔踱。我們只是將計(jì)算得分保存回電影列表中虐先,以便我們能夠打印每部電影的名稱。在第五步中派敷,我們按照我們計(jì)算的差異分?jǐn)?shù)對(duì)電影列表進(jìn)行排序蛹批,以便在列表中首先顯示最少的不同電影。
這里pandas提供了一個(gè)方便的排序值函數(shù)篮愉。最后腐芍,在第六步中,我們打印排序列表中的前五個(gè)電影试躏。這些是與當(dāng)前電影最相似的電影猪勇。
好的,我們來運(yùn)行這個(gè)程序颠蕴。用戶正在看的電影被稱為大城市法官二泣刹,我們可以看到我們?yōu)檫@部電影計(jì)算的15個(gè)屬性。這是我們發(fā)現(xiàn)的五個(gè)最相似的電影犀被。第一部電影是用戶已經(jīng)看過的電影椅您。
這是有道理的,電影將是最相似的寡键,所以我們可以忽略第一行掀泳。接下來的四部電影是我們向用戶展示的類似項(xiàng)目。根據(jù)他們的頭銜昌腰,這些電影看起來可能非常相似。他們似乎都是關(guān)于犯罪和調(diào)查的電影膀跌。續(xù)集遭商,大城市法官三,都在名單上捅伤。這是用戶可能也會(huì)感興趣的電影劫流。您可以更改電影ID并再次運(yùn)行該程序,以查看與其他電影類似的內(nèi)容。
結(jié)語
下一節(jié)將會(huì)講解如何使用推薦系統(tǒng).
你的 關(guān)注-收藏-轉(zhuǎn)發(fā) 是我繼續(xù)分享的動(dòng)力!