pandas: Compute correlation among rows of a table

2.7k views Asked by At

I have a table of values with two category fields and a single count. I need to compute the correlation among rows of one category based on their counts across the other category.

So for instance:

Category_A|Category_B|Count
Alan      |Turkey    |7
Alan      |Ham       |1
Alan      |Spam      |0
...
Bob       |Turkey    |2
Bob       |Ham       |9
Bob       |Spam      |12
...

I need to get Pearson's correlation with p-value in a table like this:

Category_A_1|Category_A_2|Correlation|P Value
Alan        |Bob         |0.7        |0.07

I can't figure out how to do this in Pandas. Please help. Thanks!

3

There are 3 answers

7
DYZ On BEST ANSWER
corrs = df.pivot('Category_A','Category_B').T.corr().stack()
#Category_A  Category_A
#Alan        Alan          1.000000
#            Bob          -0.986552
#Bob         Alan         -0.986552
#            Bob           1.000000
corrs.index.names = 'A','B'
corrs.reset_index()
#      A     B         0
#0  Alan  Alan  1.000000
#1  Alan   Bob -0.986552
#2   Bob  Alan -0.986552
#3   Bob   Bob  1.000000

Unfortunately, Pandas does not have tools for calculating the p-values.

1
Lucas Ramadan On

This may not be the "perfect" answer, in terms of using Pandas, but you could consider using the statsmodels module, as it has a OLS object that can give both the correlation coefficient, as well as the corresponding p-value.

As long as you can get the order of the arrays to be correct (using a groupby, sorting, etc), you can get the values:

d1 = [['Alan', 'Turkey', 7],
      ['Alan', 'Ham', 1],
      ['Alan', 'Spam', 0]]

df1 = pd.DataFrame(d1, columns=["Category_A", 'Category_B', 'Count'])

d2 = [['Bob', 'Turkey', 2],
      ['Bob', 'Ham', 9],
      ['Bob', 'Spam', 12]]


df2 = pd.DataFrame(d2, columns=["Category_A", 'Category_B', 'Count'])

# package import
import statsmodels.api as sm

# regression model
model = sm.OLS(df2['Count'], df1['Count'])

# get results
results = model.fit()

# pearson coefficient, and p-value
r2, pvalue = results.rsquared, results.pvalues.values[0]

OUT: (0.046200873362445494, 0.78505611578264101)

There's probably a better way to do this, but could work.

0
Ian On

In case the p_value matters:

import scipy.stats
df = df.pivot('Category_A','Category_B').T
n = len(df.volumns)
res = pd.DataFrame(columns=['Category_A','Category_B','Corr','P_value'])
for i in range(n):
    for j in range(i+1,n):
        pears = scipy.stats(df.iloc[:,i],df.iloc[:,j])
        res.loc[-1] = [df.columns[i],df.columns[j],pears[0],pears[1]]
        res.index += 1