具有统计显著性的Pandas列相关

qmelpv7a  于 2022-11-20  发布在  其他
关注(0)|答案(9)|浏览(167)

给定一个Pandas Dataframe df,要获得其列df.1df.2之间的相关性,最好的方法是什么?
我不希望输出中使用NaN来计算行数,而内置的pandas相关函数会这样做,但我也希望输出pvalue或标准错误,而内置的相关函数不会这样做。
SciPy似乎被NaN赶上了,尽管我相信它确实报告了重要性。
数据示例:

pxy2qtax

pxy2qtax1#

要一次计算所有p值,可以使用**calculate_pvalues函数**(代码如下):

df = pd.DataFrame({'A':[1,2,3], 'B':[2,5,3], 'C':[5,2,1], 'D':['text',2,3] })
calculate_pvalues(df)

输出类似于corr()(但具有p值):

A       B       C
    A       0  0.7877  0.1789
    B  0.7877       0  0.6088
    C  0.1789  0.6088       0

详细数据:
*列D自动被忽略,因为它包含文本。

  • p值四舍五入至4位小数
  • 您可以使用子集来指示确切的列:calculate_pvalues(df[['A','B','C']]

以下是***函数的***代码:

from scipy.stats import pearsonr
import pandas as pd

def calculate_pvalues(df):
    dfcols = pd.DataFrame(columns=df.columns)
    pvalues = dfcols.transpose().join(dfcols, how='outer')
    for r in df.columns:
        for c in df.columns:
            tmp = df[df[r].notnull() & df[c].notnull()]
            pvalues[r][c] = round(pearsonr(tmp[r], tmp[c])[1], 4)
    return pvalues
qybjjes1

qybjjes12#

统计学显著性以星号表示:

from scipy.stats import pearsonr
import numpy as np
rho = df.corr()
pval = df.corr(method=lambda x, y: pearsonr(x, y)[1]) - np.eye(*rho.shape)
p = pval.applymap(lambda x: ''.join(['*' for t in [.05, .01, .001] if x<=t]))
rho.round(2).astype(str) + p

ubby3x7f

ubby3x7f3#

您可以使用scipy.stats相关函数来获取p值。
例如,如果您要寻找像Pearson相关性这样的相关性,则可以使用Pearsonr函数。

from scipy.stats import pearsonr
pearsonr([1, 2, 3], [4, 3, 7])

提供输出

(0.7205766921228921, 0.48775429164459994)

其中,元组中的第一个值是相关值,第二个值是p值。
在您的示例中,可以使用panda的dropna函数先删除NaN值。

df_clean = df[['column1', 'column2']].dropna()
pearsonr(df_clean['column1'], df_clean['column2'])
f8rj6qna

f8rj6qna4#

@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

格式
与 stats 函数 的 结果 相同 :

#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']

格式
结果 ρ :

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]]

格式

bvjveswy

bvjveswy5#

在panda v0.24.0中,method参数被添加到corr中。现在,您可以执行以下操作:
第一个
请注意所需的np.eye(len(df.columns))解决方案,因为自相关始终设置为1.0(参见https://github.com/pandas-dev/pandas/issues/25726)。

dgenwo3n

dgenwo3n6#

我试过用一个函数来总结逻辑,这可能不是最有效的方法,但会提供类似于Pandasdf.corr()的输出。要使用这个方法,只需在代码中放入以下函数,并调用它提供 Dataframe 对象ie. 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)

我用Pandasv0.18.1测试过

a0zr77ik

a0zr77ik7#

这是oztalha编写的非常有用的代码。我只是在r不重要的地方更改了格式(四舍五入为2位数)。

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
neekobn8

neekobn88#

@toto_tico和@Somendra-joshi给出了很好的答案。但是,它会丢弃不必要的NAs值。在这个代码片段中,我只是丢弃了属于当前正在计算的相关性的NAs。在实际的corr实现中,它们也是这样做的。

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
8yparm6h

8yparm6h9#

在使用列表解析的单行代码中:

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

相关问题