Я ищу функцию, которая принимает в качестве входных данных два списка и возвращает корреляцию Пирсона и значение корреляции.
Я ищу функцию, которая принимает в качестве входных данных два списка и возвращает корреляцию Пирсона и значение корреляции.
Ответы:
Вы можете взглянуть на scipy.stats
:
from pydoc import help
from scipy.stats.stats import pearsonr
help(pearsonr)
>>>
Help on function pearsonr in module scipy.stats.stats:
pearsonr(x, y)
Calculates a Pearson correlation coefficient and the p-value for testing
non-correlation.
The Pearson correlation coefficient measures the linear relationship
between two datasets. Strictly speaking, Pearson's correlation requires
that each dataset be normally distributed. Like other correlation
coefficients, this one varies between -1 and +1 with 0 implying no
correlation. Correlations of -1 or +1 imply an exact linear
relationship. Positive correlations imply that as x increases, so does
y. Negative correlations imply that as x increases, y decreases.
The p-value roughly indicates the probability of an uncorrelated system
producing datasets that have a Pearson correlation at least as extreme
as the one computed from these datasets. The p-values are not entirely
reliable but are probably reasonable for datasets larger than 500 or so.
Parameters
----------
x : 1D array
y : 1D array the same length as x
Returns
-------
(Pearson's correlation coefficient,
2-tailed p-value)
References
----------
http://www.statsoft.com/textbook/glosp.html#Pearson%20Correlation
Корреляция Пирсона может быть рассчитана с помощью числа Нумпи corrcoef
.
import numpy
numpy.corrcoef(list1, list2)[0, 1]
Альтернативой может быть встроенная функция scipy из linregress, которая вычисляет:
наклон: наклон линии регрессии
Перехват: перехват линии регрессии
r-значение: коэффициент корреляции
p-значение: двустороннее p-значение для проверки гипотезы, нулевая гипотеза которой состоит в том, что наклон равен нулю
stderr: стандартная ошибка оценки
И вот пример:
a = [15, 12, 8, 8, 7, 7, 7, 6, 5, 3]
b = [10, 25, 17, 11, 13, 17, 20, 13, 9, 15]
from scipy.stats import linregress
linregress(a, b)
вернет вам:
LinregressResult(slope=0.20833333333333337, intercept=13.375, rvalue=0.14499815458068521, pvalue=0.68940144811669501, stderr=0.50261704627083648)
lineregress(two_row_df)
Если вы не хотите устанавливать scipy, я воспользовался этим быстрым взломом, немного измененным из « Программирование Коллективного Разума» :
(Отредактировано для корректности.)
from itertools import imap
def pearsonr(x, y):
# Assume len(x) == len(y)
n = len(x)
sum_x = float(sum(x))
sum_y = float(sum(y))
sum_x_sq = sum(map(lambda x: pow(x, 2), x))
sum_y_sq = sum(map(lambda x: pow(x, 2), y))
psum = sum(imap(lambda x, y: x * y, x, y))
num = psum - (sum_x * sum_y/n)
den = pow((sum_x_sq - pow(sum_x, 2) / n) * (sum_y_sq - pow(sum_y, 2) / n), 0.5)
if den == 0: return 0
return num / den
TypeError: unsupported operand type(s) for -: 'itertools.imap' and 'float'
atnum = psum - (sum_x * sum_y/n)
Следующий код является простой интерпретацией определения :
import math
def average(x):
assert len(x) > 0
return float(sum(x)) / len(x)
def pearson_def(x, y):
assert len(x) == len(y)
n = len(x)
assert n > 0
avg_x = average(x)
avg_y = average(y)
diffprod = 0
xdiff2 = 0
ydiff2 = 0
for idx in range(n):
xdiff = x[idx] - avg_x
ydiff = y[idx] - avg_y
diffprod += xdiff * ydiff
xdiff2 += xdiff * xdiff
ydiff2 += ydiff * ydiff
return diffprod / math.sqrt(xdiff2 * ydiff2)
Тест:
print pearson_def([1,2,3], [1,5,7])
возвращается
0.981980506062
Это согласуется с Excel, этот калькулятор , SciPy (также NumPy ), который возвращает 0,981980506 и 0,9819805060619657 и 0,98198050606196574 соответственно.
R :
> cor( c(1,2,3), c(1,5,7))
[1] 0.9819805
РЕДАКТИРОВАТЬ : Исправлена ошибка, указанная комментатором.
sum(x) / len(x)
вас делят целые, а не плавает. Итак sum([1,5,7]) / len([1,5,7]) = 13 / 3 = 4
, согласно целочисленному делению (тогда как вы хотите 13. / 3. = 4.33...
). Чтобы исправить это, перепишите эту строку как float(sum(x)) / float(len(x))
(достаточно одного числа с плавающей запятой, поскольку Python конвертирует его автоматически).
Вы можете сделать это pandas.DataFrame.corr
тоже:
import pandas as pd
a = [[1, 2, 3],
[5, 6, 9],
[5, 6, 11],
[5, 6, 13],
[5, 3, 13]]
df = pd.DataFrame(data=a)
df.corr()
Это дает
0 1 2
0 1.000000 0.745601 0.916579
1 0.745601 1.000000 0.544248
2 0.916579 0.544248 1.000000
Вместо того, чтобы полагаться на numpy / scipy, я думаю, что мой ответ должен быть самым простым для кодирования и понимания шагов по вычислению коэффициента корреляции Пирсона (PCC).
import math
# calculates the mean
def mean(x):
sum = 0.0
for i in x:
sum += i
return sum / len(x)
# calculates the sample standard deviation
def sampleStandardDeviation(x):
sumv = 0.0
for i in x:
sumv += (i - mean(x))**2
return math.sqrt(sumv/(len(x)-1))
# calculates the PCC using both the 2 functions above
def pearson(x,y):
scorex = []
scorey = []
for i in x:
scorex.append((i - mean(x))/sampleStandardDeviation(x))
for j in y:
scorey.append((j - mean(y))/sampleStandardDeviation(y))
# multiplies both lists together into 1 list (hence zip) and sums the whole list
return (sum([i*j for i,j in zip(scorex,scorey)]))/(len(x)-1)
Значение ОКК в основном , чтобы показать вам , как сильно коррелируют две переменные / списки. Важно отметить, что значение PCC составляет от -1 до 1 . Значение от 0 до 1 обозначает положительную корреляцию. Значение 0 = наибольшее отклонение (без какой-либо корреляции). Значение от -1 до 0 обозначает отрицательную корреляцию.
sum
функция.
Расчет коэффициента Пирсона с использованием панд в python: я бы предложил попробовать этот подход, поскольку ваши данные содержат списки. Будет легко взаимодействовать с вашими данными и манипулировать ими из консоли, поскольку вы сможете визуализировать свою структуру данных и обновлять ее по своему желанию. Вы также можете экспортировать набор данных, сохранить его и добавить новые данные из консоли Python для последующего анализа. Этот код проще и содержит меньше строк кода. Я предполагаю, что вам нужно несколько быстрых строк кода для проверки ваших данных для дальнейшего анализа
Пример:
data = {'list 1':[2,4,6,8],'list 2':[4,16,36,64]}
import pandas as pd #To Convert your lists to pandas data frames convert your lists into pandas dataframes
df = pd.DataFrame(data, columns = ['list 1','list 2'])
from scipy import stats # For in-built method to get PCC
pearson_coef, p_value = stats.pearsonr(df["list 1"], df["list 2"]) #define the columns to perform calculations on
print("Pearson Correlation Coefficient: ", pearson_coef, "and a P-value of:", p_value) # Results
Тем не менее, вы не опубликовали свои данные для меня, чтобы увидеть размер набора данных или преобразования, которые могут потребоваться перед анализом.
Хм, многие из этих ответов имеют длинный и трудный для чтения код ...
Я бы предложил использовать Numpy с его отличными функциями при работе с массивами:
import numpy as np
def pcc(X, Y):
''' Compute Pearson Correlation Coefficient. '''
# Normalise X and Y
X -= X.mean(0)
Y -= Y.mean(0)
# Standardise X and Y
X /= X.std(0)
Y /= Y.std(0)
# Compute mean product
return np.mean(X*Y)
# Using it on a random example
from random import random
X = np.array([random() for x in xrange(100)])
Y = np.array([random() for x in xrange(100)])
pcc(X, Y)
Это реализация корреляционной функции Пирсона с использованием numpy:
def corr(data1, data2):
"data1 & data2 should be numpy arrays."
mean1 = data1.mean()
mean2 = data2.mean()
std1 = data1.std()
std2 = data2.std()
# corr = ((data1-mean1)*(data2-mean2)).mean()/(std1*std2)
corr = ((data1*data2).mean()-mean1*mean2)/(std1*std2)
return corr
Вот вариант ответа mkh, который работает намного быстрее, и scipy.stats.pearsonr, используя numba.
import numba
@numba.jit
def corr(data1, data2):
M = data1.size
sum1 = 0.
sum2 = 0.
for i in range(M):
sum1 += data1[i]
sum2 += data2[i]
mean1 = sum1 / M
mean2 = sum2 / M
var_sum1 = 0.
var_sum2 = 0.
cross_sum = 0.
for i in range(M):
var_sum1 += (data1[i] - mean1) ** 2
var_sum2 += (data2[i] - mean2) ** 2
cross_sum += (data1[i] * data2[i])
std1 = (var_sum1 / M) ** .5
std2 = (var_sum2 / M) ** .5
cross_mean = cross_sum / M
return (cross_mean - mean1 * mean2) / (std1 * std2)
Вот реализация корреляции Пирсона на основе разреженного вектора. Векторы здесь выражены в виде списка кортежей, выраженного как (индекс, значение). Два разреженных вектора могут иметь разную длину, но размер вектора должен быть одинаковым. Это полезно для приложений интеллектуального анализа текста, где размер вектора чрезвычайно велик из-за того, что большинство функций является мешком слов, и, следовательно, вычисления обычно выполняются с использованием разреженных векторов.
def get_pearson_corelation(self, first_feature_vector=[], second_feature_vector=[], length_of_featureset=0):
indexed_feature_dict = {}
if first_feature_vector == [] or second_feature_vector == [] or length_of_featureset == 0:
raise ValueError("Empty feature vectors or zero length of featureset in get_pearson_corelation")
sum_a = sum(value for index, value in first_feature_vector)
sum_b = sum(value for index, value in second_feature_vector)
avg_a = float(sum_a) / length_of_featureset
avg_b = float(sum_b) / length_of_featureset
mean_sq_error_a = sqrt((sum((value - avg_a) ** 2 for index, value in first_feature_vector)) + ((
length_of_featureset - len(first_feature_vector)) * ((0 - avg_a) ** 2)))
mean_sq_error_b = sqrt((sum((value - avg_b) ** 2 for index, value in second_feature_vector)) + ((
length_of_featureset - len(second_feature_vector)) * ((0 - avg_b) ** 2)))
covariance_a_b = 0
#calculate covariance for the sparse vectors
for tuple in first_feature_vector:
if len(tuple) != 2:
raise ValueError("Invalid feature frequency tuple in featureVector: %s") % (tuple,)
indexed_feature_dict[tuple[0]] = tuple[1]
count_of_features = 0
for tuple in second_feature_vector:
count_of_features += 1
if len(tuple) != 2:
raise ValueError("Invalid feature frequency tuple in featureVector: %s") % (tuple,)
if tuple[0] in indexed_feature_dict:
covariance_a_b += ((indexed_feature_dict[tuple[0]] - avg_a) * (tuple[1] - avg_b))
del (indexed_feature_dict[tuple[0]])
else:
covariance_a_b += (0 - avg_a) * (tuple[1] - avg_b)
for index in indexed_feature_dict:
count_of_features += 1
covariance_a_b += (indexed_feature_dict[index] - avg_a) * (0 - avg_b)
#adjust covariance with rest of vector with 0 value
covariance_a_b += (length_of_featureset - count_of_features) * -avg_a * -avg_b
if mean_sq_error_a == 0 or mean_sq_error_b == 0:
return -1
else:
return float(covariance_a_b) / (mean_sq_error_a * mean_sq_error_b)
Модульные тесты:
def test_get_get_pearson_corelation(self):
vector_a = [(1, 1), (2, 2), (3, 3)]
vector_b = [(1, 1), (2, 5), (3, 7)]
self.assertAlmostEquals(self.sim_calculator.get_pearson_corelation(vector_a, vector_b, 3), 0.981980506062, 3, None, None)
vector_a = [(1, 1), (2, 2), (3, 3)]
vector_b = [(1, 1), (2, 5), (3, 7), (4, 14)]
self.assertAlmostEquals(self.sim_calculator.get_pearson_corelation(vector_a, vector_b, 5), -0.0137089240555, 3, None, None)
У меня есть очень простое и понятное решение для этого. Для двух массивов одинаковой длины коэффициент Пирсона можно легко вычислить следующим образом:
def manual_pearson(a,b):
"""
Accepts two arrays of equal length, and computes correlation coefficient.
Numerator is the sum of product of (a - a_avg) and (b - b_avg),
while denominator is the product of a_std and b_std multiplied by
length of array.
"""
a_avg, b_avg = np.average(a), np.average(b)
a_stdev, b_stdev = np.std(a), np.std(b)
n = len(a)
denominator = a_stdev * b_stdev * n
numerator = np.sum(np.multiply(a-a_avg, b-b_avg))
p_coef = numerator/denominator
return p_coef
Вы можете задаться вопросом, как интерпретировать свою вероятность в контексте поиска корреляции в определенном направлении (отрицательная или положительная корреляция). Вот функция, которую я написал, чтобы помочь с этим. Это может быть даже правильно!
Он основан на информации, которую я почерпнул из http://www.vassarstats.net/rsig.html и http://en.wikipedia.org/wiki/Student%27s_t_distribution , благодаря другим ответам, размещенным здесь.
# Given (possibly random) variables, X and Y, and a correlation direction,
# returns:
# (r, p),
# where r is the Pearson correlation coefficient, and p is the probability
# that there is no correlation in the given direction.
#
# direction:
# if positive, p is the probability that there is no positive correlation in
# the population sampled by X and Y
# if negative, p is the probability that there is no negative correlation
# if 0, p is the probability that there is no correlation in either direction
def probabilityNotCorrelated(X, Y, direction=0):
x = len(X)
if x != len(Y):
raise ValueError("variables not same len: " + str(x) + ", and " + \
str(len(Y)))
if x < 6:
raise ValueError("must have at least 6 samples, but have " + str(x))
(corr, prb_2_tail) = stats.pearsonr(X, Y)
if not direction:
return (corr, prb_2_tail)
prb_1_tail = prb_2_tail / 2
if corr * direction > 0:
return (corr, prb_1_tail)
return (corr, 1 - prb_1_tail)
Вы можете взглянуть на эту статью. Это хорошо документированный пример расчета корреляции на основе исторических данных валютных пар форекс из нескольких файлов с использованием библиотеки панд (для Python), а затем создания графика тепловой карты с использованием библиотеки Seaborn.
http://www.tradinggeeks.net/2015/08/calculating-correlation-in-python/
def pearson(x,y):
n=len(x)
vals=range(n)
sumx=sum([float(x[i]) for i in vals])
sumy=sum([float(y[i]) for i in vals])
sumxSq=sum([x[i]**2.0 for i in vals])
sumySq=sum([y[i]**2.0 for i in vals])
pSum=sum([x[i]*y[i] for i in vals])
# Calculating Pearson correlation
num=pSum-(sumx*sumy/n)
den=((sumxSq-pow(sumx,2)/n)*(sumySq-pow(sumy,2)/n))**.5
if den==0: return 0
r=num/den
return r