用Python開始機器學習(9:推薦算法之推薦矩陣)

每個人都會有這樣的經歷:當你在電商網站購物時,你會看到天貓給你彈出的“和你買了同樣物品的人還買了XXX”的信息;當你在SNS社交網站閒逛時,也會看到彈出的“你可能認識XXX“的信息;你在微博添加關注人時,也會看到“你可能對XXX也感興趣”;等等。

所有這一切,都是背後的推薦算法運作的結果。最經典的關聯規則算法是大名鼎鼎的Apriori算法,源自一個超市購物籃的故事:啤酒總是和尿布一起被購買。有興趣的可以去看看。

本章我們來學習一種最簡單的推薦算法:推薦矩陣。雖然簡單,但是卻被廣泛應用着。

1、推薦矩陣

爲描述方便,以下我們以“購物推薦”作爲背景進行介紹。假設你有個賣商品的網站,擁有每個用戶購買每個物品的數據。現在,某個用戶A購買了商品a,如何向他推薦他最有可能感興趣的其他商品呢?

爲達到這個目的,通常有兩種思路:

1:尋找與該用戶(A)購買習慣最爲相似的用戶(B),認爲B購買的物品,A也最有可能感興趣。

這種情況適用於A已經購買過一些商品,算法能夠根據A已經購買的物品作爲特徵,去匹配與A購買習慣最相近的用戶。這種方式是以用戶爲中心的,推薦出來的商品b可能跟商品a風流馬不相及,因此更適合於類似SNS和微博這樣的平臺,根據用戶的已知興趣集合來向其推薦其他具有相同興趣的用戶;

2:尋找與商品(a)最爲相似的商品(b),認爲A既然對a感興趣,也有可能對b感興趣;

這種情況是以商品爲中心的,因此更適合購物推薦這樣的場景。

 而要計算兩個向量“最相似”的程度,有很多方法,如KNN中用到的歐式距離,或者海明距離等。但是歐式距離並不適用於本場合。比如用戶A購買了5個商品a,5個商品b,用戶B購買了5個商品a,0個商品b,用戶C購買了10個商品a,10個商品b,用距離來度量的結果必然是A與B更近。而實際上A跟C是極其相似的。

因此這裏,我們介紹皮爾森相關係數(Pearson correlation coefficient)。其定義如下:


該係數定義的是兩個向量的線性相關程度,取值範圍爲[-1,+1],0表示線性無關,絕對值越大線性相關程度越大,正/負表示正/負線性相關。

簡單的給幾個例子:

[1,2,3],[4,5,6]:1

[1,2,3],[6,5,4]:-1

[1,2,3],[1,2,4]:0.98

[1,2,3],[-1,-11,-111]:-0.9

因此,我們將構造一個矩陣來描述用戶購買商品的情況,該矩陣以用戶爲行、商品爲列。要計算某個商品a最相似的商品,我們通過計算商品a所在的列與其他的每一列的皮爾森相關係數,找出最大的前N個推薦給用戶即可。

2、測試數據

數據爲一份簡單的購物清單,每一行對應着用戶id——商品id這樣的數據對。如下圖所示:

[plain] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. 1 1 3  
  2. 1 2 3  
  3. 1 3 3  
  4. 1 4 1  
  5. 2 1 1  
  6. 2 2 1  
  7. 2 3 1  
  8. 2 4 1  
  9. ......  
如第一行對應着用戶1購買了商品1,數量爲3。可以認爲該數據是一個稀疏矩陣。該矩陣可視化出來結果如下:


上圖中每一行代表一個用戶,每一列代表一個商品,對應的顏色不同表示購買的數量不同,深藍色表示購買數爲0。

從圖上很容易看出,用戶0與用戶1同時購買了商品0,1,2,僅僅數量不一樣;而商品0和商品1售出的情況一模一樣——只被用戶0,1,3,8購買過,看上去就像是捆綁銷售的一般。

3、代碼與分析

