Я шукаю функцію, яка приймає в якості двох списків і повертає співвідношення Пірсона та значення кореляції.
Я шукаю функцію, яка приймає в якості двох списків і повертає співвідношення Пірсона та значення кореляції.
Відповіді:
Ви можете подивитися 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]
Альтернативою може бути нативна наукова функція від зворотного переходу, яка обчислює:
нахил: нахил лінії регресії
перехоплення: перехоплення лінії регресії
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'
наnum = 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
EDIT : виправлено помилку, на яку вказав коментатор.
sum(x) / len(x)
вас ділиться int, а не floats. Отже 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), а потім генерування сюжетного тепла за допомогою бібліотеки новонароджених.
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