def loadExData(): return[[1,1,1,0,0], [2,2,2,0,0], [1,1,1,0,0], [5,5,5,0,0], [1,1,0,2,2], [0,0,0,3,3], [0,0,0,1,1]] def loadExData2(): return[[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]] from numpy import * from numpy import linalg as la #歐氏距離 def euclidSim(inA,inB): return 1.0/(1.0+la.norm(inA-inB)) #皮爾遜相關系數 def pearsSim(inA,inB): if len(inA)<3:return 1.0 return 0.5+0.5*corrcoef(inA,inB,rowvar=0)[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) #基於物品相似度的推薦引擎(標准相似度計算方法下的用戶估計值 ) def standEst(dataMat,user,simMeas,item): #商品數目 n=shape(dataMat)[1] #兩個用於計算估計評分值的變量 simTotal=0.0;ratSimTotal=0.0 #遍歷所有商品,並將它與所有的物品進行比較 for j in range(n): #用戶對某個物品的評分 userRating=dataMat[user,j] if userRating==0:continue # logical_and:矩陣逐個元素運行邏輯與,返回值為每個元素的True,False # dataMat[:,item].A>0: 第item列中大於0的元素 # dataMat[:,j].A: 第j列中大於0的元素 # overLap: dataMat[:,item],dataMat[:,j]中同時都大於0的那個元素的行下標(一個向量) overLap=nonzero(logical_and(dataMat[:,item].A>0,\ dataMat[:,j].A>0))[0] print(j) print("------overLap------") print(overLap) if len(overLap)==0:similarity=0 # 計算overLap矩陣的相似度 else: similarity=simMeas(dataMat[overLap,item],\ dataMat[overLap,j]) print("dataMat[overLap,item:") print(dataMat[overLap,item]) print("dataMat[overLap,j:") print(dataMat[overLap,j]) print ('the %d and %d similarity is:%f' % (item,j,similarity)) # 累計總相似度(不太理解) # 假設A評分未知,A,B相似度0.9,B評分5,;A C相似度0.8,C評分4. # 那么按照公式A評分=(0.9*5+0.8*4)/(0.9+0.8) # 相當於加權平均(如果除以2),但是因為2個評分的權重是不一樣的,所以應除以相似度之和 simTotal+=similarity # ratSimTotal = 相似度*元素值 ratSimTotal+=similarity*userRating print("ratSimTotal+=similarity*userRating:") print(ratSimTotal) if simTotal==0:return 0 else:return ratSimTotal/simTotal #對某個用戶產生最高的N個推薦結果 #user 表示要推薦的用戶編號 def recommend(dataMat,user,N=3,simMeas=cosSim,estMethod=standEst): #對給定用戶建立一個未評分的物品矩陣 unratedItems=nonzero(dataMat[user,:].A==0)[1] #第user行中等於0的元素 # print(dataMat[user,:].A==0)----[[ True True True ..., True False True]] # 對於二維數組b2,nonzero(b2)所得到的是一個長度為2的元組。它的第0個元素是數組a中值不為0的元素的第0軸的下標,第1個元素則是第1軸的下標,因此從下面的結果可知b2[0,0]、b[0,2]和b2[1,0]的值不為0: # #>>> b2 = np.array([[True, False, True], [True, False, False]]) #>>> np.nonzero(b2) #(array([0, 0, 1], dtype=int64), array([0, 2, 0], dtype=int64)) if len(unratedItems)==0:return 'you rated everything' #給未評分物品存放預測得分的列表 itemScores=[] for item in unratedItems: #對每個未評分物品通過standEst()方法來預測得分 print("item------------") print(item) estimatedScore=estMethod(dataMat,user,simMeas,item) #將物品編號和估計得分存放在列表中 itemScores.append((item,estimatedScore)) #sorted排序函數,key 是按照關鍵字排序,lambda是隱函數,固定寫法, #jj表示待排序元祖,jj[1]按照jj的第二列排序,reverse=True,降序;[:N]前N個 return sorted(itemScores,key=lambda jj:jj[1],reverse=True)[:N] #利用SVD提高推薦效果 #基於SVD的評分估計 def svdEst(dataMat,user,simMeas,item): #商品數目 n=shape(dataMat)[1] simTotal=0.0;ratSimTotal=0.0 #SVD分解為:U*S*V U,Sigma,VT=la.svd(dataMat) #分解后只利用90%能量的奇異值,存放在numpy數組里面 Sig4=mat(eye(4)*Sigma[:4]) #利用U矩陣將物品轉換到低維空間中 xformeditems=dataMat.T*U[:,:4]*Sig4.I for j in range(n): userRating=dataMat[user,j] if userRating==0 or j==item:continue similarity=simMeas(xformeditems[item,:].T,\ xformeditems[j,:].T) print ('the %d and %d similarity is :%f' % (item,j,similarity)) simTotal+=similarity ratSimTotal+=similarity*userRating if simTotal==0:return 0 else: return ratSimTotal/simTotal if __name__ == '__main__': myMat=mat(loadExData2()) print(recommend(myMat,2))