2009-09-14 55 views
4

這是有問題的功能。它計算p1和p2的Pearson相關係數,它應該是-1和1之間的一個數字。從「編程集體智慧」這個Python函數有什麼問題?

當我將此用於實際用戶數據時,它有時會返回大於1的數字,如本例中:

def sim_pearson(prefs,p1,p2): 
    si={} 
    for item in prefs[p1]: 
     if item in prefs[p2]: si[item]=1 

    if len(si)==0: return 0 

    n=len(si) 

    sum1=sum([prefs[p1][it] for it in si]) 
    sum2=sum([prefs[p2][it] for it in si]) 

    sum1Sq=sum([pow(prefs[p1][it],2) for it in si]) 
    sum2Sq=sum([pow(prefs[p2][it],2) for it in si]) 

    pSum=sum([prefs[p1][it]*prefs[p2][it] for it in si]) 

    num=pSum-(sum1*sum2/n) 
    den=sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n)) 

    if den==0: return 0 

    r=num/den 

    return r 

critics = { 
    'user1':{ 
     'item1': 3, 
     'item2': 5, 
     'item3': 5, 
     }, 

    'user2':{ 
     'item1': 4, 
     'item2': 5, 
     'item3': 5, 
     } 
} 

print sim_pearson(critics, 'user1', 'user2',) 

1.15470053838 
+1

好吧,如果它是關於整數與真正的除法,那麼請注意這個問題已經在Py3k中解決了---'/'總是真正的除法(並且正如你所看到的!)。 – 2009-09-14 20:13:57

回答

8

看起來你可能會意外地使用整數除法。我做了如下的變化和你的函數返回1.0

num=pSum-(1.0*sum1*sum2/n) 
den=sqrt((sum1Sq-1.0*pow(sum1,2)/n)*(sum2Sq-1.0*pow(sum2,2)/n)) 

獲取關於Python的除法運算符更多信息,請參閱PEP 238。修理你上面的代碼的另一種方法是:

from __future__ import division 
2

嗯,我花了一分鐘以上的代碼來讀取,但如果你改變你的數據輸入到似乎彩車將工作

2

整數除法令人困惑。它的工作原理,如果你做n一個float:

n=float(len(si)) 
1

好吧,我不完全能找到什麼錯在你的功能邏輯,所以我只是重新實現它使用Pearson相關係數的定義:

from math import sqrt 

def sim_pearson(p1,p2): 
    keys = set(p1) | set(p2) 
    n = len(keys) 

    a1 = sum(p1[it] for it in keys)/n 
    a2 = sum(p2[it] for it in keys)/n 

# print(a1, a2) 

    sum1Sq = sum((p1[it] - a1) ** 2 for it in keys) 
    sum2Sq = sum((p2[it] - a2) ** 2 for it in keys) 

    num = sum((p1[it] - a1) * (p2[it] - a2) for it in keys) 
    den = sqrt(sum1Sq * sum2Sq) 

# print(sum1Sq, sum2Sq, num, den) 
    return num/den 

critics = { 
    'user1':{ 
     'item1': 3, 
     'item2': 5, 
     'item3': 5, 
     }, 

    'user2':{ 
     'item1': 4, 
     'item2': 5, 
     'item3': 5, 
     } 
} 

assert 0.999 < sim_pearson(critics['user1'], critics['user1']) < 1.0001 

print('Your example:', sim_pearson(critics['user1'], critics['user2'])) 
print('Another example:', sim_pearson({1: 1, 2: 2, 3: 3}, {1: 4, 2: 0, 3: 1})) 

請注意,在您的示例中,皮爾遜係數僅爲1.0,因爲向量(-4/3,2/3,2/3)和(-2/3,1/3,1/3)平行。