#準備工作,調(diào)入相關(guān)的庫
import numpyas np
from numpyimport linalgas la
import pandasas pd
#第1部分:加載測試數(shù)據(jù)集,形成loadExData()函數(shù)。
#用戶-物品矩陣行代表用戶user,列代表物品item,其中的值代表用戶對物品的打分。該矩陣存放在評分.csv文件中,使用前需要加載。由movie數(shù)據(jù)集生成該評分.csv的具體實現(xiàn)見6.9節(jié)。
#行:代表用戶
#列:代表電影
#值:代表用戶對電影的評分,0表示未評分
#記載數(shù)據(jù)集
def loadExData():
return np.array(pd.read_csv("評分.csv",sep=",",header=None))
#第2部分:計算相似度,形成ecludSim()函數(shù)、pearsSim()函數(shù)、cosSim()函數(shù)。
'''
以下是三種計算相似度的算法,分別是歐式距離、皮爾遜相關(guān)系數(shù)和余弦相似度
注意三種計算方式的參數(shù)X和Y都是采用一維數(shù)組。
'''
# 利用歐式距離計算相似度 0~1之間
def ecludSim(X, Y):
return 1.0 / (1.0 + la.norm(X - Y))# linalg.norm()是向量A的模(2階范數(shù))計算方法,
#1/(1+ norm)表示將相似度歸一到0與1之間。
# 利用皮爾遜相關(guān)系數(shù)計算相似度 0~1之間
def pearsSim(X, Y):
if len(X) <3:return 1.0
? ? return 0.5 +0.5 * np.corrcoef(X, Y,rowvar=1)[0][1]
# corrcoef()表示皮爾遜相關(guān)系數(shù)的計算方法
#corrcoef() 在 -1 ~ 1之間,0.5 + 0.5*corrcoef()把其取值范圍歸一化到0到1之間。
#利用余弦相似度計算相似度0~1之間
def cosSim(X, Y):
XY =float(X.dot(Y))# 向量 X*Y
? ? XYnorm= la.norm(X) * la.norm(Y)#向量A的模(2階范數(shù)) * 向量B的模(2階范數(shù))
? ? return 0.5 +0.5 * (XY / XYnorm)#向量A 與 向量B 的夾角余弦 A*B / (||A||*||B||)
#范圍在-1~1 ,將相似度歸一到0與1之間。
#第3部分:對矩陣降維處理,形成svd_item()函數(shù)。
#本部分首先確定要選取的奇異值個數(shù),然后進行降維計算矩陣的近似值。
#1.計算選取的奇異值數(shù)目k值,形成SigmaPct函數(shù)。
'''
按照前k個奇異值的平方和占總奇異值的平方和的百分比percentage確定k的值。
后續(xù)計算SVD時需要將item原始矩陣降維
'''
def SigmaPct(sigma, percentage):
sum_sigma =sum(sigma **2)
sum_sigma1 = sum_sigma * percentage# 求所有奇異值sigma的平方和的百分比
? ? sum_sigma2 =0? # sum_sigma2是前k個奇異值的平方和
? ? k =0? # 計數(shù)
? ? for iin sigma:
sum_sigma2 += i **2? # 計算每個奇異值的平方
? ? ? ? k +=1? # 計數(shù)增加1
? ? ? ? if sum_sigma2 >= sum_sigma1:# 判斷是否已達到percentage
? ? ? ? ? ? return k
#2.降維處理,形成svd_item()函數(shù)。
#(1)調(diào)用SigmaPct()函數(shù),確定k值。
#(2)利用 ,求出降維后的 。
# 返回降維的物品數(shù)據(jù)
def svd_item(data, percentage):
n = np.shape(data)[1]# 物品種類數(shù)據(jù)
? ? U, s, VT = la.svd(data)# 數(shù)據(jù)集進行奇異值分解,返回的s為對角線上的值
? ? k = SigmaPct(s, percentage)# 確定了k的值,前k個已經(jīng)包含了percentage的能力
? ? Sigma = np.eye(k) * s[:k]# 構(gòu)建對角矩陣
# 將數(shù)據(jù)轉(zhuǎn)換到k維空間(低維),構(gòu)建轉(zhuǎn)換后的物品
? ? FormedItems = data.T.dot(U[:, :k].dot(la.inv(Sigma)))
return FormedItems# 返回降維的物品數(shù)據(jù)
#第4部分:在已經(jīng)降維的數(shù)據(jù)中,對用戶未打分的一個物品進行評分預(yù)測,形成svd_predict()函數(shù)。
'''
參數(shù)包含:數(shù)據(jù)矩陣、用戶編號、物品編號和奇異值占比的閾值,
數(shù)據(jù)矩陣的行對應(yīng)用戶,列對應(yīng)物品
函數(shù)的作用:基于item的相似性對用戶未評過分的物品進行預(yù)測評分
'''
def svd_predict(data, user, simMeas, FormedItems, item,percentage):
n = np.shape(data)[1]# 得到數(shù)據(jù)集中的物品種類數(shù)據(jù)
? ? Totalsim =0.0? # 初始化兩個評分值
? ? TotalratSim =0.0? # 相似性總和變量初始化
# 遍歷給定的用戶行中的每個物品
# 即(對用戶評過分的物品進行遍歷,并將它與其他物品進行比較),計算相似度
? ? for jin range(n):
# 得到給定的用戶user對商品的評分
? ? ? ? Rating_user = data[user, j]
# 只對評價過的商品和不是自己的商品求相似度
? ? ? ? if Rating_user !=0 and j != item:
# 計算 svd轉(zhuǎn)換過后矩陣的相似度,物品item與物品j之間的相似度
# 相似度的計算方法也會作為一個參數(shù)傳遞給該函數(shù)
? ? ? ? ? ? Similarity = simMeas(FormedItems[item, :], FormedItems[j, :])
Totalsim += Similarity# 對相似度不斷累加求和
? ? ? ? ? ? TotalratSim += Similarity * Rating_user# 對相似度及對應(yīng)評分值乘積求和
? ? if Totalsim ==0:
return 0
? ? else:
return TotalratSim / Totalsim# 得到對物品的預(yù)測評分,返回后用于分數(shù)的排序
#第5部分:產(chǎn)生前N個評分值高的物品,返回物品編號以及預(yù)測評分值,形成recommend()函數(shù)。
'''
函數(shù)recommend()產(chǎn)生預(yù)測評分最高的N個推薦結(jié)果,默認返回5個;
參數(shù)包括:數(shù)據(jù)矩陣、用戶編號、相似度衡量的方法、預(yù)測評分的方法、以及奇異值占比的閾值。
'''
def recommend(data, user, FormedItems, N, simMeas, percentage):
# 為未評價的物品建立一個用戶未評分item的列表
? ? unratedItems = np.array(np.nonzero(data[user, :] ==0))[0]
if len(unratedItems) ==0:
return "你已評價完所有物品"? # 若都已經(jīng)評過分,則退出
? ? Scoresitem = []
for itemin unratedItems:# 對未評分的物品item,都計算其預(yù)測評分
# 計算評價值
? ? ? ? estimatedScore = svd_predict(data, user, simMeas, FormedItems, item, percentage)
Scoresitem.append((item, estimatedScore))# 記錄商品及評價值
? ? Scoresitem =sorted(Scoresitem,key=lambda x: x[1],reverse=True)# 按照得分逆序排序
? ? return Scoresitem[:N]# 返回前N個評分的物品名
#第6部分:對指定用戶進行商品推薦,形成recommend_predict函數(shù)。
def recommend_predict():
user_item = loadExData()
percentage=0.9 #奇異值平方和的百分比
? ? n=4? #推薦個數(shù)
? ? FormedItems = svd_item(user_item, percentage)# 獲得SVD降維后的物品
? ? print('利用余弦相似度計算距離,進行的奇異值分解推薦:')
simMeas=cosSim#相似度
? ? for iin range(0,np.shape(user_item)[0]):
print("對第",i,"個用戶進行推薦:")
print("按相似度推薦的物品編號為:", recommend(user_item, i, FormedItems, n, simMeas, percentage))
print('利用歐式距離相似度計算距離,進行的奇異值分解推薦:')
simMeas = ecludSim
for iin range(0,np.shape(mymat1)[0]):
print("對第",i,"個用戶進行推薦:")
print("按相似度推薦的物品編號為:", recommend(user_item, i, FormedItems, n, simMeas, percentage))
print('利用皮爾遜相似度計算距離,進行的奇異值分解推薦:')
simMeas= pearsSim
for iin range(0,np.shape(mymat1)[0]):
print("對第",i,"個用戶進行推薦:")
print("按相似度推薦的物品編號為:", recommend(user_item, user, FormedItems, n, simMeas, percentage))
#第7部分:調(diào)用recommend_predict()函數(shù),獲得結(jié)果。
#主程序
recommend_predict()
其他文章:協(xié)同過濾