Python에서 Pearson 상관 관계 및 의미 계산


답변:


202

당신은 볼 수 있습니다 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

2
두 사전의 상관 계수는 어떻습니까?!
user702846

2
@ user702846 Pearson 상관 관계는 2xN 행렬에 정의됩니다. 두 사전을 2xN 행렬로 변환하는 일반적으로 적용 가능한 방법은 없지만 사전 키 쌍의 교차 키에 해당하는 사전 값 쌍 배열을 사용할 수 있습니다.
winerd


56

대안은 다음 을 계산하는 linregress 의 기본 scipy 함수일 수 있습니다 .

기울기 : 회귀선의 기울기

가로 채기 : 회귀선 가로 채기

r- 값 : 상관 계수

p-value : 귀무 가설이 기울기가 0이라는 가설 검정의 양면 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)

2
훌륭한 답변-가장 유익한 정보. 또한 2 열 팬더와 함께 작동합니다. DataFrame :lineregress(two_row_df)
dmeu

훌륭한 답변. 당신이 생각한다면 매우 직관적입니다
Raghuram

37

scipy를 설치하고 싶지 않다면 Programming Collective Intelligence 에서 약간 수정 된이 빠른 해킹을 사용했습니다 .

(정확성을 위해 편집되었습니다.)

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

2
Excel, NumPy 및 R과의 의견 차이에 대해 놀랐습니다 . stackoverflow.com/questions/3949226/…을 참조하십시오 .
dfrankow

2
다른 주석가가 지적했듯이, 이것은 float / int 버그가 있습니다. sum_y / n은 정수의 정수 나누기라고 생각합니다. sum_x = float (sum (x)) 및 sum_y = float (sum (y))를 사용하면 작동합니다.
dfrankow

@dfrankow 나는 imap이 float을 처리 할 수 ​​없기 때문이라고 생각한다. python gives TypeError: unsupported operand type(s) for -: 'itertools.imap' and 'float'atnum = psum - (sum_x * sum_y/n)
alvas

