《推荐系统实战(一)》基于统计的电影推荐系统(tmdb-5000数据集,数据清洗、特征提取、搭建模型等详细过程)
前言
本文將利用kaggle上的電影數據tmdb-5000(已上傳,可免費下載;若收費,請聯系作者修改),實現一個電影推薦系統。由于數據集并不涉及到用戶行為數據,所以我們只能用基于統計或者基于內容的推薦方法。
我們將整個項目分為三個部分。
- 數據讀取
- 數據預處理和數據可視化
- 搭建推薦系統
在第一部分,我們看到tmdb-5000的兩個csv文件里面實際上包含著json格式的數據,我們需要對其進行提取。
在第二部分,我們對缺失值和關鍵詞信息進行處理,提高數據質量;我們還對部分信息進行可視化展示,方便直觀了解數據。
在第三部分,我們將整個推薦系統分為召回和過濾兩個階段。
- 在召回階段,我們通過提取關鍵詞、導演、演員、類別等特征,計算其他電影與當前電影的相似度,并進而取出最相似的40部電影;
- 在過濾階段,我們將進一步考慮其他特征,如年代、投票等,對召回結果進行進一步的過濾和打分;
- 最終,根據最后過濾階段的打分,我們推薦打分最高的4部電影
下面,我們將詳細介紹每一部分。
Part 1. 數據讀取
Step 1
點開tmdb_5000_movies.csv文件,可以發現某些數據是字典,如下
特征"genres"下第一行
用json.load()函數來讀取此類字典數據,讀取后為
[{'id': 28, 'name': 'Action'},{'id': 12, 'name': 'Adventure'},{'id': 14, 'name': 'Fantasy'},{'id': 878, 'name': 'Science Fiction'}]Step 2
對于特征"genres",我們不需要其中的id,僅僅需要類別名稱,因此,從"genres"中抽取類別名稱。
具體的,我們在tmdb_5000_movies.csv文件中,
- 從“genres”中抽取電影類別名稱
- 從“keywords”中抽取關鍵詞名稱
- 從“production_companies”中抽取出公司名稱
- 從“production_countries”中抽取出國家名稱
- 從“spoken_languages”中抽取出語言名稱
在tmdb_5000_credits.csv文件中,
- 從“cast”中抽取演員名稱
- 從“crew”中抽取導演名稱(劇組中我們通常只看導演)
Step 3
這樣抽取完成之后,我們將兩個數據集根據電影id合并起來,形成一個dataframe,方便后面數據處理。
此時,dataframe看起來是這樣的
Part 2. 數據清洗以及可視化
經過初步處理之后的數據,其實是有些問題的,對于推薦系統而言,
- 特征重復,如"title_x"和“title_y”
- 無用特征,如“original_language”,“budget”,“revenue”等
- 特征提取,如“release_date”可以簡單為年份或者時代
- 缺失值處理
數據經過處理之后,我們可以進行可視化,對數據有一個直觀的了解,具體的,
- 電影年份分布
- 電影關鍵詞
- 電影類別趨勢
Step 1. 數據清洗
Step 1.1. 舍去無用特征
由于我們關心的是電影的推薦,所以,我們將以下特征舍去
- 電影投資收益信息:‘budget’,‘revenue’
- 電影內容信息:‘homepage’, ‘tagline’
- 電影制作信息:‘production_companies’, ‘production_countries’,‘status’,‘runtime’
- 電影重復信息:‘id’,‘original_language’, ‘original_title’,‘title_y’
舍去無用特征之后,我們剩下如下特征,
- ‘id’:電影唯一標識
- ‘title’:電影名稱
- ‘actors’:電影所有演員名字
- ‘director’:電影導演名字
- ‘genres’:電影類別
- ‘keywords’:電影關鍵詞
- ‘popularity’:基于某種方法算出來的電影流行度
- ‘date’:電影發布日期
- ‘vote_average’:電影平均評分
- ‘vote_count’:給電影打分人數
- ‘overview’:電影簡介
Step 1.2. 缺失值
為了直觀看當前數據的缺失值情況,我們給出缺失值表格
從上面表格可以看出,除了keywords之外,其余特征缺失值占總體數據比例非常低(均在1%之下),我們對這些缺失值直接做舍棄處理。
我們主要考慮keywords缺失值。
- keywords缺失值占總體數據8.58%,如果能夠填充,當然最好
- 直觀上說,keywords與overview和genres很接近,我們或許能從overview和genres中提出信息對keywords進行填充
- 對overview進行tf-idf處理,提取出有代表性的單詞,作為keywords
然而實際情況是,我們有4000多個數據,當僅用100個數據對overview進行tf-idf處理時,得到的結果已經很不理想。以第一行數據為例,
- 實際keywords:[‘culture clash’, ‘future’, ‘space war’, ‘space colony’, ‘society’, ‘space travel’, ‘futuristic’, ‘romance’, ‘space’, ‘alien’, ‘tribe’, ‘alien planet’, ‘cgi’, ‘marine’, ‘soldier’, ‘battle’, ‘love affair’, ‘anti war’, ‘power relations’, ‘mind and soul’, ‘3d’]
- overview的tf-idf處理結果:[‘22nd’, ‘dispatched’, ‘orders’, ‘pandora’, ‘paraplegic’, ‘protecting’]
- genres:[‘Action’, ‘Adventure’, ‘Fantasy’, ‘Science Fiction’]
可以看到,實際keywords與overview和genres的處理結果相差很大,為了避免影響數據質量,我們決定不對keywords進行填充,對缺失值所在行直接舍去。
此時,我們一同舍去的還有overview,因為我們只需要用genres和keywords對電影內容進行刻畫就行,而相似電影的overview可能完全不同。因此,我們
- 舍去keywords缺失值
- 舍去overview特征
Step 1.3. 特征處理
我們主要對date和keywords進行處理,具體來說,
- 從date中取出年份信息
- 根據年份信息得到年代信息
- 從keywords中取出每個關鍵詞的詞根(考慮到很多關鍵詞都是同一個詞根的動名詞變化等等)
- 對出現次數較低的關鍵詞予以刪除,比如低于3次
- (可選項)將同義的關鍵詞用同一個關鍵詞代替
之所以對date這樣處理,是因為電影往往和年代有關,比如90年代的電影相比于80年代的電影,有更大的區分度。
之所以對關鍵詞這樣處理,是因為后面我們將關鍵詞作為特征來計算相似度,我們需要盡量保證特征之間的獨立性,以及特征方差較大。
對date的處理結果如下
而對keywords的處理,我們首先用nltk的PorterStemmer()找出一個關鍵詞的詞根,然后用nltk的wordnet給出關鍵詞的同義詞。但是,這樣比較耗費時間,同時效果并不明顯。這是因為,經過刪除出現頻率較低的關鍵詞之后,我們的關鍵詞已經從9000多降低到2000多,再進行同義詞處理效果不明顯。
另外,我們還要對actors進行處理。這是因為觀眾往往僅關注少數的幾個主演,對于其他演員并不敏感。
Step 2. 可視化
-
第一張圖:演員詞云展示
從詞云圖中可以明顯看出,Robert De Niro(羅伯特·德尼羅)、Nicolas Cage(尼古拉斯凱奇)、Bruce Willis(布魯斯威利斯)、Morgan Freeman等人出演電影較多。實際上,這些人也都是非常著名和成功的演員。 -
第二張圖:導演詞云展示
通過詞云,可以明顯找到steven spielberg(斯蒂芬 斯皮爾伯格)、Clint Eastwood(克林特·伊斯特伍德)等眾多名導演。 -
第三張圖:電影類型的時間趨勢圖
上面實際上是從1916年到2015年間,美國電影的類別趨勢圖。可以較為明顯的看到,從95年左右電影數量開始大量增長,同時,較為流行的電影類型始終是 drama(劇情片)、thriller(驚悚)、action(動作片)、romance(愛情片)和crime(犯罪片)等。 -
第四張圖:不同年代的電影占比
從上圖中可以明顯看出,90年代至今的電影占據了大多數,其中相比于90年代,00年代的電影數量顯著增加,而10年代之所以數量較少,是因為10年代的僅僅統計到2015年。 -
第五張圖:不同流行度電影的數量
可以看到,大部分電影的流行度都較低,流行度超過200以上的非常少。 -
第六張圖:不同打分下的電影數量
從上面可以看出來,大部分打分都集中在5-8分,但相比于低分段0-5分的其他分數,0分的電影數量反而更多。
Part 3. 推薦引擎
經過上面的數據清洗,我們基本上得到想要的數據。現在,根據這些數據,對于給定的一部電影,我們推薦5部電影。
我們將過程分為 召回 和過濾部分。在召回階段,我們從所有電影中選出40部電影,在過濾部分,我們從這40部電影中,進一步篩選出5部電影作為最終推薦。
在召回階段,通過考慮電影的類別信息、導演信息、主演信息和內容的關鍵詞信息,構建特征,通過計算電影之間在給定特征下的相似度,我們給出最相似的40部電影。
在過濾階段,我們進一步考慮電影的年份信息、評分信息、流行度信息等,對電影進行進一步打分。具體的,
- 對于年份越接近的電影,我們給的分越高
- 對于評分越高的電影,我們給的分越高
- 對于流行度較低但是評分較高的電影,我們給的分越高
基于上述想法,我們構建了推薦系統。
Part 4. 結果測試
我們給出兩個例子,測試推薦結果是否吸引人。
第一個例子,對于電影 阿凡達(Avatar),電影id為19995,推薦結果為
['Captain America: The Winter Soldier','Treasure Planet','Star Trek Into Darkness','Titan A.E.',"Ender's Game"]對于電影阿凡達,我們是清楚的,我們看看系統推薦了什么,
- Captain America: The Winter Soldier(美國隊長2),豆瓣評分8.0,看過的同學應該比較清楚,都是很經典的科幻冒險動作片
- Treasure Planet(星銀島,2002),豆瓣評分7.9,其實閱讀評論發現對這部電影評價很高,同樣是一部很好的科幻冒險片
- Star Trek Into Darkness(星際迷航2,2013),豆瓣評分8.0,同樣是一部經典的科幻冒險動作片
- Titan A.E.(冰凍星球,2000),豆瓣評分6.8,是一部科幻冒險動畫片,獲過多個大獎,應該是一部不錯的電影
- Ender’s Game(安德的游戲,2013),豆瓣評分7.0,個人很喜歡這部電影,是屬于科幻冒險動作類大片
可以看到,當一個人看完阿凡達之后,系統將會推薦上面5部電影,就我看過的美國隊長2、星際迷航2和安德的游戲而言,是非常恰當的,再就是星銀島和冰凍星球,年份相對較早,不過屬于經典之作,應該也值得一看。
第二個例子,對于電影 海底總動員(Finding Nemo),電影id為12,推薦結果為
['The Secret of Kells',"VeggieTales: The Pirates Who Don't Do Anything",'Winnie the Pooh','Tangled','Arthur Christmas']從上到下,電影名稱依次是,凱爾經的秘密(2009,豆瓣評分8.5,奇幻冒險動畫),無所事事的海盜(2008,豆瓣評分6.8,冒險家庭喜劇動畫),小熊維尼(2011,豆瓣評分8.0,冒險喜劇動畫),魔法奇緣(2010,豆瓣評分8.2,奇幻冒險動畫),亞瑟圣誕(2011,豆瓣評分7.6,喜劇動畫)。
從推薦的內容來看,評分都較高,大部分和海底總動員一樣,屬于適合家庭一起觀看的喜劇經典動畫。
評價:總體來看是達到預期效果的,期望系統推薦經典的高評分的相似電影,有些電影屬于冷門好看的,這正是我們期待的效果。
不足:對于原始信息中,有些特征,比如電影簡介、電影投入、電影收益之類的特征,我們沒有使用,如果能夠有效利用,或許能提供其他種類的推薦;再就是我們在設計特征的時候,實際上是人工設置的,可能換一種設置方法就能推薦不同的電影,這個也是值得商榷的。
附:github代碼
總結
以上是生活随笔為你收集整理的《推荐系统实战(一)》基于统计的电影推荐系统(tmdb-5000数据集,数据清洗、特征提取、搭建模型等详细过程)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构——c语言 队列杨辉三角
- 下一篇: Srm32 dwm1000 tdoa定位