原創-機器學習之推薦系統實戰

如何實現一個電影推薦系統

原創內容ios

轉載註明出處:http://www.vmfor.comgit

 

GavinHackergithub

推薦算法在互聯網行業的應用很是普遍,今日頭條、美團點評等都有個性化推薦,推薦算法抽象來說,是一種對於內容滿意度的擬合函數,涉及到用戶特徵和內容特徵,做爲模型訓練所需維度的兩大來源,而點擊率,頁面停留時間,評論或下單等均可以做爲一個量化的 Y 值,這樣就能夠進行特徵工程,構建出一個數據集,而後選擇一個合適的監督學習算法進行訓練,獲得模型後,爲客戶推薦偏好的內容,如頭條的話,就是諮詢和文章,美團的就是生活服務內容。算法

可選擇的模型不少,如協同過濾,邏輯斯蒂迴歸,基於DNN的模型,FM等。咱們使用的方式是,基於內容類似度計算進行召回,以後經過FM模型和邏輯斯蒂迴歸模型進行精排推薦,下面就分別說一下,咱們作這個電影推薦系統過程當中,從數據準備,特徵工程,到模型訓練和應用的整個過程。sql

咱們實現的這個電影推薦系統,爬取的數據實際上維度是相對少的,特別是用戶這一側的維度,正常推薦系統涉及的維度,諸如頁面停留時間,點擊頻次,收藏等這些維度都是沒有的,以及用戶自己的維度也相對要少,沒有地址、年齡、性別等這些基本的維度,這樣咱們爬取的數據只有打分和評論這些信息,因此以後咱們又從這些信息裏再拿出一些統計維度來用。咱們爬取的電影數據(除電影詳情和圖片信息外)是以下這樣的形式:app

image

這裏的數據是有冗餘的,又經過以下的代碼,對數據進行按維度合併,去除冗餘數據條目:機器學習

 1 # 處理主函數,負責將多個冗餘數據合併爲一條電影數據,將地區,導演,主演,類型,特點等維度數據合併
 2 
 3 def mainfunc():
 4     try:
 5         unable_list = []
 6         with connection.cursor() as cursor:
 7             sql='select id,name from movie'
 8             cout=cursor.execute(sql)
 9             print("數量: "+str(cout))
10 
11             for row in cursor.fetchall():
12                 #print(row[1])
13                 movieinfo = df[df['電影名'] == row[1]]
14                 if movieinfo.shape[0] == 0:
15                     disable_movie(row[0])
16                     print('disable movie ' + str(row[1]))
17                 else:
18                     g = lambda x:movieinfo[x].iloc[0]
19                     types = movieinfo['類型'].tolist()
20                     types = reduce(lambda x,y:x+'|'+y,list(set(types)))
21                     traits = movieinfo['特點'].tolist()
22                     traits = reduce(lambda x,y:x+'|'+y,list(set(traits)))
23                     update_one_movie_info(type_=types, actors=g('主演'), region=g('地區'), director=g('導演'), trait=traits, rat=g('評分'), id_=row[0])
24 
25         connection.commit()
26     finally:
27         connection.close()

 

以後開始準備用戶數據,咱們從用戶打分的數據中,統計出每個用戶的打分的最大值,最小值,中位數值和平均值等,從而做爲用戶的一個附加屬性,存儲於userproex表中:函數

1 'insert into userproex(userid, rmax, rmin, ravg, rcount, rsum, rmedian) values(\'%s\', %s, %s, %s, %s, %s, %s)' % (userid, rmax, rmin, ravg, rcount, rsum, rmedium)
2 
3 
4 'update userproex set rmax=%s, rmin=%s, ravg=%s, rmedian=%s, rcount=%s, rsum=%s where userid=\'%s\'' % (rmax, rmin, ravg, rmedium, rcount, rsum, userid)

 

以上兩個SQL是最終插入表的時候用到的,表明準備用戶數據的最終步驟,其他細節能夠參考文末的github倉庫,不在此贅述,數據處理還用到了一些SQL,以及其餘處理細節。學習

系統上線運行時,第一次是全量的數據處理,以後會是增量處理過程,這個後面還會提到。fetch

咱們目前把用戶數據和電影的數據的原始數據算是準備好了,下一步開始特徵工程。作特徵工程的思路是,對type, actors, director, trait四個類型數據分別構建一個頻度統計字典,用於以後的one-hot編碼,代碼以下:

 1 def get_dim_dict(df, dim_name):
 2   type_list = list(map(lambda x:x.split('|') ,df[dim_name]))
 3   type_list = [x for l in type_list for x in l]
 4   def reduce_func(x, y):
 5     for i in x:
 6       if i[0] == y[0][0]:
 7         x.remove(i)
 8         x.append(((i[0],i[1] + 1)))
 9         return x
