Почему встроенная функция суммы в Python ведет себя так? - PullRequest
0 голосов
/ 06 января 2019

Я пытаюсь написать программу, которая определяет коэффициент корреляции Пирсона со стандартным отклонением популяции в питоне. Я думал, что это будет довольно тривиально, пока я не дошел до той части, где я суммировал (yi - μy) * (xi - μx). Вот мой полный код:

def r(x, y):
    mx, my = sum(x) / len(x), sum(y) / len(y)
    sdx, sdy = (sum([(xi-mx)**2 for xi in x]) / len(x))**0.5, (sum([(yi- 
    my)**2 for yi in y]) / (len(y)))**0.5
    res = ((sum([(xi-mx)*(yi-my) for xi in x for yi in y]))/(len(x)*sdx*sdy))**0.5
    return res

Я заметил, что результат был очень маленьким, поэтому я проверил сумму (xi-mx):

sum([(xi-mx) for xi in x])

, и результат составил -9,769962616701378e-15. Вот значения в списке:

print([(xi-mx) for xi in x])
[3.2699999999999987, 3.0699999999999994, 1.2699999999999987, 1.0699999999999985, 0.9699999999999989, 0.2699999999999987, -0.7300000000000013, -1.7300000000000013, -2.7300000000000013, -4.730000000000001]

Кто-нибудь может объяснить, почему python так странно себя ведет?

Ответы [ 2 ]

0 голосов
/ 06 января 2019
res = (sum([(xi-mx)*(yi-my) for xi in x for yi in y]))/(len(x)*sdx*sdy)

Это не делает то, что вы думаете, что делает. При расчете числителя коэффициента корреляции Пирсона, (xi - mx) * (yi - my) должно быть спарено последовательно. Использование zip должно исправить это.

res = (sum([(xi-mx)*(yi-my) for xi, yi in zip(x, y)]))/(len(x)*sdx*sdy)

Вот что я получаю:

def r(x, y):
    mx, my = sum(x) / len(x), sum(y) / len(y)
    sdx, sdy = (sum([(xi-mx)**2 for xi in x]) / len(x))**0.5, (sum([(yi-
    my)**2 for yi in y]) / (len(y)))**0.5
    res = (sum([(xi-mx)*(yi-my) for xi, yi in zip(x, y)]))/(len(x)*sdx*sdy)
    return res

r(x, y) # 0.6124721937208479

Что на самом деле делает for xi in x for yi in y

>>> x, y = [1, 2, 3], [4, 5, 6]
>>> [(xi, yi) for xi in x for yi in y]
[(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]

Так что повторение продолжается. (Фактически создание списка комбинаций.) Вы можете использовать zip для объединения значений в пары:

>>> [*zip(x, y)]
[(1, 4), (2, 5), (3, 6)]
0 голосов
/ 06 января 2019

Сумма чисел, которые вы показали, на самом деле близка к 0. Почему это странно? Фактически, это должно быть близко к 0. Независимо от значений в x для начала, математически

sum(xi - mean(x) for xi in x) =
sum(xi for xi in x) - sum(mean(x) for xi in x) =
len(x) * mean(x) - len(x) * mean(x) =
0

То, что числовой результат не равен 0, просто из-за ошибок округления с плавающей запятой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...