Что не так с алгоритмом Пирсона из «Программирование коллективного разума»?

Эта функция из книги «Программирование коллективного разума» и предназначена для вычисления коэффициента корреляции Пирсона для p1 и p2, который должен быть числом от -1 до 1.

Если два критика оценивают предметы очень одинаково, функция должна вернуть 1 или близкое к 1.

С реальными пользовательскими данными я иногда получаю странные результаты. В следующем примере набор данных Critics2 должен вернуть 1, а не 0.

Кто-нибудь замечает ошибку?

(Это не дубликат Что не так с помощью этой функции Python из «Программирование коллективного разума»)

from __future__ import division
from math import sqrt

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,
        }
}
critics2 = {
    'user1':{
        'item1': 5,
        'item2': 5,
        'item3': 5,
        },
    'user2':{
        'item1': 5,
        'item2': 5,
        'item3': 5,
        }
}
critics3 = {
    'user1':{
        'item1': 1,
        'item2': 3,
        'item3': 5,
        },
    'user2':{
        'item1': 5,
        'item2': 3,
        'item3': 1,
        }
}

print sim_pearson(critics, 'user1', 'user2', )
result: 1.0 (expected)
print sim_pearson(critics2, 'user1', 'user2', )
result: 0 (unexpected)
print sim_pearson(critics3, 'user1', 'user2', )
result: -1 (expected)

person Hobhouse    schedule 22.11.2009    source источник


Ответы (4)


В вашем результате нет ничего плохого. Вы пытаетесь построить линию через 3 точки. Во втором случае у вас есть все три точки с одинаковыми координатами, то есть фактически одна точка. Вы не можете сказать, коррелируют ли эти точки или антикоррелируют, потому что вы можете провести бесконечное количество линий через одну точку (den в вашем коде равно нулю).

person Denis Otkidach    schedule 22.11.2009

Если вы посмотрите корреляцию Пирсона в Википедии, вы увидите, что в формуле используется разница между каждый элемент в серии и среднее значение в серии. Когда все элементы в ряду одинаковы, вы получаете деление на ноль, поэтому ваш расчет терпит неудачу.

Если это яснее, вы можете использовать этот код:

def simplified_sim_pearson(p1, p2):
    n = len(p1)
    assert (n != 0)
    sum1 = sum(p1)
    sum2 = sum(p2)
    m1 = float(sum1) / n
    m2 = float(sum2) / n
    p1mean = [(x - m1) for x in p1]
    p2mean = [(y - m2) for y in p2]
    numerator = sum(x * y for x, y in zip(p1mean, p2mean))
    denominator = math.sqrt(sum(x * x for x in p1mean) * sum(y * y for y in p2mean))
    return numerator / denominator if denominator else 0

def sim_pearson(prefs,p1,p2):
    p1 = prefs[p1]
    p2 = prefs[p2]
    si = set(p1.keys()).intersection(set(p2.keys()))
    p1_x = [p1[k] for k in sorted(si)]
    p2_x = [p2[k] for k in sorted(si)]
    return simplified_sim_pearson(p1_x, p2_x)



critics = {
    'user1':{
        'item1': 3,
        'item2': 5,
        'item3': 5,
        },
    'user2':{
        'item1': 4,
        'item2': 5,
        'item3': 5,
        }
}
critics2 = {
    'user1':{
        'item1': 5,
        'item2': 5,
        'item3': 5,
        },
    'user2':{
        'item1': 5,
        'item2': 5,
        'item3': 5,
        }
}
critics3 = {
    'user1':{
        'item1': 1,
        'item2': 3,
        'item3': 5,
        },
    'user2':{
        'item1': 5,
        'item2': 3,
        'item3': 1,
        }
}

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

Кстати, использование Excel для определения правильного ответа — хороший способ проверить большинство вычислений. В этом случае вы бы использовали correl.

person hughdbrown    schedule 22.11.2009

Алгоритм дает правильный результат. 0 означает, что между ними нет корреляции (или, по крайней мере, вы не можете сказать, исходя из того, что знаете).

Как правило (в зависимости от того, в какой области вы применяете этот алгоритм) вы можете рассматривать все в диапазоне от -0,9 ‹ x ‹ 0,09 как «Нет наблюдаемой корреляции».

person jitter    schedule 22.11.2009

Корреляция не подразумевает причинно-следственной связи. Пришлось сказать. Вам необходимо развить понимание корреляционной статистики. Корреляция может быть между -1 и 1, и значение 0 попадает в этот диапазон и является вполне разумным результатом. Корреляция 0 означает, что между двумя переменными нет статистически значимой связи. Помните, что нельзя делать статистику с менее чем 30 образцами.

person whatnick    schedule 22.11.2009