Tính toán tương quan và ý nghĩa của Pearson trong Python


Câu trả lời:


202

Bạn có thể xem qua 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
Làm thế nào về hệ số tương quan của hai từ điển?!
dùng702846

2
@ user702846 Tương quan Pearson được xác định trên ma trận 2xN. Không có phương pháp áp dụng chung nào có thể chuyển đổi hai từ điển thành ma trận 2xN, nhưng bạn có thể sử dụng mảng các cặp giá trị từ điển tương ứng với các khóa của giao điểm của các từ điển của bạn.
thắng cuộc


56

Một thay thế có thể là một hàm scipy bản địa từ linregress tính toán:

độ dốc: độ dốc của đường hồi quy

đánh chặn: chặn đường hồi quy

giá trị r: hệ số tương quan

p-value: giá trị p hai mặt cho một bài kiểm tra giả thuyết có giả thuyết null là độ dốc bằng không

stderr: Lỗi tiêu chuẩn của dự toán

Và đây là một ví dụ:

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)

sẽ trả lại cho bạn:

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

2
Câu trả lời tuyệt vời - cho đến nay nhiều thông tin nhất. Cũng hoạt động với một con gấu trúc hai hàng.DataFrame:lineregress(two_row_df)
dmeu

Rực rỡ trả lời. Cũng rất trực quan, nếu bạn nghĩ về nó
Raghuram

37

Nếu bạn không muốn cài đặt scipy, tôi đã sử dụng bản hack nhanh này, được sửa đổi một chút từ Lập trình thông minh lập trình :

(Đã chỉnh sửa cho chính xác.)

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
Tôi đã rất ngạc nhiên khi phát hiện ra sự không đồng ý này với Excel, NumPy và R. Xem stackoverflow.com/questions/3949226/ .
dfrankow

2
Như một bình luận khác đã chỉ ra, điều này có lỗi float / int. Tôi nghĩ sum_y / n là phép chia số nguyên cho ints. Nếu bạn sử dụng sum_x = float (sum (x)) và sum_y = float (sum (y)), nó hoạt động.
dfrankow

@dfrankow Tôi nghĩ đó là vì imap không thể xử lý nổi. python cho một TypeError: unsupported operand type(s) for -: 'itertools.imap' and 'float'lúcnum = psum - (sum_x * sum_y/n)
alvas

4
Như một ghi chú về phong cách Python cau mày với việc sử dụng bản đồ không cần thiết này (ủng hộ việc hiểu danh sách)
Maxim Khesin

14
Cũng như một nhận xét, hãy xem xét rằng các thư viện như scipy et al được phát triển bởi những người biết nhiều phân tích số. Điều này có thể tránh cho bạn rất nhiều cạm bẫy phổ biến (ví dụ: có số lượng rất lớn và rất ít trong X hoặc Y có thể dẫn đến hủy bỏ catastrofic)
geekazoid

32

Các mã sau đây là một giải thích thẳng của định nghĩa :

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)

Kiểm tra:

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

trả lại

0.981980506062

Điều này đồng ý với Excel, máy tính này , SciPy (cũng là NumPy ), lần lượt trả về 0,981980506 và 0,9819805060619657 và 0,98198050606196574.

R :

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

EDIT : Đã sửa lỗi được chỉ ra bởi một người bình luận.


4
Cẩn thận với các loại biến! Bạn đã gặp một vấn đề int / float. Trong sum(x) / len(x)bạn chia ints, không nổi. Vì vậy sum([1,5,7]) / len([1,5,7]) = 13 / 3 = 4, theo phân chia số nguyên (trong khi bạn muốn 13. / 3. = 4.33...). Để sửa nó, hãy viết lại dòng này dưới dạng float(sum(x)) / float(len(x))(một float là đủ, vì Python tự động chuyển đổi nó).
Piotr Migdal

Mã của bạn sẽ không hoạt động trong các trường hợp như: [10,10,10], [0,0,0] hoặc [10,10], [10,0]. hoặc thậm chí [10,10], [10,10]
madCode

4
Hệ số tương quan không được xác định cho bất kỳ trường hợp nào. Đặt chúng vào R trả về "NA" cho cả ba.
dfrankow

28

Bạn cũng có thể làm điều này với 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()

Điều này mang lại

          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
Đây chỉ là mối tương quan không có ý nghĩa
Ivelin

12

Thay vì dựa vào numpy / scipy, tôi nghĩ rằng câu trả lời của tôi nên dễ viết mã nhất và hiểu các bước trong tính toán Hệ số tương quan 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)

