Python'da Pearson korelasyonunu ve önemini hesaplama


Yanıtlar:


202

Şuna bir göz atabilirsiniz 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
İki sözlük arasındaki korelasyon katsayısına ne dersiniz?!
user702846

2
user702846 Pearson korelasyonu 2xN matrisinde tanımlanır. İki sözlüğü 2xN matrisine dönüştüren genel olarak uygulanabilir bir yöntem yoktur, ancak sözlüklerinizin anahtarlarının kesişiminin tuşlarına karşılık gelen sözlük değerleri çiftini kullanabilirsiniz.
winerd


56

Bir alternatif, linregress'ten yerel bir scipy fonksiyonu olabilir ve bu da aşağıdakileri hesaplar:

eğim: regresyon çizgisinin eğimi

kesme noktası: regresyon çizgisinin kesilmesi

r-değeri: korelasyon katsayısı

p değeri: sıfır hipotezi eğimin sıfır olduğu hipotez testi için iki taraflı p değeri

stderr: Tahminin standart hatası

Ve işte bir örnek:

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)

size dönecektir:

LinregressResult(slope=0.20833333333333337, intercept=13.375, rvalue=0.14499815458068521, pvalue=0.68940144811669501, stderr=0.50261704627083648)

2
Büyük cevap - bugüne kadar en bilgilendirici. Ayrıca iki sıralı pandalarla da çalışır.DataFrame:lineregress(two_row_df)
dmeu

Mükemmel cevap. Çok sezgisel, eğer düşünürseniz
Raghuram

37

Scipy kurmak istemiyorsanız, Programlı Kolektif Zeka'dan biraz değiştirilmiş bu hızlı hack'i kullandım :

(Doğruluk için düzenlenmiştir.)

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 ve R ile bu anlaşmazlıkları keşfetmekten şaşırdım . Bkz. Stackoverflow.com/questions/3949226/… .
dfrankow

2
Başka bir yorumcunun işaret ettiği gibi, bunun bir float / int hatası var. Bence sum_y / n ints için tamsayı bölümüdür. Sum_x = float (sum (x)) ve sum_y = float (sum (y)) kullanırsanız çalışır.
dfrankow

@dfrankow Bence imap şamandıra ile baş edemiyor. python verir bir TypeError: unsupported operand type(s) for -: 'itertools.imap' and 'float'atnum = psum - (sum_x * sum_y/n)
alvas

4
Bir stil notu olarak Python, haritanın bu gereksiz kullanımı hakkında (liste kavrayışları lehine)
kaşlarını çatıyor

14
Bir yorum olarak, scipy ve diğerleri gibi kütüphanelerin çok sayıda sayısal analiz bilen insanlar tarafından geliştirildiğini düşünün. Bu, çok sayıda yaygın tuzaktan kaçınabilir (örneğin, X veya Y'de çok büyük ve çok az sayıya sahip olmak felaket iptali ile sonuçlanabilir)
geekazoid

32

Aşağıdaki kod, tanımın düz bir yorumudur :

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)

Ölçek:

print pearson_def([1,2,3], [1,5,7])

İadeler

0.981980506062

Bu Excel ile aynı görüşü bu hesap makinesi , SciPy (ayrıca NumPy sırasıyla 0.981980506 ve 0.9819805060619657 ve 0.98198050606196574, dönüş).

R :

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

EDIT : Bir yorumcunun işaret ettiği bir hata düzeltildi.


4
Değişkenlerin türüne dikkat edin! Bir int / float sorunuyla karşılaştınız. İçinde sum(x) / len(x)ints bölmek, yüzen değil. Yani sum([1,5,7]) / len([1,5,7]) = 13 / 3 = 4, tamsayıya göre (istediğiniz gibi 13. / 3. = 4.33...). Düzeltmek için bu satırı yeniden yazın float(sum(x)) / float(len(x))(bir şamandıra yeterlidir, çünkü Python otomatik olarak dönüştürür).
Piotr Migdal

Kodunuz [10,10,10], [0,0,0] veya [10,10], [10,0] gibi durumlar için çalışmaz. hatta [10,10], [10,10]
madCode 18:12

4
Bu vakaların hiçbiri için korelasyon katsayısı tanımlanmamıştır. Bunları R'ye koymak, üçü için de "NA" döndürür.
dfrankow

28

Bunu aşağıdakilerle de yapabilirsiniz 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()

Bu verir

          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
Bu önemsiz bir korelasyon
Ivelin

