推荐算法(一)电影推荐系统
目錄
一、推薦系統基本概念
1. 基于內容的推薦系統
2. 基于矩陣分解的協同過濾
3. 基于item的協同過濾
4. 基于用戶的協同過濾
5. 冷啟動問題 cold start
6. 混合算法
7. 推薦系統性能評估
線下評估
線上評估
二、使用TF構建電影推薦系統
1. 數據收集
2. 數據準備
3. 構建模型
4. 模型訓練
5. 模型評估
6. 構建完整的電影推薦系統
一、推薦系統基本概念
1. 基于內容的推薦系統
給定電影部分評分表和電影內容矩陣X,求解用戶喜好矩陣theta:
- 評分記錄表:i用戶對j電影是否評分了
- j用戶喜好 * i電影內容 = 預測j用戶對i電影的評分
- 正則化項:通過調整lambda防止theta構成的模型對原始數據集產生過擬合
優點:
- 不存在商品冷啟動
- 明確告訴用戶推薦的商品包含哪些屬性
缺點:
- 需要透徹的內容分析
- 很少給用戶帶來驚喜
- 存在用戶冷啟動
2. 基于矩陣分解的協同過濾
給定電影部分評分表和用戶喜好矩陣theta,求解電影內容矩陣X,再將theta和X相乘,得到完整的電影評分表:
同時求解X和theta,將以上兩個公式合并為:
?
給定電影內容矩陣X,用戶喜好矩陣theta,如何給用戶A推薦電影?
- 看用戶A看過哪些電影,然后找到電影內容矩陣X找到與之相似的電影,然后推薦給用戶A
- 使用用戶喜好矩陣theta找到與用戶A相似的其他用戶,將其他用戶看過的電影推薦給用戶A
如何計算兩部電影之間的相似度?
- 每個電影或每個用戶可以用向量表示,將每個向量想象成高維空間的一個點,兩點之間距離來度量兩個實例之間的相似性
優點:
- 能夠根據用戶的歷史信息推斷商品質量
- 不需要對商品有任何專業領域知識
缺點:
- 冷啟動問題
- gray sheep 如果沒有其他相似用戶,就無法推薦
- 復雜度會隨著商品數量和用戶數量的增加而增加
- 同義詞的影響
- shilling attack 刷分
3. 基于item的協同過濾
先計算商品之間的相似度:
再預測用戶對商品的評分,將其進行排序,選擇評分高的商品推薦給用戶:
4. 基于用戶的協同過濾
先找到與用戶A相似的其他用戶,看其他用戶購買過什么商品:
再預測用戶對商品的評分,將其進行排序,選擇評分高的商品推薦給用戶:
?
5. 冷啟動問題 cold start
針對新用戶:
- 對該用戶進行隨機推薦,但推薦的東西有可能是反感的
- 不推薦,用戶有行為后再推薦
針對新商品:
- 在網頁中增加一欄代表新電影,當新電影收看人數達到100人,并且被評分,就將該電影的評分信息加入評分表中,然后參與到推薦系統的計算中,最后就可推薦該電影
重要的是解決的問題的方案,然后去實踐,測試,優化!
6. 混合算法
組合多種推薦算法:
- mixed:使用多個推薦系統同時推薦,將結果推薦給用戶
- feature combination:將多個推薦系統使用的特征組合起來給另一個推薦系統
- cascade:一個推薦系統產生結果后用另一個系統進行篩選,將篩選結果推薦給用戶
- switching:根據當前狀態在不同的推薦系統之間進行切換
7. 推薦系統性能評估
線下評估
RMSE 均方根誤差:
MAE 絕對值誤差:
Recall 召回率:
- 針對評分不多的商品
- recall =?6/10 = 0.6
- recall值越大,推薦系統包含越多用戶所需,目標是推薦的商品盡可能是用戶所需
??
Precision:
- 6/50 = 0.12
- 與recall結合,當兩者分值都很大,系統好
F1 score:
?
- F分值越大越好
- 如果推薦系統預測用戶A會買商品i,實際也如此,是tp,如果實際沒有,是fp
- 如果推薦系統預測用戶A不會買商品i,實際也如此,是tn,如果實際買了,是fn
線上評估
- 并不是線下評估越好,線上也好
- 而是利潤越高越好
CTR:click through rate 用戶點擊率
- 推薦系統重復推薦類似商品10次,用戶點擊3次,CTR = 0.3,越高代表用戶感興趣
CR:conversion rate 轉化率
- 用戶點擊后,是否看完這部電影或聽完這首歌或購買了商品,就是CR,越高代表用戶體驗好
ROI:不同的投資帶來的回報
- 越大,代表推薦系統性能越好
- 將回報定義為:利潤量增加,閱讀量增加
- 將代價定義為:計算資源成本
QA:成立QA小組,根據個人經驗評判推薦系統
二、使用TF構建電影推薦系統
1. 數據收集
https://grouplens.org/datasets.movielens/
2. 數據準備
import pandas as pd import numpy as np import tensorflow as tf# 加載文件和查看文件 ratings_df = pd.read_csv('ml-latest-small/ratings.csv') ratings_df.tail() movies_df = pd.read_csv('ml-latest-small/movies.csv') movies_df.tail()# 添加行號信息:因為movies表中的movieID遠大于行號,如果使用movieID的最大值來構建評分表,那么評分表是一個非常大的稀疏矩陣,浪費內存,所以使用行號標志電影 movies_df['movieRow'] = movies_df.index movies_df.tail()''' 創建兩個矩陣 1. 創建電影評分矩陣rating:用于記錄每個用戶對每個電影的評分 2. 創建用戶是否評分矩陣record:如果評分是1,否則為0 '''# 首先篩選movies_df中的特征 movies_df = movies_df[['movieRow', 'movieId', 'title']]# 保存該處理后的數據 movies_df.to_csv('moviesProcessed.csv', index=False, header=True, encoding='utf-8') movies_df.tail()# 將ratings_df中的movieId替換為行號 ratings_df = pd.merge(ratings_df, movies_df, on='movieId') ratings_df.head()# 篩選需要用到的特征 ratings_df = movies_df[['movieRow', 'userId', 'rating']] ratings_df.to_csv('ratingsProcessed.csv', index=False, header=True, encoding='utf-8') ratings_df.head()# 1. 創建電影評分矩陣rating:用于記錄每個用戶對每個電影的評分 # 獲取用戶最大編號:作為rating矩陣中的列 userNo = ratings_df['userId'].max()+1 # 獲取電影最大編號:作為rating矩陣中的行 movieNo = ratings_df['movieRow'].max()+1 # 創建rating矩陣 # 全部初始化為0 rating = np.zeros((movieNo, userNo)) # 創建電影評分表:添入rating矩陣 flag = 0 # 記錄處理進度 ratings_df_length = np.shape(ratings_df)[0] # ratings_df的樣本個數# 將ratings_df中的數據填寫到rating中 for index, row in ratings_df.iterrows():rating[int(row['movieRow']), int(row['userId'])] = row['rating'] # 將row中的評分rating,填入rating中的電影編號和用戶編號flag += 1 # 處理完一行print('processed %d, %d left' % (flag, ratings_df_length-flag)) # # 2. 創建用戶是否評分矩陣record:如果已經評分是1,否則為0 # 在電影評分表中,為0代表未評分 record = rating > 0 # 因為record中是布爾值組成的矩陣,將其轉化為0和1 record = np.array(record, dtype=int)3. 構建模型
# 對評分取值范圍進行縮放 # 定義函數:接受兩個參數:電影評分表,評分記錄表 def normalizeRating (rating, record):m, n = rating.shape # m電影數,n用戶數# 每個電影每個用戶的評分平均值rating_mean = np.zeros((m, 1)) # 所有電影平均評分初始化為0rating_norm = np.zeros((m, n)) # 保存處理之后的數據for i in range(m): # 將原始評分減去平均評分,將結果和平均評分返回idx = record[i, :] != 0 # 已評分的電影對應的用戶下標rating_mean[i] = np.mean(rating[i, idx]) # 記錄這些評分的平均值,第i部電影rating_norm[i, idx] -= rating_mean[i] # 原始評分減去評分的平均值return rating_norm, rating_meanrating_norm, rating_mean = normalizeRatings(rating, record) # 結果提示有全0數據,需處理rating_norm = np.nan_to_num(rating_norm) # 將nan數據轉換為0 rating_mean = np.nan_to_num(rating_mean) # 將nan數據轉換為0num_features = 10 # 假設有10種類型的電影# 初始化電影內容矩陣X,產生的每個參數都是隨機數且正態分布 X_parameters = tf.Variable(tf.random_normal([movieNo, num_features], stddev=0.35)) # 初始化用戶喜好矩陣theta,產生的每個參數都是隨機數且正態分布 Theta_parameters = tf.Variable(tf.random_normal([userNo, num_features], stddev=0.35)) # 定義代價函數loss:tf.reduce_sum求和,tf.matmul相乘,transpose_b=True轉置b項, loss = 1/2 * tf.reduce_sum(((tf.matmul(X_parameters, Theta_parameters, transpose_b=True) - rating_norm) * record) ** 2) + 1/2 * (tf.reduce_sum(X_parameters ** 2) + tf.reduce_sum(Theta_parameters ** 2)) # 后面部分是正則化項,lambda為1,可以調整lambda來觀察模型性能變化# 創建adam優化器和優化目標 optimizer = tf.train.AdamOptimizer(le-4) # 學習速率10^-4 train = optimizer.minimize(loss) # 目標:最小化代價函數4. 模型訓練
# 查看代價值隨著迭代次數增加的變化情況 # 使用tensorboard將整個訓練可視化 # tensorboard中tf.summary模塊用于將tensorflow的數據導出,從而可視化# 由于需要可視化的loss值是標量,所以要用summary中的scalar tf.summary.scalar('loss', loss)# 將所有summary信息匯總 summaryMerged = tf.summary.merge_all()# 保存信息的路徑 filename = './movie_tensorboard' # FileWriter用于把信息保存到文件中 writer = tf.summary.FileWriter(filename)# 創建tensorflow會話 sess = tf.Session() init = tf.global_variables_initializer() sess.run(init)# 訓練模型,訓練次數5000 for i in range(5000):_, movie_summary = sess.run([train, summaryMerged]) # 記錄每次迭代的loss的變化,每次train訓練的結果保存到_中writer.add_summary(movie_summary, i) # 訓練后保存數據,代價值隨著迭代次數i的變化情況''' 查看代價值隨著迭代次數的變化情況: 1. 打開cmd操作界面 2. 切換cd到保存數據的路徑中 3. 運行:tensorboard --logdir=./ 4. 瀏覽器中輸入:127.0.0.1:6006 5. 可以看到代價值隨著迭代次數的增加而減小 '''5. 模型評估
# 測試不同的num_features的值,通過比較誤差,判斷哪個num_features的值最合適 # 使用前面得到的參數,填滿電影評分表# 獲取當前X和theta Current_X_parameters, Current_Theta_parameters = sess.run([X_parameters, Theta_parameters])# 將電影內容矩陣和用戶喜好矩陣相乘,再加上每一行的均值,得到一個完整的電影評分表 # dot用于矩陣之間的乘法操作 predicts = np.dot(Current_X_parameters, Current_Theta_parameters.T) + rating_mean# 計算預測值與真實值之間的算數平方根作為預測誤差 errors = np.sqrt(np.sum((predicts - rating)**2)) errors6. 構建完整的電影推薦系統
# 獲取用戶ID,并保存 user_id = input('您要向哪位用戶進行推薦?請輸入用戶編號:')# 獲取對該用戶電影評分的列表 # 預測出的用戶對電影的評分,并從大到小排序 sortedResult = predicts[:, int(user_id)].argsort()[::-1]# 向該用戶推薦評分最高的20部電影 idx = 0 # 保存已經推薦了多少部電影 print('為該用戶推薦的評分最高的20部電影是'.center(80, '='))# 開始推薦 for i in sortedResult:print('評分:%.2f, 電影名:%s' % (predicts[i, int(user_id)], movies_df.iloc[i]['title']))idx += 1 # 已經推薦的電影if idx == 20: break總結
以上是生活随笔為你收集整理的推荐算法(一)电影推荐系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: R内存扩展 win7内存扩展
- 下一篇: SaaS窘境[欣赏然后翻译之]