Tầm quan trọng của PCC về cơ bản là cho bạn thấy mức độ tương quan mạnh mẽ của hai biến / danh sách. Điều quan trọng cần lưu ý là giá trị PCC nằm trong khoảng từ -1 đến 1 . Giá trị từ 0 đến 1 biểu thị mối tương quan dương. Giá trị 0 = biến thiên cao nhất (không có tương quan gì). Giá trị từ -1 đến 0 biểu thị mối tương quan âm.


2
Lưu ý rằng Python có sumhàm dựng sẵn .
bfontaine

5
Nó có độ phức tạp đáng kinh ngạc và hiệu suất chậm trên 2 danh sách với hơn 500 giá trị.
Nikolay Fominyh

9

Tính toán hệ số Pearson bằng cách sử dụng gấu trúc trong trăn: Tôi khuyên bạn nên thử phương pháp này vì dữ liệu của bạn chứa danh sách. Sẽ dễ dàng tương tác với dữ liệu của bạn và thao tác dữ liệu từ bảng điều khiển vì bạn có thể hình dung cấu trúc dữ liệu của mình và cập nhật dữ liệu theo ý muốn. Bạn cũng có thể xuất tập dữ liệu và lưu nó và thêm dữ liệu mới từ bảng điều khiển python để phân tích sau. Mã này đơn giản hơn và chứa ít dòng mã hơn. Tôi giả sử bạn cần một vài dòng mã nhanh để sàng lọc dữ liệu của mình để phân tích thêm

Thí dụ:

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 

Tuy nhiên, bạn đã không đăng dữ liệu của bạn cho tôi để xem kích thước của tập dữ liệu hoặc các biến đổi có thể cần thiết trước khi phân tích.


Xin chào, chào mừng bạn đến với StackOverflow! Hãy thử thêm một mô tả ngắn về lý do tại sao bạn chọn mã này và cách áp dụng trong trường hợp này khi bắt đầu câu trả lời của bạn!
Tristo

8

Hmm, nhiều phản hồi trong số này có mã dài và khó đọc ...

Tôi khuyên bạn nên sử dụng numpy với các tính năng tiện lợi của nó khi làm việc với mảng:

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)

Mặc dù tôi rất thích câu trả lời này, tôi sẽ khuyên bạn nên sao chép / sao chép cả X và Y bên trong hàm. Mặt khác, cả hai đều bị thay đổi, có thể không phải là một hành vi mong muốn.
antonimmo

7

Đây là một triển khai của hàm Pearson Correlation bằng cách sử dụng 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

Đây là một biến thể của câu trả lời của mkh chạy nhanh hơn nó rất nhiều và scipy.stats.pearsonr, sử dụng 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

Đây là một triển khai cho tương quan pearson dựa trên vector thưa thớt. Các vectơ ở đây được thể hiện dưới dạng một danh sách các bộ dữ liệu được biểu thị dưới dạng (chỉ mục, giá trị). Hai vectơ thưa thớt có thể có chiều dài khác nhau nhưng trên tất cả kích thước vectơ sẽ phải giống nhau. Điều này hữu ích cho các ứng dụng khai thác văn bản trong đó kích thước vectơ cực kỳ lớn do hầu hết các tính năng là túi từ và do đó các phép tính thường được thực hiện bằng cách sử dụng các vectơ thưa thớt.

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)

Bài kiểm tra đơn vị:

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

Tôi có một giải pháp rất đơn giản và dễ hiểu cho việc này. Đối với hai mảng có độ dài bằng nhau, hệ số Pearson có thể được tính toán dễ dàng như sau:

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

Bạn có thể tự hỏi làm thế nào để giải thích xác suất của bạn trong bối cảnh tìm kiếm một mối tương quan theo một hướng cụ thể (tương quan tiêu cực hoặc tích cực.) Đây là một chức năng tôi đã viết để giúp với điều đó. Nó thậm chí có thể đúng!

Nó dựa trên thông tin tôi lượm lặt được từ http://www.vassarstats.net/rsig.htmlhttp://en.wikipedia.org/wiki/Student%27s_t_distribution , nhờ các câu trả lời khác được đăng ở đây.

# 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)

1

Bạn có thể xem bài viết này. Đây là một ví dụ được chứng minh bằng tài liệu để tính toán tương quan dựa trên dữ liệu cặp tiền tệ ngoại hối lịch sử từ nhiều tệp bằng thư viện gấu trúc (đối với Python), sau đó tạo một sơ đồ nhiệt bằng thư viện seaborn.

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


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

Câu trả lời chỉ có mã không được coi là thực hành tốt. Vui lòng xem xét thêm một vài từ để giải thích cách mã của bạn giải quyết câu hỏi. (đọc trang trợ giúp về cách trả lời câu hỏi trên SO)
Yannis
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.