4
스타일 노트로서 파이썬은이 불필요한 불필요한 맵 사용에 대해 눈살을
찌푸립니다 (

14
주석처럼, scipy et al과 같은 라이브러리는 많은 수치 분석을 알고있는 사람들에 의해 개발되었다는 것을 고려하십시오. 이렇게하면 많은 일반적인 함정을 피할 수 있습니다 (예를 들어, X 또는 Y에 숫자가 매우 많고 아주 적
으면

32

다음 코드는 정의에 대한 간단한 해석입니다 .

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

이것은 엑셀, 동의 이 계산기 , SciPy (도 NumPy와 각각 0.981980506 및 0.9819805060619657 및 0.98198050606196574을 반환).

R :

> cor( c(1,2,3), c(1,5,7))
[1] 0.9819805

편집 : 댓글 작성자가 지적한 버그를 수정했습니다.


4
변수 유형에주의하십시오! int / float 문제가 발생했습니다. 에서 sum(x) / len(x)당신의 int를 분할, 수레 없습니다. 따라서 sum([1,5,7]) / len([1,5,7]) = 13 / 3 = 4정수 나누기 (원하는 곳)에 따르면13. / 3. = 4.33... )에 따라. 그것을 고치려면이 줄을 다음과 같이 다시 작성하십시오 float(sum(x)) / float(len(x))(파이썬이 자동으로 변환하므로 하나의 부동 소수점이면 충분합니다).
Piotr Migdal

[10,10,10], [0,0,0] 또는 [10,10], [10,0]과 같은 경우 코드가 작동하지 않습니다. 또는 심지어 [10,10], [10,10]
madCode

4
이러한 경우에 상관 계수가 정의되지 않았습니다. R에 넣으면 세 개 모두에 대해 "NA"가 반환됩니다.
dfrankow

28

당신도 이것을 할 수 있습니다 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

5
이것은 의미없는 상관 관계 일뿐입니다
Ivelin

12

numpy / scipy에 의존하기보다는 Pearson Correlation Coefficient (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 의 중요성 은 기본적으로 두 변수 / 목록이 얼마나 강한 상관 관계 가 있는지 보여줍니다 . PCC 값의 범위 는 -1 ~ 1 입니다. 0에서 1 사이의 값은 양의 상관 관계를 나타냅니다. 0의 값은 가장 높은 변동 (상관 관계 없음)입니다. -1에서 0 사이의 값은 음의 상관 관계를 나타냅니다.


2
파이썬에는 내장 sum함수가 있습니다.
bfontaine 10

5
500 개 이상의 값을 가진 2 개의 목록에서 놀라운 복잡성과 성능이 저하됩니다.
Nikolay Fominyh

9

파이썬에서 팬더를 사용한 피어슨 계수 계산 : 데이터에 목록이 포함되어 있으므로이 접근법을 시도하는 것이 좋습니다. 데이터 구조를 시각화하고 원하는대로 업데이트 할 수 있기 때문에 콘솔에서 데이터와 쉽게 상호 작용하고 조작 할 수 있습니다. 나중에 분석하기 위해 데이터 세트를 내보내고 저장하고 파이썬 콘솔에서 새 데이터를 추가 할 수도 있습니다. 이 코드는 더 간단하고 적은 코드 줄을 포함합니다. 추가 분석을 위해 데이터를 스크리닝하기 위해 몇 가지 빠른 코드 줄이 필요하다고 가정합니다.

예:

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 

그러나 데이터 세트의 크기 나 분석 전에 필요할 수있는 변환을 볼 수 있도록 데이터를 게시하지 않았습니다.


안녕하세요, StackOverflow에 오신 것을 환영합니다! 이 코드를 선택한 이유와 답변 시작시이 코드가 어떻게 적용되는지에 대한 간단한 설명을 추가하십시오!
Tristo

8

흠, 이러한 응답 중 많은 부분이 길고 읽기 어려운 코드입니다 ...

배열로 작업 할 때 멋진 기능으로 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)

이 답변을 매우 좋아하지만 함수 내에서 X와 Y를 모두 복사 / 복제하는 것이 좋습니다. 그렇지 않으면 둘 다 변경되어 원하는 동작이 아닐 수 있습니다.
antonimmo 2016 년

7

이것은 numpy를 사용한 Pearson Correlation 함수의 구현입니다.


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


7

다음은 mkh의 답변보다 훨씬 빠르게 실행되는 변형과 numba를 사용하는 scipy.stats.pearsonr입니다.

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)

5

다음은 희소 벡터를 기반으로 한 피어슨 상관에 대한 구현입니다. 여기의 벡터는 (인덱스, 값)으로 표현 된 튜플 목록으로 표현됩니다. 두 희소 벡터는 길이가 다를 수 있지만 모든 벡터 크기에서 동일해야합니다. 이것은 대부분의 기능이 단어로 인해 벡터 크기가 매우 큰 텍스트 마이닝 응용 프로그램에 유용하므로 계산은 일반적으로 스파 스 벡터를 사용하여 수행됩니다.

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)

3

이에 대한 매우 간단하고 이해하기 쉬운 솔루션이 있습니다. 길이가 같은 두 배열의 경우 Pearson 계수는 다음과 같이 쉽게 계산할 수 있습니다.

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

1

특정 방향 (음 또는 양의 상관)으로 상관 관계를 찾는 상황에서 확률을 해석하는 방법이 궁금 할 수 있습니다. 여기에 도움을주기 위해 작성한 함수가 있습니다. 심지어 옳을 수도 있습니다!

여기에 게시 된 다른 답변 덕분에 http://www.vassarstats.net/rsig.htmlhttp://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)


0
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

코드 전용 답변은 모범 사례로 간주되지 않습니다. 코드에서 질문을 처리하는 방법을 설명하기 위해 몇 단어를 추가하십시오. (SO에 대한 질문에 대답하는 방법에 대한 도움말 페이지를 읽으십시오)
Yannis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.