10     x.append(y[0])
11     return x
12   l = filter(lambda x:x != None, map(lambda x:[(x, 1)], type_list))
13   type_zip = reduce(reduce_func, list(l))
14   type_dict = {}
15   for i in type_zip:
16     type_dict[i[0]] = i[1]
17   return type_dict

 

涉及到的冗餘數據也要刪除

df_ = df.drop(['ADD_TIME', 'enable', 'rat', 'id', 'name'], axis=1)

 

將電影數據轉換爲字典列表,因爲演員和導演均過萬維,實際計算時過於稀疏,當演員或導演只出現一次時,標記爲冷門演員或導演
movie_dict_list = []
for i in df_.index:
  movie_dict = {}
  #type
  for s_type in df_.iloc[i]['type'].split('|'):
    movie_dict[s_type] = 1
  #actors
  for s_actor in df_.iloc[i]['actors'].split('|'):
    if actors_dict[s_actor] < 2:
      movie_dict['other_actor'] = 1
    else:
      movie_dict[s_actor] = 1
  #regios
  movie_dict[df_.iloc[i]['region']] = 1
  #director
  for s_director in df_.iloc[i]['director'].split('|'):
    if director_dict[s_director] < 2:
      movie_dict['other_director'] = 1
    else:
      movie_dict[s_director] = 1
  #trait
  for s_trait in df_.iloc[i]['trait'].split('|'):
    movie_dict[s_trait] = 1
  movie_dict_list.append(movie_dict)

 

使用DictVectorizer進行向量化,作One-hot編碼

1 v = DictVectorizer()
2 X = v.fit_transform(movie_dict_list)

 

這樣的數據,下面作餘弦類似度已經能夠了,這是特徵工程的基本的一個處理,模型所使用的數據,須要將電影,評分,用戶作一個數據拼接,構建訓練樣本,並保存CSV,注意這個CSV不用每次全量構建,而是除第一次外都是增量構建,經過mqlog中類型爲'c'的消息,增量構建以comment(評分)爲主的訓練樣本,拼接以後的形式以下:

USERID    cf2349f9c01f9a5cd4050aebd30ab74f
movieid    10533913
type    劇情|奇幻|冒險|喜劇
actors    艾米·波勒|菲利絲·史密斯|理查德·坎德|比爾·哈德爾|劉易斯·布萊克
region    美國
director    彼特·道格特|羅納爾多·德爾·卡門
trait    感人|經典|勵志
rat    8.7
rmax    5
rmin    2
ravg    3.85714
rcount    7
rmedian    4
TIME_DIS    15

 

這個數據的actors等字段和上面的處理是同樣的,爲了以後libfm的使用,在這裏須要轉換爲libsvm的數據格式

dump_svmlight_file(train_X_scaling, train_y_, train_file)


有不少細節不在這裏描述,這樣大概的特徵工程工做就作好了,以後使用類似度計算,FM,LR進行推薦模型的訓練。 具體訓練的過程不在這裏進行闡述了,能夠參考代碼索引頁

 

所有子項目代碼地址

 

模型使用上遵循先召回,後精排的策略,先經過餘弦類似度計算一個類似度矩陣,而後根據這個矩陣,爲用戶推薦類似的M個電影,在經過訓練好的FM,LR模型,對這個M個電影作偏好預估,FM會預估一個用戶打分,LR會預估一個點擊機率,綜合結果推送給用戶做爲推薦電影。

 

作了這個電影推薦系統後,感受算是對本身這麼長時間學習機器學習知識作一個綜合的實踐,有很多的感悟,如今有不少學習機器學習的同窗,建議在你們刷論文的同時,也注重在項目中實踐,計算機科學,雖然叫作科學,實際倒是一門實踐性學科,一些AI頂級大牛,他們並非數學家,也不是理論家,大可能是從理論和實踐結合這條路成就的,和金庸小說中的武林絕技是一個道理。說到這,你們都知道,最近朋友圈被《94射鵰英雄傳》AI換臉楊冪刷屏了,看來AI視頻換臉技術發展已經至關快,仔細想一想,這已是AI進入藝術創做領域的一個表象,筆者認爲AI以後的發展必定是從互聯網行業擴展出去,變成IT產業當中的一個重要的技術支柱。

 

相關文章
相關標籤/搜索