Menghitung korelasi dan signifikansi Pearson dalam Python


Jawaban:


202

Anda dapat melihat 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
Bagaimana dengan koefisien korelasi dua kamus ?!
user702846

2
@ user702846 korelasi Pearson didefinisikan pada matriks 2xN. Tidak ada metode yang berlaku secara umum yang mengubah dua kamus menjadi matriks 2xN, tetapi Anda dapat menggunakan larik pasangan nilai kamus yang terkait dengan kunci persimpangan dari kunci-kunci kamus Anda.
winerd


56

Alternatif dapat berupa fungsi scipy asli dari linregress yang menghitung:

slope: kemiringan garis regresi

mencegat: mencegat garis regresi

nilai r: koefisien korelasi

p-value: p-value dua sisi untuk uji hipotesis yang hipotesis nolnya adalah kemiringan nol

stderr: Kesalahan standar estimasi

Dan ini sebuah contoh:

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)

akan mengembalikan Anda:

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

2
Jawaban yang bagus - sejauh ini yang paling informatif. Juga berfungsi dengan panda dua baris. Data Bingkai:lineregress(two_row_df)
dmeu

Jawaban yang brilian. Sangat intuitif juga, jika Anda memikirkannya
Raghuram

37

Jika Anda merasa tidak ingin menginstal scipy, saya telah menggunakan hack cepat ini, sedikit dimodifikasi dari Programming Collective Intelligence :

(Diedit untuk kebenaran.)

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
Saya terkejut menemukan ini tidak setuju dengan Excel, NumPy, dan R. Lihat stackoverflow.com/questions/3949226/… .
dfrankow

2
Seperti komentator lain tunjukkan, ini memiliki bug float / int. Saya pikir sum_y / n adalah pembagian integer untuk int. Jika Anda menggunakan sum_x = float (jumlah (x)) dan sum_y = float (jumlah (y)), itu berhasil.
dfrankow

@dfrankow Saya pikir itu karena imap tidak dapat menangani float. python memberikan TypeError: unsupported operand type(s) for -: 'itertools.imap' and 'float'atnum = psum - (sum_x * sum_y/n)
alvas

4
Sebagai catatan gaya, Python tidak menyukai penggunaan peta yang tidak perlu ini (mendukung pemahaman daftar)
Maxim Khesin

14
Sama seperti komentar, pertimbangkan bahwa perpustakaan sebagai scipy et al dikembangkan oleh orang-orang yang tahu banyak analisis numerik. Ini mungkin menghindarkan Anda dari banyak perangkap umum (misalnya, memiliki jumlah X atau Y yang sangat besar dan sangat sedikit dapat mengakibatkan pembatalan bencana)
geekazoid

32

Kode berikut adalah interpretasi langsung dari definisi :

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)

Uji:

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

kembali

0.981980506062

Ini setuju dengan Excel, kalkulator ini , SciPy (juga NumPy ), yang mengembalikan 0,981980506 dan 0,9819805060619657, dan 0,98198050606196574, masing-masing.

R :

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

EDIT : Memperbaiki bug yang ditunjukkan oleh komentator.


4
Waspadalah terhadap jenis variabel! Anda mengalami masalah int / float. Di sum(x) / len(x)Anda membagi ints, bukan mengapung. Jadi sum([1,5,7]) / len([1,5,7]) = 13 / 3 = 4, menurut pembagian integer (padahal Anda mau 13. / 3. = 4.33...). Untuk memperbaikinya, tulis ulang baris ini sebagai float(sum(x)) / float(len(x))(satu float sudah mencukupi, seperti Python yang mengubahnya secara otomatis).
Piotr Migdal

Kode Anda tidak akan berfungsi untuk kasus-kasus seperti: [10,10,10], [0,0,0] atau [10,10], [10,0]. atau bahkan [10,10], [10,10]
madCode

4
Koefisien korelasi tidak didefinisikan untuk semua kasus tersebut. Menempatkan mereka dalam R mengembalikan "NA" untuk ketiganya.
dfrankow

28

Anda dapat melakukannya dengan 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()

Ini memberi

          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
Ini hanya korelasi tanpa signifikansi
Ivelin

12

