web-dev-qa-db-fra.com

Calcul de la corrélation et de la signification de Pearson en Python

Je cherche une fonction qui prend en entrée deux listes et renvoie la corrélation Pearson , ainsi que la signification de la corrélation.

150
ariel

Vous pouvez consulter 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
176
Sacha

La corrélation de Pearson peut être calculée avec numpy corrcoef .

import numpy
numpy.corrcoef(list1, list2)[0, 1]
94
winerd

Une alternative peut être une fonction scipy native de linregress qui calcule:

pente: pente de la droite de régression 

intercept: intercept de la droite de régression 

valeur r: coefficient de corrélation

valeur p: valeur p bilatérale pour un test d'hypothèse dont l'hypothèse nulle est que la pente est nulle

stderr: erreur type de l'estimation

Et voici un exemple:

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)

vous rendra: 

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

Si vous n'avez pas envie d'installer scipy, j'ai utilisé ce hack rapide, légèrement modifié depuis Programmation de l'intelligence collective :

(Edité pour l'exactitude.)

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
34
Jeff Hammerbacher

Le code suivant est une interprétation directe de la définition :

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)

Tester:

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

résultats

0.981980506062

Ceci correspond à Excel, cette calculatrice , SciPy (également NumPy ), qui renvoient respectivement 0,981980506 et 0.9819805060619657 et 0.98198050606196574.

R :

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

EDIT: correction d'un bug signalé par un commentateur.

29
dfrankow

Vous pouvez le faire avec pandas.DataFrame.corr aussi:

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

Cela donne

          0         1         2
0  1.000000  0.745601  0.916579
1  0.745601  1.000000  0.544248
2  0.916579  0.544248  1.000000
20
Martin Thoma

Plutôt que de compter sur numpy/scipy, je pense que ma réponse devrait être la plus facile à coder et comprendre les étapes dans le calcul du coefficient de corrélation de 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)

La signification de PCC est essentiellement destinée à vous montrer comment fortement corrélés les deux variables/listes sont. Il est important de noter que la valeur PCC varie de de -1 à 1 . Une valeur comprise entre 0 et 1 indique une corrélation positive . Valeur de 0 = la plus forte variation ) . Une valeur comprise entre -1 et 0 indique une corrélation négative.

13
compski

Hmm, beaucoup de ces réponses ont un code long et difficile à lire ...

Je suggère d'utiliser numpy avec ses fonctionnalités astucieuses lorsque vous travaillez avec des tableaux:

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

Voici une variante de la réponse de mkh qui s'exécute beaucoup plus rapidement que scipy.stats.pearsonr, à l'aide de 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
Turtles Are Cute

Voici une implémentation pour la corrélation pearson basée sur un vecteur clairsemé. Les vecteurs ici sont exprimés sous la forme d'une liste de tuples exprimée sous la forme (index, valeur). Les deux vecteurs clairsemés peuvent être de longueur différente, mais la taille de tous les vecteurs devra être identique. Ceci est utile pour les applications d’exploration de texte où la taille du vecteur est extrêmement grande en raison du fait que la plupart des caractéristiques sont un sac de mots et que, par conséquent, les calculs sont effectués à l’aide de vecteurs fragmentés. 

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)

Tests unitaires:

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)
4
Vipul Sharma

Ceci est une implémentation de la fonction de corrélation de Pearson utilisant 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
4

Calcul du coefficient de Pearson avec des pandas en python: Je suggérerais d’essayer cette approche car vos données contiennent des listes. Il sera facile d’interagir avec vos données et de les manipuler depuis la console puisque vous pouvez visualiser votre structure de données et la mettre à jour à votre guise. Vous pouvez également exporter le jeu de données et le sauvegarder, puis ajouter de nouvelles données à partir de la console Python pour une analyse ultérieure. Ce code est plus simple et contient moins de lignes de code. Je suppose que vous avez besoin de quelques lignes de code rapides pour filtrer vos données en vue d'une analyse plus approfondie. 

Exemple:

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 

Cependant, vous ne m'avez pas envoyé vos données pour voir la taille de l'ensemble de données ou les transformations nécessaires avant l'analyse. 

3
Web Ster

Vous pouvez jeter un oeil à cet article. Ceci est un exemple bien documenté pour calculer la corrélation sur la base des données historiques des paires de devises forex à partir de plusieurs fichiers à l'aide de la bibliothèque pandas (pour Python), puis pour générer un graphique heatmap à l'aide de la bibliothèque Seaborn.

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

1
Oleg K

Vous vous demandez peut-être comment interpréter votre probabilité dans le contexte de la recherche d'une corrélation dans une direction particulière (corrélation négative ou positive). Voici une fonction que j'ai écrite pour vous aider. Cela pourrait même être juste!

C'est basé sur les informations que j'ai glanées dans http://www.vassarstats.net/rsig.html et http://en.wikipedia.org/wiki/Student%27s_t_distribution , grâce aux autres réponses postées. ici.

# 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
Joshua Richardson
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
0
Source

J'ai une solution très simple et facile à comprendre pour cela. Pour deux tableaux de longueur égale, le coefficient de Pearson peut facilement être calculé comme suit: 

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
0
aumpen