[python] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. # -*- coding: utf-8 -*-  
  2. from matplotlib import pyplot  
  3. import scipy as sp  
  4. import numpy as np  
  5. from matplotlib import pylab  
  6. from sklearn.datasets import load_files  
  7. from sklearn.cross_validation import train_test_split  
  8. from sklearn.metrics import precision_recall_curve, roc_curve, auc  
  9. from sklearn.metrics import classification_report  
  10.   
  11. import time  
  12. from scipy import sparse  
  13.   
  14. start_time = time.time()  
  15.   
  16. #計算向量test與data數據每一個向量的相關係數,data一行爲一個向量  
  17. def calc_relation(testfor, data):  
  18.     return np.array(  
  19.         [np.corrcoef(testfor, c)[0,1]  
  20.          for c in data])  
  21.   
  22. # luispedro提供的加速函數:  
  23. def all_correlations(y, X):  
  24.     X = np.asanyarray(X, float)  
  25.     y = np.asanyarray(y, float)  
  26.     xy = np.dot(X, y)  
  27.     y_ = y.mean()  
  28.     ys_ = y.std()  
  29.     x_ = X.mean(1)  
  30.     xs_ = X.std(1)  
  31.     n = float(len(y))  
  32.     ys_ += 1e-5  # Handle zeros in ys  
  33.     xs_ += 1e-5  # Handle zeros in x  
  34.     return (xy - x_ * y_ * n) / n / xs_ / ys_  
  35.   
  36.           
  37. #數據讀入  
  38. data = np.loadtxt('1.txt')  
  39. x_p = data[:, :2# 取前2列  
  40. y_p = data[:,  2# 取前2列  
  41. x_p -= 1          # 0爲起始索引  
  42. y = (sparse.csc_matrix((data[:,2], x_p.T)).astype(float))[:, :].todense()  
  43. nUser, nItem = y.shape  
  44.   
  45.   
  46. #可視化矩陣  
  47. pyplot.imshow(y, interpolation='nearest')  
  48. pyplot.xlabel('商品')  
  49. pyplot.ylabel('用戶')  
  50. pyplot.xticks(range(nItem))  
  51. pyplot.yticks(range(nUser))  
  52. pyplot.show()  
  53.   
  54.   
  55. #加載數據集,切分數據集80%訓練,20%測試  
  56. x_p_train, x_p_test, y_p_train, y_p_test = \  
  57.           train_test_split(data[:,:2], data[:,2], test_size = 0.0)      
  58. x = (sparse.csc_matrix((y_p_train, x_p_train.T)).astype(float))[:, :].todense()  
  59.       
  60.   
  61. Item_likeness = np.zeros((nItem, nItem))  
  62.   
  63. #訓練      
  64. for i in range(nItem):  
  65.     Item_likeness[i] = calc_relation(x[:,i].T, x.T)  
  66.     Item_likeness[i,i] = -1          
  67.           
  68. for t in range(Item_likeness.shape[1]):  
  69.     item = Item_likeness[t].argsort()[-3:]  
  70.     print("Buy Item %d will buy item %d,%d,%d "%  
  71.           (t, item[0], item[1], item[2]))  
  72.   
  73. print("time spent:", time.time() - start_time)  
輸出如下:

Buy Item 0, recommond item 3,2,1 
Buy Item 1, recommond item 3,2,0 
Buy Item 2, recommond item 3,0,1 
Buy Item 3, recommond item 0,1,5 
Buy Item 4, recommond item 6,7,8 
Buy Item 5, recommond item 0,1,3 
Buy Item 6, recommond item 4,7,8 
Buy Item 7, recommond item 4,8,6 
Buy Item 8, recommond item 4,7,6 
time spent: 1.9111089706420898

代碼中,我們計算了每一個Item與其他所有item的相關性,然後排序選取最大的前3個作爲推薦。

最需要注意的是,真正的應用中,大量的用戶與大量的商品之間建立矩陣,計算量是巨大的。從皮爾森相關係數的定義來看,其計算量也是巨大的。因此代碼中給了luispedro提供的一種計算相關係數的替換函數,效率能提高不少。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章