天天看點

【筆記5】用pandas實作矩陣資料格式的推薦算法 (基于物品的協同)

'''

基于物品的協同推薦

矩陣資料

說明:

1.修正的餘弦相似度是一種基于模型的協同過濾算法。我們前面提過,這種算法的優勢之

一是擴充性好,對于大資料量而言,運算速度快、占用記憶體少。

2.使用者的評價标準是不同的,比如喜歡一個歌手時有些人會打4分,有些打5分;不喜歡時

有人會打3分,有些則會隻給1分。修正的餘弦相似度計算時會将使用者對物品的評分減去

使用者所有評分的均值,進而解決這個問題。

import pandas as pd

from io import StringIO

#資料類型一:csv矩陣(使用者-商品)(适用于小資料量)

csv_txt = '''"user","Blues Traveler","Broken Bells","Deadmau5","Norah Jones","Phoenix","Slightly Stoopid","The Strokes","Vampire Weekend"

"Angelica",3.5,2.0,,4.5,5.0,1.5,2.5,2.0

"Bill",2.0,3.5,4.0,,2.0,3.5,,3.0

"Chan",5.0,1.0,1.0,3.0,5,1.0,,

"Dan",3.0,4.0,4.5,,3.0,4.5,4.0,2.0

"Hailey",,4.0,1.0,4.0,,,4.0,1.0

"Jordyn",,4.5,4.0,5.0,5.0,4.5,4.0,4.0

"Sam",5.0,2.0,,3.0,5.0,4.0,5.0,

"Veronica",3.0,,,5.0,4.0,2.5,3.0,'''

csv_txt2 = '''"user","Kacey Musgraves","Imagine Dragons","Daft Punk","Lorde","Fall Out Boy"

"David",,3,5,4,1

"Matt",,3,4,4,1

"Ben",4,3,,3,1

"Chris",4,4,4,3,1

"Tori",5,4,5,,3'''

#根據《data minning guide》第85頁的users2資料

csv_txt3 = '''"user","Taylor Swift","PSY","Whitney Houston"

"Amy",4,3,4

"Ben",5,2,

"Clara",,3.5,4

"Daisy",5,,3'''

df = None

#方式一:加載csv資料

def load_csv_txt():

global df, csv_txt, csv_txt2, csv_txt3

df = pd.read_csv(StringIO(csv_txt3), header=0, index_col="user")

#測試:讀取資料

load_csv_txt()

#=======================================

# 注意:不需要build_xy

# 計算兩個物品相似度

def computeSimilarity(goods1, goods2):

'''根據《data minning guide》第71頁的公式s(i,j)'''

# 每行的使用者評分都減去了該使用者的平均評分

df2 = df[[goods1, goods2]].sub(df.mean(axis=1), axis=0).dropna(axis=0) #黑科技

# 傳回修正的餘弦相似度

return sum(df2[goods1] * df2[goods2]) / (sum(df2[goods1]**2) * sum(df2[goods2]**2))**0.5

# csv_txt

#print('\n測試:計算Blues Traveler與Broken Bells的相似度')

#print(computeSimilarity("Blues Traveler","Broken Bells"))

# csv_txt2

#print('\n測試:計算Kacey Musgraves與Imagine Dragons的相似度')

#print(computeSimilarity("Kacey Musgraves","Imagine Dragons"))

# 計算給定使用者對物品的可能評分

def p(user, goods):

'''根據《data minning guide》第75頁的公式p(u,i)'''

assert pd.isnull(df.ix[user, goods]) # 必須使用者對給定物品尚未評分

s1 = df.ix[user, df.ix[user].notnull()] #使用者對已打分物品的打分資料

s2 = s1.index.to_series().apply(lambda x:computeSimilarity(x, goods)) #打分物品分别與給定物品的相似度

return sum(s1 * s2) / sum(abs(s2))

#print('\n測試:計算David對Kacey Musgraves的可能打分')

#print(p("David","Kacey Musgraves"))

#為了讓公式的計算效果更佳,對物品的評價分值最好介于-1和1之間

def rate2newrate(rate):

'''根據《data minning guide》第76頁的公式NR(u,N)'''

ma, mi = df.max().max(), df.min().min()

return (2*(rate - mi) - (ma - mi))/(ma - mi)

#已知rate2newrate求newrate2rate

def newrate2rate(new_rate):

'''根據《data minning guide》第76頁的公式R(u,N)'''

return (0.5 * (new_rate + 1) * (ma - mi)) + mi

print('\n測試:計算3的new_rate值')

print(rate2newrate(3))

print('\n測試:計算0.5的rate值')

print(newrate2rate(0.5))

# 計算給定使用者對物品的可能評分(對評分進行了修正/還原)

def p2(user, goods):

s1 = s1.apply(lambda x:rate2newrate(x)) #修正

s2 = s1.index.to_series().apply(lambda x:computeSimilarity(x, goods)) #已打分物品分别與給定物品的相似度

return newrate2rate(sum(s1 * s2) / sum(abs(s2)))#還原

#print('\n測試:計算David對Kacey Musgraves的可能打分(修正)')

#print(p2("David","Kacey Musgraves"))

#==================================

# 下面是Slope One算法

#

# 兩個步驟:

# 1. 計算內插補點

# 2. 預測使用者對尚未評分物品的評分

# 1.計算兩物品之間的差異

def dev(goods1, goods2):

'''根據《data minning guide》第80頁的公式dev(i,j)'''

s = (df[goods1] - df[goods2]).dropna()

d = sum(s) / s.size

return d, s.size #傳回差異值,及權值(同時對兩個物品打分的人數)

#print('\n測試:計算Kacey Musgraves與Imagine Dragons的分數差異')

#print(dev("Kacey Musgraves","Imagine Dragons"))

#計算所有兩兩物品之間的評分差異,得到方陣pd.DataFrame(行對列)

def get_dev_table():

'''根據《data minning guide》第87頁的表'''

goods_names = df.columns.tolist()

df2 = pd.DataFrame(.0, index=goods_names, columns=goods_names) #零方陣

for i,goods1 in enumerate(goods_names):

for goods2 in goods_names[i+1:]:

d, _ = dev(goods1, goods2) # 注意:隻取了物品差異值

df2.ix[goods1, goods2] = d

df2.ix[goods2, goods1] = -d # 對稱的位置取反

return df2

print('\n測試:計算所有兩兩物品之間的評分差異表')

print(get_dev_table())

#預測某使用者對給定物品的評分

# 權重Slope One算法

def slopeone(user, goods):

'''根據《data minning guide》第82頁的公式p(u,j)'''

s1 = df.ix[user].dropna() #使用者對已打分物品的打分資料

s2 = s1.index.to_series().apply(lambda x:dev(goods, x)) #待打分物品與已打分物品的差異值及權值

s3 = s2.apply(lambda x:x[0]) #差異值

s4 = s2.apply(lambda x:x[1]) #權值

#print(s1, s3, s4)

return sum((s1 + s3) * s4)/sum(s4)

print('\n測試:預測使用者Ben對物品Whitney Houston的評分')

print(slopeone('Ben', 'Whitney Houston')) # 3.375

本文轉自羅兵部落格園部落格,原文連結:http://www.cnblogs.com/hhh5460/p/6121918.html,如需轉載請自行聯系原作者