Daripada mengandalkan numpy / scipy, saya pikir jawaban saya harus yang paling mudah untuk kode dan memahami langkah-langkah dalam menghitung Koefisien Korelasi Pearson (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)

The signifikansi dari PCC pada dasarnya adalah untuk menunjukkan kepada Anda bagaimana sangat berkorelasi dua variabel / daftar yang. Penting untuk dicatat bahwa nilai PCC berkisar dari -1 hingga 1 . Nilai antara 0 hingga 1 menunjukkan korelasi positif. Nilai 0 = variasi tertinggi (tidak ada korelasi apa pun). Nilai antara -1 hingga 0 menunjukkan korelasi negatif.


2
Perhatikan bahwa Python memiliki sumfungsi bawaan .
bfontaine

5
Ini memiliki kompleksitas luar biasa dan kinerja lambat pada 2 daftar dengan nilai 500+.
Nikolay Fominyh

9

Perhitungan koefisien Pearson menggunakan panda dalam python: Saya sarankan mencoba pendekatan ini karena data Anda berisi daftar. Akan mudah berinteraksi dengan data Anda dan memanipulasinya dari konsol karena Anda dapat memvisualisasikan struktur data Anda dan memperbaruinya sesuai keinginan. Anda juga dapat mengekspor kumpulan data dan menyimpannya dan menambahkan data baru dari konsol python untuk analisis nanti. Kode ini lebih sederhana dan mengandung lebih sedikit baris kode. Saya mengasumsikan Anda memerlukan beberapa baris kode cepat untuk menyaring data Anda untuk analisis lebih lanjut

Contoh:

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 

Namun, Anda tidak memposting data Anda untuk saya untuk melihat ukuran kumpulan data atau transformasi yang mungkin diperlukan sebelum analisis.


Halo, selamat datang di StackOverflow! Coba tambahkan deskripsi singkat tentang mengapa Anda memilih kode ini dan bagaimana penerapannya dalam kasus ini di awal jawaban Anda!
Tristo

8

Hmm, banyak dari tanggapan ini yang panjang dan sulit dibaca kode ...

Saya sarankan menggunakan numpy dengan fitur-fiturnya yang bagus ketika bekerja dengan array:

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)

Meskipun saya sangat menyukai jawaban ini, saya akan menyarankan untuk menyalin / mengkloning X dan Y di dalam fungsi. Kalau tidak keduanya diubah, yang mungkin bukan perilaku yang diinginkan.
antonimmo

7

Ini adalah implementasi fungsi Korelasi Pearson menggunakan 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


7

Berikut varian jawaban mkh yang berjalan lebih cepat daripada itu, dan scipy.stats.pearsonr, menggunakan 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)

5

Berikut ini adalah implementasi untuk korelasi pearson berdasarkan vektor jarang. Vektor di sini dinyatakan sebagai daftar tupel yang dinyatakan sebagai (indeks, nilai). Dua vektor jarang dapat memiliki panjang yang berbeda tetapi pada semua ukuran vektor harus sama. Ini berguna untuk aplikasi penambangan teks di mana ukuran vektor sangat besar karena sebagian besar fitur menjadi kantong kata dan karenanya perhitungan biasanya dilakukan menggunakan vektor jarang.

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)

Tes unit:

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

Saya punya solusi yang sangat sederhana dan mudah dipahami untuk ini. Untuk dua array dengan panjang yang sama, koefisien Pearson dapat dengan mudah dihitung sebagai berikut:

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

Anda mungkin bertanya-tanya bagaimana menafsirkan probabilitas Anda dalam konteks mencari korelasi dalam arah tertentu (korelasi negatif atau positif.) Berikut adalah fungsi yang saya tulis untuk membantu hal itu. Bahkan mungkin benar!

Ini berdasarkan info yang saya peroleh dari http://www.vassarstats.net/rsig.html dan http://en.wikipedia.org/wiki/Student%27s_t_distribution , terima kasih atas jawaban lain yang diposting di sini.

# 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

Jawaban hanya kode tidak dianggap praktik yang baik. Harap pertimbangkan untuk menambahkan beberapa kata untuk menjelaskan bagaimana kode Anda menjawab pertanyaan. (baca halaman bantuan tentang cara menjawab pertanyaan di SO)
Yannis
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.