簡易推薦系統功能:
1.基於物品相似度,向同一用戶推薦不同的相似商品(user:items=1:N);
2.基於用戶相似度,將同一商品推薦給不同的未購買用戶(users:item=N:1);
#coding=utf-8
"""
簡易推薦系統:
1.基於物品相似度,向同一用戶推薦不同的相似商品(user:items=1:N);
2.基於用戶相似度,將同一商品推薦給不同的未購買用戶(users:item=N:1);
"""
from numpy import *
from numpy import linalg as la
'''加載測試數據集'''
def loadExData():
return np.mat([[0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 5],
[0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 3],
[0, 0, 0, 0, 4, 0, 0, 1, 0, 4, 0],
[3, 3, 4, 0, 0, 0, 0, 2, 2, 0, 0],
[5, 4, 5, 0, 0, 0, 0, 5, 5, 0, 0],
[0, 0, 0, 0, 5, 0, 1, 0, 0, 5, 0],
[4, 3, 4, 0, 0, 0, 0, 5, 5, 0, 1],
[0, 0, 0, 4, 0, 4, 0, 0, 0, 0, 4],
[0, 0, 0, 2, 0, 2, 5, 0, 0, 1, 2],
[0, 0, 0, 0, 5, 0, 0, 0, 0, 4, 0],
[1, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0]])
'''以下是三種計算相似度的算法,分別是歐式距離、皮爾遜相關係數和餘弦相似度,
注意三種計算方式的參數inA和inB都是列向量'''
def ecludSim(inA,inB):
return 1.0/(1.0+la.norm(inA-inB)) #範數的計算方法linalg.norm(),這裏的1/(1+距離)表示將相似度的範圍放在0與1之間
def pearsSim(inA,inB):
if len(inA)<3: return 1.0
return 0.5+0.5*np.corrcoef(inA,inB,rowvar=0)[0][1] #皮爾遜相關係數(範圍[-1,1])的計算方法corrcoef(),參數rowvar=0表示對列求相似度,這裏的0.5+0.5*corrcoef()是爲了將範圍歸一化放到0和1之間
def cosSim(inA,inB):
num=float(inA.T*inB)
denom=la.norm(inA)*la.norm(inB) #計算模長的函數
return 0.5+0.5*(num/denom) #將相似度歸一到0與1之間
'''按照前k個奇異值的平方和佔總奇異值的平方和的百分比percentage來確定k的值,
後續計算SVD時需要將原始矩陣轉換到k維空間'''
def sigmaPct(sigma,percentage):
sigma2=sigma**2 #對sigma求平方
sumsgm2=sum(sigma2) #求所有奇異值sigma的平方和
sumsgm3=0 #sumsgm3是前k個奇異值的平方和
k=0
for i in sigma:
sumsgm3+=i**2
k+=1
if sumsgm3>=sumsgm2*percentage:
return k
'''函數svdEst()的參數包含:數據矩陣、用戶編號、物品編號和奇異值佔比的閾值,
數據矩陣的行對應用戶,列對應物品,函數的作用是基於item的相似性對用戶未評過分的物品進行預測評分'''
xformedItems000=[] #存儲中間過程,以備驗證和查看
sssssss000=[]
def svdEst(dataMat,user,simMeas,item,percentage):
n=np.shape(dataMat)[1]
simTotal=0.0;ratSimTotal=0.0
u,sigma,vt=la.svd(dataMat) #dataMat,對商品列做降維
sssssss000.append([u,sigma,vt])
k=sigmaPct(sigma,percentage) #確定了k的值
sigmaK=np.mat(np.eye(k)*sigma[:k]) #構建對角矩陣
xformedItems=dataMat.T*u[:,:k]*sigmaK.I #根據k的值將原始數據轉換到k維空間(低維),xformedItems表示物品(item)在k維空間轉換後的值
xformedItems000.append(xformedItems)
for j in range(n):
userRating=dataMat[user,j]
if userRating==0 or j==item:
continue
similarity=simMeas(xformedItems[item,:].T,xformedItems[j,:].T) #計算物品item與物品j之間的相似度
simTotal+=similarity #對所有相似度求和
ratSimTotal+=similarity*userRating #用"物品item和物品j的相似度"乘以"用戶對物品j的評分",並求和
if simTotal==0:
return 0
else:
return ratSimTotal/simTotal #得到對物品item的預測評分
xformedItems1111=[]
sssssss111=[]
def svdEst1(dataMat,item,simMeas,user,percentage):
n=np.shape(dataMat)[0]
simTotal=0.0;ratSimTotal=0.0
u,sigma,vt=la.svd(dataMat.T) #dataMat.T,對用戶列做降維
sssssss111.append([u,sigma,vt])
k=sigmaPct(sigma,percentage) #確定了k的值
sigmaK=np.mat(np.eye(k)*sigma[:k]) #構建對角矩陣
xformedItems=dataMat.T*u[:,:k]*sigmaK.I #根據k的值將原始數據轉換到k維空間(低維),xformedItems表示物品(item)在k維空間轉換後的值
#np.shape(xformedItems1111[0]) #(3, 11)
xformedItems1111.append(xformedItems)
for j in range(n):
itemRating=dataMat.T[item,j]
if itemRating==0 or j==user:
continue
similarity=simMeas(xformedItems[user,:].T,xformedItems[j,:].T) #計算物品item與物品j之間的相似度
simTotal+=similarity #對所有相似度求和
ratSimTotal+=similarity*itemRating #用"物品item和物品j的相似度"乘以"用戶對物品j的評分",並求和
if simTotal==0:
return 0
else:
return ratSimTotal/simTotal #得到對物品item的預測評分
'''函數recommend()產生預測評分最高的N個推薦結果,默認返回5個;
參數包括:數據矩陣、用戶編號、相似度衡量的方法、預測評分的方法、以及奇異值佔比的閾值;
數據矩陣的行對應用戶,列對應物品,函數的作用是基於item的相似性對用戶未評過分的物品進行預測評分;
相似度衡量的方法默認用餘弦相似度'''
#給同一用戶,推薦不同的商品
def recommendSameUserBydiffItems(dataMat,user,cosSim,svdEst,N=5,percentage=0.9):
unratedItems=np.nonzero(dataMat[user,:].A==0)[1] #建立一個用戶未評分item的列表,內部元素是有多少件未評分的物品。dataMat,行是user,列是item.
if len(unratedItems)==0:
return [] #如果都已經評過分,則退出
itemScores=[]
for item in unratedItems: #對於每個未評分的item,都計算其預測評分
estimatedScore=svdEst(dataMat,user,cosSim,item,percentage)
itemScores.append((item,estimatedScore))
itemScores=sorted(itemScores,key=lambda x:x[1],reverse=True)#按照item的得分進行從大到小排序
return itemScores[:N] #返回前N大評分值的item名,及其預測評分值
dataMat=loadExData()
SameUserBydiffItems=list()
user=[i for i in range(11)]
for user1 in user: ##給某用戶推薦給top k=5個最相似的未購買的商品。
print(user1)
rec_score=recommendSameUserBydiffItems(dataMat,user1,cosSim,svdEst,N=5,percentage=0.9)
SameUserBydiffItems.append(rec_score)
del rec_score
#將同一物品,推薦給不同的用戶
def recommendSameItemBydiffUsers(dataMat,item,cosSim,svdEst1,N=5,percentage=0.9):
#找出最相似的top k=5個未購買item的用戶,將同一商品推薦給他們
unbuyedUsers=np.nonzero(dataMat.T[item,:].A==0)[1] #建立一個對item這個商品未購買的用戶的用戶列表,內部元素是有未購買item的用戶編號。dataMat.T,行是item,列是user.
if len(unbuyedUsers)==0:
return [] #如果都已經購買過該商品,則退出
userScores=[]
for user1 in unbuyedUsers: #對於未購買item的每個用戶計算其購買的可能性(可能打分)
estimatedScore=svdEst1(dataMat,item,cosSim,user1,percentage)
userScores.append((user1,estimatedScore))
userScores=sorted(userScores,key=lambda x:x[1],reverse=True)#按照item的得分進行從大到小排序
return userScores[:N] #返回前N個相似的user名,以及預測相似度
SameItemBydiffUsers=list()
item=[i for i in range(11)]
for item1 in item: #將某件商品推薦給top k=5個最相似的未購買的用戶。
print(item1)
rec_score=recommendSameItemBydiffUsers(dataMat,item1,cosSim,svdEst1,N=5,percentage=0.9)
SameItemBydiffUsers.append(rec_score)
del rec_score