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

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

全部這一切,都是背後的推薦算法運做的結果。最經典的關聯規則算法是大名鼎鼎的Apriori算法,源自一個超市購物籃的故事:啤酒老是和尿布一塊兒被購買。有興趣的能夠去看看。算法

本章咱們來學習一種最簡單的推薦算法:推薦矩陣。雖然簡單,可是卻被普遍應用着。函數

一、推薦矩陣

爲描述方便,如下咱們以「購物推薦」做爲背景進行介紹。假設你有個賣商品的網站,擁有每一個用戶購買每一個物品的數據。如今,某個用戶A購買了商品a,如何向他推薦他最有可能感興趣的其餘商品呢?學習

爲達到這個目的,一般有兩種思路:測試

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

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

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

這種狀況是以商品爲中心的,所以更適合購物推薦這樣的場景。rest

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

所以這裏,咱們介紹皮爾森相關係數(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個推薦給用戶便可。

二、測試數據

數據爲一份簡單的購物清單,每一行對應着用戶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購買過,看上去就像是捆綁銷售的通常。

三、代碼與分析

 

# -*- 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提供的一種計算相關係數的替換函數,效率能提升很多。

相關文章
相關標籤/搜索