Cosa c'è di sbagliato in questa funzione python di & # 8220; Programmazione dell'intelligenza collettiva & # 8221 ;?
Domanda
Questa è la funzione in questione. Calcola il coefficiente di correlazione di Pearson per p1 e p2, che dovrebbe essere un numero compreso tra -1 e 1.
Quando lo utilizzo con dati utente reali, a volte restituisce un numero maggiore di 1, come in questo esempio:
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
Soluzione
Sembra che tu stia utilizzando inaspettatamente la divisione dei numeri interi. Ho apportato la seguente modifica e la tua funzione ha restituito 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))
Vedi PEP 238 per ulteriori informazioni sull'operatore di divisione in Python. Un modo alternativo per correggere il codice sopra è:
from __future__ import division
Altri suggerimenti
Beh, mi ci è voluto un minuto per leggere il codice, ma sembra che se cambi i tuoi dati di input in float funzionerà
La divisione intera la confonde. Funziona se rendi n
un float:
n=float(len(si))
Beh, non sono stato esattamente in grado di trovare ciò che non va nella logica della tua funzione, quindi l'ho semplicemente reimplementata usando la definizione del coefficiente di 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}))
Nota che nel tuo esempio il coefficiente di Pearson è solo 1.0
poiché i vettori (-4/3, 2/3, 2/3) e (-2/3, 1/3, 1 / 3) sono paralleli.