Python機器學習(8)——推薦算法之推薦矩陣


每個人都會有這樣的經歷:當你在電商網站購物時,你會看到天貓給你彈出的“和你買了同樣物品的人還買了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這樣的數據對。如下圖所示:

 

1 1 3
1 2 3
1 3 3
1 4 1
2 1 1
2 2 1
2 3 1
2 4 1
......

如第一行對應着用戶1購買了商品1,數量為3。可以認為該數據是一個稀疏矩陣。該矩陣可視化出來結果如下:

 

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

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

3、代碼與分析

 

# -*- coding: utf-8 -*-
from matplotlib import pyplot
import scipy as sp
import numpy as np
from matplotlib import pylab
from sklearn.datasets import load_files
from sklearn.cross_validation import train_test_split
from sklearn.metrics import precision_recall_curve, roc_curve, auc
from sklearn.metrics import classification_report
 
import time
from scipy import sparse
 
start_time = time.time()
 
#計算向量test與data數據每一個向量的相關系數,data一行為一個向量
def calc_relation(testfor, data):
    return np.array(
        [np.corrcoef(testfor, c)[0,1]
         for c in data])
 
# luispedro提供的加速函數:
def all_correlations(y, X):
    X = np.asanyarray(X, float)
    y = np.asanyarray(y, float)
    xy = np.dot(X, y)
    y_ = y.mean()
    ys_ = y.std()
    x_ = X.mean(1)
    xs_ = X.std(1)
    n = float(len(y))
    ys_ += 1e-5  # Handle zeros in ys
    xs_ += 1e-5  # Handle zeros in x
    return (xy - x_ * y_ * n) / n / xs_ / ys_
 
        
#數據讀入
data = np.loadtxt('1.txt')
x_p = data[:, :2] # 取前2列
y_p = data[:,  2] # 取前2列
x_p -= 1          # 0為起始索引
y = (sparse.csc_matrix((data[:,2], x_p.T)).astype(float))[:, :].todense()
nUser, nItem = y.shape
 
 
#可視化矩陣
pyplot.imshow(y, interpolation='nearest')
pyplot.xlabel('商品')
pyplot.ylabel('用戶')
pyplot.xticks(range(nItem))
pyplot.yticks(range(nUser))
pyplot.show()
 
 
#加載數據集,切分數據集80%訓練,20%測試
x_p_train, x_p_test, y_p_train, y_p_test = \
          train_test_split(data[:,:2], data[:,2], test_size = 0.0)    
x = (sparse.csc_matrix((y_p_train, x_p_train.T)).astype(float))[:, :].todense()
    
 
Item_likeness = np.zeros((nItem, nItem))
 
#訓練    
for i in range(nItem):
    Item_likeness[i] = calc_relation(x[:,i].T, x.T)
    Item_likeness[i,i] = -1        
        
for t in range(Item_likeness.shape[1]):
    item = Item_likeness[t].argsort()[-3:]
    print("Buy Item %d will buy item %d,%d,%d "%
          (t, item[0], item[1], item[2]))
 
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提供的一種計算相關系數的替換函數,效率能提高不少。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM