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
Sacha
sumber
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
115

Korelasi Pearson dapat dihitung dengan numpy corrcoef.

import numpy
numpy.corrcoef(list1, list2)[0, 1]
pemenang
sumber
hasilnya membingungkan, tetapi sebenarnya sangat sederhana. periksa penjelasan ini stackoverflow.com/a/3425548/1245622
linqu
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)
Salvador Dali
sumber
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
Jeff Hammerbacher
sumber
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.

dfrankow
sumber
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
Martin Thoma
sumber
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.

compski
sumber
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.

Web Ster
sumber
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)
Martin F Thomsen
sumber
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

Mojtaba Khodadadi
sumber
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)
Turtles Are Cute
sumber
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)
Vipul Sharma
sumber
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
aumpen
sumber
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)
Joshua Richardson
sumber
1

Anda dapat melihat artikel ini. Ini adalah contoh yang terdokumentasi dengan baik untuk menghitung korelasi berdasarkan data pasangan mata uang forex historis dari beberapa file menggunakan panda library (untuk Python), dan kemudian menghasilkan plot peta panas menggunakan perpustakaan seaborn.

http://www.tradinggeeks.net/2015/08/calculating-correlation-in-python/

Oleg K
sumber
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
Sumber
sumber
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