给定一个pandas数据帧df,获得其列df.1
和df.2
之间的相关性的最佳方法是什么?
我不希望输出计算NaN
行,pandas
内置关联。但是我也希望它输出pvalue
或标准错误,内置的错误没有。
SciPy
似乎被NaN追上了,但我相信它确实具有重要意义。
数据示例:
1 2
0 2 NaN
1 NaN 1
2 1 2
3 -4 3
4 1.3 1
5 NaN NaN
答案 0 :(得分:22)
您可以使用scipy.stats相关函数来获取p值。
例如,如果您正在寻找Pearson相关性等相关性,则可以使用pearsonr函数。
from scipy.stats import pearsonr
pearsonr([1, 2, 3], [4, 3, 7])
提供输出
(0.7205766921228921, 0.48775429164459994)
元组中的第一个值是相关值,第二个值是p值。
在您的情况下,您可以使用pandas的dropna
函数首先删除NaN
值。
df_clean = df[['column1', 'column2']].dropna()
pearsonr(df_clean['column1'], df_clean['column2'])
答案 1 :(得分:10)
@Shashank提供的答案很好。但是,如果您想要纯pandas
的解决方案,您可能会喜欢这样:
import pandas as pd
from pandas.io.data import DataReader
from datetime import datetime
import scipy.stats as stats
gdp = pd.DataFrame(DataReader("GDP", "fred", start=datetime(1990, 1, 1)))
vix = pd.DataFrame(DataReader("VIXCLS", "fred", start=datetime(1990, 1, 1)))
#Do it with a pandas regression to get the p value from the F-test
df = gdp.merge(vix,left_index=True, right_index=True, how='left')
vix_on_gdp = pd.ols(y=df['VIXCLS'], x=df['GDP'], intercept=True)
print(df['VIXCLS'].corr(df['GDP']), vix_on_gdp.f_stat['p-value'])
结果:
-0.0422917932738 0.851762475093
与统计数据功能相同:
#Do it with stats functions.
df_clean = df.dropna()
stats.pearsonr(df_clean['VIXCLS'], df_clean['GDP'])
结果:
(-0.042291793273791969, 0.85176247509284908)
为了扩展到更多的可用性,我给你一个丑陋的循环方法:
#Add a third field
oil = pd.DataFrame(DataReader("DCOILWTICO", "fred", start=datetime(1990, 1, 1)))
df = df.merge(oil,left_index=True, right_index=True, how='left')
#construct two arrays, one of the correlation and the other of the p-vals
rho = df.corr()
pval = np.zeros([df.shape[1],df.shape[1]])
for i in range(df.shape[1]): # rows are the number of rows in the matrix.
for j in range(df.shape[1]):
JonI = pd.ols(y=df.icol(i), x=df.icol(j), intercept=True)
pval[i,j] = JonI.f_stat['p-value']
rho的结果:
GDP VIXCLS DCOILWTICO
GDP 1.000000 -0.042292 0.870251
VIXCLS -0.042292 1.000000 -0.004612
DCOILWTICO 0.870251 -0.004612 1.000000
pval的结果:
[[ 0.00000000e+00 8.51762475e-01 1.11022302e-16]
[ 8.51762475e-01 0.00000000e+00 9.83747425e-01]
[ 1.11022302e-16 9.83747425e-01 0.00000000e+00]]
答案 2 :(得分:8)
To calculate all the p-values at once, you can use the below calculate_pvalues
function:
df = pd.DataFrame({'A':[1,2,3], 'B':[2,5,3], 'C':[5,2,1], 'D':['text',2,3] })
calculate_pvalues(df)
The output is similar to the corr()
(but with p-values):
A B C
A 0 0.7877 0.1789
B 0.7877 0 0.6088
C 0.1789 0.6088 0
p-values are rounded to 4 decimals
from scipy.stats import pearsonr
import pandas as pd
def calculate_pvalues(df):
df = df.dropna()._get_numeric_data()
dfcols = pd.DataFrame(columns=df.columns)
pvalues = dfcols.transpose().join(dfcols, how='outer')
for r in df.columns:
for c in df.columns:
pvalues[r][c] = round(pearsonr(df[r], df[c])[1], 4)
return pvalues
答案 3 :(得分:8)
rho = df.corr()
rho = rho.round(2)
pval = calculate_pvalues(df) # toto_tico's answer
# create three masks
r1 = rho.applymap(lambda x: '{}*'.format(x))
r2 = rho.applymap(lambda x: '{}**'.format(x))
r3 = rho.applymap(lambda x: '{}***'.format(x))
# apply them where appropriate
rho = rho.mask(pval<=0.1,r1)
rho = rho.mask(pval<=0.05,r2)
rho = rho.mask(pval<=0.01,r3)
rho
# note I prefer readability over the conciseness of code,
# instead of six lines it could have been a single liner like this:
# [rho.mask(pval<=p,rho.applymap(lambda x: '{}*'.format(x)),inplace=True) for p in [.1,.05,.01]]
答案 4 :(得分:1)
我试图对函数中的逻辑求和,它可能不是最有效的方法,但会为您提供与pandas df.corr()类似的输出。要使用它,只需在代码中添加以下函数,并调用它来提供数据框对象,即。 corr_pvalue(your_dataframe)
我已将值四舍五入到小数点后4位,如果您想要不同的输出,请更改圆函数中的值。
from scipy.stats import pearsonr
import numpy as np
import pandas as pd
def corr_pvalue(df):
numeric_df = df.dropna()._get_numeric_data()
cols = numeric_df.columns
mat = numeric_df.values
arr = np.zeros((len(cols),len(cols)), dtype=object)
for xi, x in enumerate(mat.T):
for yi, y in enumerate(mat.T[xi:]):
arr[xi, yi+xi] = map(lambda _: round(_,4), pearsonr(x,y))
arr[yi+xi, xi] = arr[xi, yi+xi]
return pd.DataFrame(arr, index=cols, columns=cols)
我用pandas v0.18.1测试了它
答案 5 :(得分:0)
这是 oztalha 非常有用的代码。我只是改变了格式(舍入到2位数),只要r不显着。
rho = data.corr()
pval = calculate_pvalues(data) # toto_tico's answer
# create three masks
r1 = rho.applymap(lambda x: '{:.2f}*'.format(x))
r2 = rho.applymap(lambda x: '{:.2f}**'.format(x))
r3 = rho.applymap(lambda x: '{:.2f}***'.format(x))
r4 = rho.applymap(lambda x: '{:.2f}'.format(x))
# apply them where appropriate --this could be a single liner
rho = rho.mask(pval>0.1,r4)
rho = rho.mask(pval<=0.1,r1)
rho = rho.mask(pval<=0.05,r2)
rho = rho.mask(pval<=0.01,r3)
rho
答案 6 :(得分:0)
@toto_tico和@ Somendra-joshi的不错答案。 但是,它会丢弃不必要的NAs值。在此代码片段中,我只是删除了当前正在计算的相关性所属的NA。在实际的corr implementation中,它们执行相同的操作。
def calculate_pvalues(df):
df = df._get_numeric_data()
dfcols = pd.DataFrame(columns=df.columns)
pvalues = dfcols.transpose().join(dfcols, how='outer')
for r in df.columns:
for c in df.columns:
if c == r:
df_corr = df[[r]].dropna()
else:
df_corr = df[[r,c]].dropna()
pvalues[r][c] = pearsonr(df_corr[r], df_corr[c])[1]
return pvalues
答案 7 :(得分:0)
在pandas v0.24.0中,method
参数被添加到corr
中。现在,您可以执行以下操作:
import pandas as pd
import numpy as np
from scipy.stats import pearsonr
df = pd.DataFrame({'A':[1,2,3], 'B':[2,5,3], 'C':[5,2,1]})
df.corr(method=lambda x, y: pearsonr(x, y)[1]) - np.eye(len(df.columns))
A B C
A 0.000000 0.787704 0.178912
B 0.787704 0.000000 0.608792
C 0.178912 0.608792 0.000000
请注意需要使用np.eye(len(df.columns))
的解决方法,因为自相关始终设置为1.0
(请参见https://github.com/pandas-dev/pandas/issues/25726)。
答案 8 :(得分:0)
使用列表理解功能,在一行代码中:
>>> import pandas as pd
>>> from scipy.stats import pearsonr
>>> data = {'y':[0, 3, 2, 4, 3, 5, 4, 6, 5, 7, 6],
... 'x1':[0, 4, 2, 6, 2, 8, 6, 10, 4, 13, 5],
... 'x2':[0.0, 1.3, 0.2, 4.5, 1.3, 1.6, 3.5, 1.7, 1.6, 3.7, 1.7]}
>>> df = pd.DataFrame(data)
>>> pvals = pd.DataFrame([[pearsonr(df[c], df[y])[1] for y in df.columns] for c in df.columns],
... columns=df.columns, index=df.columns)
>>> pvals
y x1 x2
y 0.000000 0.000732 0.069996
x1 0.000732 0.000000 0.036153
x2 0.069996 0.036153 0.000000
>>>
我会对一种光滑的技术感兴趣,该技术可以将上述数据框与此相结合:
>>> df.corr()
y x1 x2
y 1.000000 0.857786 0.565208
x1 0.857786 1.000000 0.634093
x2 0.565208 0.634093 1.000000
所需的输出:
y x1 x2
y c 1.000000 0.857786 0.565208
p (0.0000) (0.0007) (0.0699)
x1 c 0.857786 1.000000 0.634093
p (0.0007) (0.0000) (0.0361)
x2 c 0.565208 0.634093 1.000000
p (0.0699) (0.0361) (0.0000)
有多个索引,其中c
行是相关系数,而p
行则提供pvalue。
有没有人?