遷移到:http://www.bdata-cap.com/newsinfo/1741432.html
推薦算法以及數據挖掘算法,計算「距離」是必須的~最近想搭一個推薦系統,看了一些資料和書《寫給程序員的數據挖掘指南》,此書不錯,推薦你們看看,講解得很透徹,有理論有代碼,還有相關網站。看完後,你馬上就能把推薦算法應用在你的項目中~html
本文先主要說明如何計算物品或用戶之間的「距離」,陸續會介紹推薦算法自己~程序員
大致上,推薦算法能夠有兩種簡單的思路:一是類似的用戶,二是類似的物品。算法
前者,把與你類似的用戶喜歡(或購買或評價高)的商品推薦給你,也就是說,若是你跟某個用戶的喜愛比較接近,那麼就能夠把這個用戶喜歡的,而你不知道(或沒瀏覽過,或沒購買過等等)的物品推薦給你。什麼叫「喜愛接近」,就是對某些物品的評價也好,購買也罷,都比較接近,就認爲,你和他喜愛相同~app
前者的缺陷在於,用戶的評價畢竟是少數,想一想,你評價過(顯式評價)的物品有多少!大多數仍是隱式評價,所謂隱式評價,若是你購買一個物品,那顯然你會喜歡他,否則也不會買~所以,利用類似的用戶是有侷限性的。不如利用類似的物品來推薦。ide
下面「距離」算法主要針對計算用戶之間的距離(類似性)。oop
假設,8個用戶對8個樂隊進行評分,以下表所示。橫向是用戶,縱向是樂隊。網站
表 1 用戶評分表idea
計算距離最簡單的方法是曼哈頓距離。假設,先考慮二維狀況,只有兩個樂隊 x 和 y,用戶A的評價爲(x1,y1),用戶B的評價爲(x2,y2),那麼,它們之間的曼哈頓距離爲spa
所以,Angelica 與 Bill 之間的曼哈頓距離以下表所示。3d
表 2 Angelica 與 Bill 的曼哈頓距離
那麼,Angelica 與 Bill 之間的曼哈頓距離爲 9,即第二列減第三列的絕對值,最後累加。
注意,必須是這兩個用戶都評分的樂隊。
能夠推廣到n個樂隊,即n維向量,用戶 A(x1,x2,…,xn),用戶B(y1,y2,…,yn) ,那麼它們之間的曼哈頓距離爲
則用戶之間的曼哈頓距離以下表所示。
表 3 用戶之間的曼哈頓距離
曼哈頓距離的最大好處就是簡單,只是加減法而已。若是有幾百萬個用戶,計算起來會很快。
不只能夠擴展到 n 個樂隊,固然也能夠擴展到 m 個用戶,它們能夠造成一個矩陣。下面的其餘距離同理。
Netflix 當初出 100 萬美圓獎勵給能提高推薦算法 10% 準確率的團隊或人,而贏得獎金的人就是使用了一種叫奇異矩陣分解的方法~
除了曼哈頓距離外,還能夠計算兩個用戶之間的歐式距離。
仍是先考慮兩個樂隊 x 和 y 的狀況,假設,用戶A=(x1,y1),用戶B=(x2,y2),那麼它們之間的歐式距離:
Angelica 與 Bill 之間的曼哈頓距離以下表所示。
表 4 Angelica 與 Bill 的歐式距離
推廣到 n 個樂隊,用戶 A(x1,x2,…,xn),用戶B(y1,y2,…,yn)
表 5 用戶之間的歐式距離
但曼哈頓距離和歐式距離,有個缺點。對比一下 Hailey 與 Veronica 和 Jordyn,Hailey 與前者只有兩個樂隊評過度,而與後者是五個。換句話說,Hailey 與 Veronica 的距離是基於二維的,而 Hailey 與 Jordyn 是基於五維。想一想都以爲有問題。
因此,曼哈頓距離和歐式距離適合數據比較稠密、缺失值比較少的狀況。若是缺失值不少,餘弦類似度就比較合適。
曼哈頓距離和歐式距離,有通用公式,稱爲閔可夫斯基距離(Minkowski Distance)。
假設,有兩個樂隊,用戶A=(x1,y1),用戶B=(x2,y2),那麼他們之間的餘弦相識度爲:
表 6 Angelica 與 Bill 的餘弦類似度
推廣到n維,用戶A和B,對n個樂隊的評分分別爲(x1,x2,...,xn)和(y1,y2,...,yn),則他們之間的餘弦類似度爲
#
# dis.py
#
from math import *
teams = [
"Blues Traveler",
"Broken Bells",
"Deadmau5",
"Norah Jones",
"Phoenix",
"Slightly Stoopid",
"The Strokes",
"Vampire Weekend"
]
users = {
"Angelica": {
"Blues Traveler": 3.5,
"Broken Bells": 2,
"Norah Jones": 4.5,
"Phoenix": 5,
"Slightly Stoopid": 1.5,
"The Strokes": 2.5,
"Vampire Weekend": 2
},
"Bill": {
"Blues Traveler": 2,
"Broken Bells": 3.5,
"Deadmau5": 4,
"Phoenix": 2,
"Slightly Stoopid": 3.5,
"Vampire Weekend": 3
},
"Chan": {
"Blues Traveler": 5,
"Broken Bells": 1,
"Deadmau5": 1,
"Norah Jones": 3,
"Phoenix": 5,
"Slightly Stoopid": 1
},
"Dan": {
"Blues Traveler": 3,
"Broken Bells": 4,
"Deadmau5": 4.5,
"Phoenix": 3,
"Slightly Stoopid": 4.5,
"The Strokes": 4,
"Vampire Weekend": 2
},
"Hailey": {
"Broken Bells": 4,
"Deadmau5": 1,
"Norah Jones": 4,
"The Strokes": 4,
"Vampire Weekend": 1
},
"Jordyn": {
"Broken Bells": 4.5,
"Deadmau5": 4,
"Norah Jones": 5,
"Phoenix": 5,
"Slightly Stoopid": 4.5,
"The Strokes": 4,
"Vampire Weekend": 4
},
"Sam": {
"Blues Traveler": 5,
"Broken Bells": 2,
"Norah Jones": 3,
"Phoenix": 5,
"Slightly Stoopid": 4,
"The Strokes": 5
},
"Veronica": {
"Blues Traveler": 3,
"Norah Jones": 5,
"Phoenix": 4,
"Slightly Stoopid": 2.5,
"The Strokes": 3
}
}
def manhattan(rating1, rating2):
"""Computes the Manhattan distance. Both rating1 and rating2 are dictionaries
of the form {'The Strokes': 3.0, 'Slightly Stoopid': 2.5}"""
distance = 0
commonRatings = False
for key in rating1:
if key in rating2:
distance += abs(rating1[key] - rating2[key])
commonRatings = True
if commonRatings:
return distance
else:
return -1 #Indicates no ratings in common
def euclidean(rating1, rating2):
"""Computes the euclidean distance. Both rating1 and rating2 are dictionaries
of the form {'The Strokes': 3.0, 'Slightly Stoopid': 2.5}"""
distance = 0
commonRatings = False
for key in rating1:
if key in rating2:
distance += pow(rating1[key] - rating2[key],2)
commonRatings = True
if commonRatings:
return sqrt(distance)
else:
return -1 #Indicates no ratings in common
def minkowski(rating1, rating2, r):
"""Computes the minkowski distance. Both rating1 and rating2 are dictionaries
of the form {'The Strokes': 3.0, 'Slightly Stoopid': 2.5}"""
distance = 0
commonRatings = False
for key in rating1:
if key in rating2:
distance += pow(abs(rating1[key] - rating2[key]),r)
commonRatings = True
if commonRatings:
return pow(distance, 1.0/r)
else:
return -1 #Indicates no ratings in common
def cosineSimilarity (rating1, rating2):
"""Computes the Cosine Similarity distance. Both rating1 and rating2 are dictionaries
of the form {'The Strokes': 3.0, 'Slightly Stoopid': 2.5}"""
sum_xy = 0
sum_sqr_x = 0
sum_sqr_y = 0
for key in teams:
if key in rating1 and key in rating2:
sum_xy += rating1[key]* rating2[key]
sum_sqr_x += pow(rating1[key], 2)
sum_sqr_y += pow(rating2[key], 2)
elif key not in rating1 and key in rating2:
sum_xy += 0
sum_sqr_x += 0
sum_sqr_y += pow(rating2[key], 2)
elif key in rating1 and key not in rating2:
sum_xy += 0
sum_sqr_x += pow(rating1[key], 2)
sum_sqr_y += 0
else:
sum_xy += 0
sum_sqr_x += 0
sum_sqr_y += 0
if sum_sqr_x ==0 or sum_sqr_y==0:
return -1 #Indicates no ratings in common
else:
return sum_xy / (sqrt(sum_sqr_x) * sqrt(sum_sqr_y))
def pearson(rating1, rating2):
"""Computes the pearson distance. Both rating1 and rating2 are dictionaries
of the form {'The Strokes': 3.0, 'Slightly Stoopid': 2.5}"""
sum_xy = 0
sum_x = 0
sum_y = 0
sum_x2 = 0
sum_y2 = 0
n = 0
for key in rating1:
if key in rating2:
n += 1
x = rating1[key]
y = rating2[key]
sum_xy += x * y
sum_x += x
sum_y += y
sum_x2 += pow(x, 2)
sum_y2 += pow(y, 2)
# now compute denominator
denominator = sqrt(sum_x2 - pow(sum_x, 2) / n) * sqrt(sum_y2 - pow(sum_y, 2) / n)
if denominator == 0:
return 0
else:
return (sum_xy - (sum_x * sum_y) / n) / denominator