12

Numpy / scipy'e güvenmek yerine, cevabımın Pearson Korelasyon Katsayısı'nı (PCC) hesaplama adımlarını kodlamak ve anlamak için en kolay olması gerektiğini düşünüyorum .

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)

Önemi PCC nasıl size göstermek için temelde güçlü bir korelasyon iki değişken / listelerdir. PCC değerinin -1 ile 1 arasında değiştiğine dikkat etmek önemlidir . 0 ile 1 arasındaki bir değer pozitif bir korelasyonu gösterir. 0 değeri = en yüksek varyasyon (herhangi bir korelasyon yoktur). -1 ile 0 arasındaki bir değer negatif bir korelasyona işaret eder.


2
Python'un yerleşik bir sumişlevi olduğunu unutmayın .
bfontaine

5
500'den fazla değerle 2 listede inanılmaz karmaşıklığa ve yavaş performansa sahiptir.
Nikolay Fominyh

9

Python'da pandalar kullanarak Pearson katsayısı hesaplaması: Verileriniz listeler içerdiğinden bu yaklaşımı denemenizi öneririm. Veri yapınızı görselleştirip istediğiniz gibi güncelleyebileceğinizden verilerinizle etkileşim kurmak ve konsoldan değiştirmek kolay olacaktır. Ayrıca veri kümesini dışa aktarabilir ve kaydedebilir ve daha sonra analiz etmek için python konsolundan yeni veriler ekleyebilirsiniz. Bu kod daha basittir ve daha az kod satırı içerir. Daha fazla analiz için verilerinizi taramak için birkaç hızlı kod satırına ihtiyacınız olduğunu varsayıyorum

Misal:

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 

Ancak, veri kümesinin boyutunu veya analizden önce gerekli olabilecek dönüşümleri görmek için verilerinizi bana göndermediniz.


Merhaba, StackOverflow'a hoş geldiniz! Bu kodu neden seçtiğinizi ve cevabınızın başında bu durumda nasıl uygulandığına dair kısa bir açıklama eklemeyi deneyin!
Tristo

8

Hmm, bu yanıtların çoğunun kodu uzun ve zor okunuyor ...

Dizilerle çalışırken nifty özellikleriyle numpy kullanmanızı öneririm:

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)

Bu cevabı çok sevmeme rağmen, fonksiyonun içinde hem X hem de Y'yi kopyalamanızı / klonlamanızı tavsiye ederim. Aksi takdirde her ikisi de değiştirilir, bu da istenen bir davranış olmayabilir.
antonimmo

7

Bu numpy kullanarak Pearson Korelasyon fonksiyonunun bir uygulamasıdır:


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

İşte mkh cevabından ondan çok daha hızlı çalışan bir değişken ve scipy.stats.pearsonr, numba kullanarak.

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

İşte seyrek vektöre dayalı pearson korelasyonu için bir uygulama. Buradaki vektörler, (indeks, değer) olarak ifade edilen tupleslerin bir listesi olarak ifade edilir. İki seyrek vektör farklı uzunlukta olabilir, ancak tüm vektör boyutlarının aynı olması gerekir. Bu, çoğu özelliğin kelime torbası olması nedeniyle vektör boyutunun çok büyük olduğu metin madenciliği uygulamaları için yararlıdır ve bu nedenle hesaplamalar genellikle seyrek vektörler kullanılarak gerçekleştirilir.

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)

Birim testleri:

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

Bunun için çok basit ve anlaşılması kolay bir çözümüm var. Eşit uzunlukta iki dizi için Pearson katsayısı aşağıdaki gibi kolayca hesaplanabilir:

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

Olasılığınızı belirli bir yönde bir korelasyon arama bağlamında nasıl yorumlayacağınızı merak edebilirsiniz (negatif veya pozitif korelasyon.) İşte size yardımcı olmak için yazdığım bir fonksiyon. Doğru bile olabilir!

Burada yayınlanan diğer yanıtlar sayesinde http://www.vassarstats.net/rsig.html ve http://en.wikipedia.org/wiki/Student%27s_t_distribution'dan topladığım bilgilere dayanmaktadır .

# 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

Yalnızca kod yanıtları iyi uygulama olarak değerlendirilmez. Lütfen kodunuzun soruyu nasıl ele aldığını açıklamak için birkaç kelime eklemeyi düşünün. (SO ile ilgili bir soruya nasıl cevap verileceği ile ilgili yardım sayfasını okuyun)
Yannis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.