【火爐煉AI】機器學習032-使用者之間相似度的計算
(本文所使用的Python庫和版本號: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )
在構建推薦引擎時,一般需要計算兩個使用者之間的相似度,以便找到與資料庫中特定使用者相似的使用者。計算相似度的方法有很多種,其中比較常見的兩種是計算歐幾里得距離和皮爾遜相關係數,本文分別講述使用這兩種方法來計算使用者之間的相似度。
1. 計算兩個使用者的歐氏距離
歐幾里得距離是歐幾里得空間中兩點間的普通距離,即兩點組成的直線的距離。其計算公式可以說是數學裡的基本公式,如下,其基本含義就是計算兩個點之間的空間距離。
歐式距離很直觀,是常見的一種相似度演算法。其基本思路為:根據兩使用者之間共同評價的專案為維度,建立一個多維空間,使用者對單一維度上的評價就可以組成一個陣列或向量,一旦這個向量確定,那麼就可以確定這個使用者在這個多維空間的位置。但我們把多個使用者都放置到這個多維空間後,距離非常近的兩個使用者,可以認為他們之間的相似度非常高,反之,距離較遠的使用者之間的相似度也較遠,故而這種多維空間內的使用者之間的歐式距離就標定了他們之間的相似度。
但是在日常使用中,我們一般不太習慣數值小反而表示相似度高,故而對這種數值取一個倒數,使得數值都落在0-1之間,即使用 1/(1+Distance(X,Y))之後,得到的相似度範圍為:0<=Similarity(X,y)<=1,越接近1,表示相似度越高,這種表示方式很符合我們的慣性思維。
下面用程式碼來計算兩個使用者之間的歐式距離,其思想是,計算兩個使用者在資料集中的所有專案中的平方和,然後在開方,得到兩個使用者之間的距離,在用倒數法轉變一下。
# 定義一個函式來計算兩個使用者之間的歐式距離
def euclidean_distance(dataset,user1,user2):
# 首先要排除一種情況,如果資料集中不存在同時被兩個使用者評價過的電影,
# 則表示兩個使用者之間的沒有相似度,直接返回0
both_rated_num=0 # 表示同時被兩個使用者都評價過的電影的數目
for item in dataset[user1]: # 在user1評價過的電影中
if item in dataset[user2]: # 如果user2也評價過,則+1
both_rated_num+=1
if both_rated_num==0:# 不存在同時被兩個使用者都評價過的電影
return 0 # 直接返回0,表示兩個使用者之間相似度為0
squared_difference=[] # 每一個元素表示同時被兩個使用者都評價過的電影得分的歐式距離
for item in dataset[user1]:
if item in dataset[user2]:
squared_difference.append(np.square(dataset[user1][item]-dataset[user2][item]))
return 1/(1+np.sqrt(np.sum(squared_difference)))
複製程式碼
由於原始的電影評價資料都存放在movie_ratings.json檔案中,所以需要用json模組載入資料,並對其進行分析
# 原始的電影評價資料都放置在 movie_ratings.json檔案中,我們載入進來看看結果
import json
with open("E:\PyProjects\DataSet\FireAI\movie_ratings.json",'r') as file:
dataset=json.loads(file.read())
# 現在計算兩個隨機使用者之間的歐式距離
user1='John Carson'
user2='Michelle Peterson'
print(" Euclidean score: ",euclidean_distance(dataset,user1,user2))
複製程式碼
---------------------------輸---------出--------------------------------
Euclidean score: 0.29429805508554946
--------------------------------完-------------------------------------
即此處計算出這兩個使用者之間的歐式距離為0.29,相似度不是很高。
歐式距離雖然是比較常用的計算使用者相似度的方法,但是它有其內在的缺點,比如:
1,由於計算時基於各維度特徵的絕對數值,所以歐式距離需要保證各維度指標在相同的刻度級別。
2,歐式距離是資料上的直觀體現,看似簡單,但在處理一些受主觀影響很大的評分資料時,效果則不太明顯。即評價者的評價相對於平均水平偏離很大的時候歐式距離不能很好地揭示出真實的相似度。
2. 計算兩個使用者的皮爾遜相關係數
在統計學中,皮爾遜相關係數用於度量兩個變數之間的線性相關性,其值位於-1到1之間。相關係數為1時,成為完全正相關;當相關係數為-1時,成為完全負相關;相關係數的絕對值越大,相關性越強;相關係數越接近於0,相關度越弱。
# 定義一個函式來計算兩個使用者之間的皮爾遜相關係數
def pearson_score(dataset,user1,user2):
# 和上面的函式類似,先排除相似度為0的情況
# both_rated_num=0 # 表示同時被兩個使用者都評價過的電影的數目
# for item in dataset[user1]: # 在user1評價過的電影中
# if item in dataset[user2]: # 如果user2也評價過,則+1
# both_rated_num+=1
# if both_rated_num==0:# 不存在同時被兩個使用者都評價過的電影
# return 0 # 直接返回0,表示兩個使用者之間相似度為0
both_rated={}
for item in dataset[user1]:
if item in dataset[user2]:
both_rated[item]=1
num_ratings=len(both_rated)
if num_ratings==0: # 不存在同時被兩個使用者都評價過的電影
return 0
# 計算每個使用者對每個相同電影的評價之和
user1_sum=np.sum([dataset[user1][item] for item in both_rated])
user2_sum=np.sum([dataset[user2][item] for item in both_rated])
# 計算每個使用者對每個相同電影的評價的平方和
user1_squared_sum = np.sum([np.square(dataset[user1][item]) for item in both_rated])
user2_squared_sum = np.sum([np.square(dataset[user2][item]) for item in both_rated])
# 計算兩個使用者的相同電影的乘積
product_sum=np.sum([dataset[user1][item]*dataset[user2][item] for item in both_rated])
# 計算Pearson 相關係數
Sxy = product_sum - (user1_sum * user2_sum / num_ratings)
Sxx = user1_squared_sum - np.square(user1_sum) / num_ratings
Syy = user2_squared_sum - np.square(user2_sum) / num_ratings
if Sxx * Syy == 0:
return 0
return Sxy / np.sqrt(Sxx * Syy)
複製程式碼
同理計算得到兩個使用者的皮爾遜相關係數為: Peason score: 0.396. 相似度不能橫向比較,即不能將Pearson得分和歐式距離進行比較,這樣比較沒有意義,只能用於縱向比較。
########################小**********結###############################
1,使用者之間的相似度計算可以採用歐式距離的方式計算,也可以採用皮爾遜相關係數來計算。
2,貌似用皮爾遜相關係數來表示相似度更好一些,在很多時候能夠克服歐式距離表示法的一些缺點。
#################################################################
注:本部分程式碼已經全部上傳到(我的github)上,歡迎下載。
參考資料:
1, Python機器學習經典例項,Prateek Joshi著,陶俊傑,陳小莉譯