如何计算与Python中性能最好的p值的相关性?

如何计算与Python中性能最好的p值的相关性?,python,pandas,correlation,Python,Pandas,Correlation,我想创建数据与其p值的相关性。目前我正在使用Pandas及其corr方法对DataFrame。问题是这种关联方法没有提供p值 所以我试着用两个答案来回答这个问题:。两种解决方案都使用scipy.stats.pearsonr方法进行计算。我无法使用此解决方案(),因为它会删除我的大部分数据集。我的下一次尝试是这个()。它得到了我想要的结果,但需要大量的时间 相比之下:我的pandas-only关联从创建数据帧到计算关联大约需要4秒。解决方案2大约需要6分钟才能返回结果。我的猜测是,新创建的Data

我想创建数据与其p值的相关性。目前我正在使用
Pandas
及其
corr
方法对
DataFrame
。问题是这种关联方法没有提供p值

所以我试着用两个答案来回答这个问题:。两种解决方案都使用
scipy.stats.pearsonr
方法进行计算。我无法使用此解决方案(),因为它会删除我的大部分数据集。我的下一次尝试是这个()。它得到了我想要的结果,但需要大量的时间

相比之下:我的pandas-only关联从创建
数据帧到计算关联大约需要4秒。解决方案2大约需要6分钟才能返回结果。我的猜测是,新创建的
DataFrame
需要大量的计算,因此我的数据集需要计算时间

有没有更有效的方法来计算这个结果
corr
也必须在后台执行此操作,以处理我的
None
值,因此必须有更好的解决方案


我的测试数据集有500行,每行有550个值。正如我所说,你也有
None
值。

解决你的问题需要数学和编程。由于
df.corr
在您的案例中很快返回,因此我将重点关注p值:

程序设计
scipy.stats.pearsonr(col\u x,col\u y)
不喜欢与NaN打交道。因此,对于每一对列,必须删除其中一个或两个元素都为NaN的所有行。您有550列,因此550*549/2=150975对。您最好确保您的循环非常有效

如果您查看它的,
DataFrame.corr
速度如此之快有两个原因:

  • 它用Cython编码,并在全局解释器锁(GIL)之外运行。这意味着循环在裸金属C中,因此速度非常快
  • 它实现自己的方差算法(),不依赖于
    scipy.stats
    。该算法的复杂度为
    O(n*m^2)
    ,其中
    n
    是行数,
    m
    是列数
数学 本文件提供了关于如何计算p值的说明:

r = <Pearson correlation coefficient>
dist = scipy.stats.beta(n/2 - 1, n/2 - 1, loc=-1, scale=2)
p = 2 * dist.cdf(-abs(r))
幸运的是,
betainc
函数是矢量化的,因此如果我们传入3个与参数长度相同的数组,它将返回一个数组作为输出


解决方案1 此解决方案采用本机Python,可在数据集(500*550)上提供合理的性能。在我的2014 iMac上使用16GB内存大约需要30秒:

导入scipy.special
def corr1(df):
mask=df.notna().to_numpy()
corr=df.corr()to_numpy()
n_行,n_列=df.shape
#初始化返回数组以获得更好的性能
长度=整数(n列*(n列-1)/2)
idx=np.empty((长度,2),dtype=object)
correl=np.empty(长度,dtype=np.float64)
count=np.empty(长度,数据类型=np.uint64)
#对于2-列组合,设'n'为其
#元素都是非NaN的。我们以后需要它来计算
#p值
k=-1
对于范围内的i(n_cols):
对于范围(i)中的j:
n=0
对于范围内的行(n_行):
如果掩码[行,i]和掩码[行,j]为0,则n+=1
k+=1
idx[k]=(i,j)
correl[k]=corr[i,j]
计数[k]=n
#p值可通过不完全β函数(betainc)获得
#我们只需要稍微按摩一下输入
阿尔法=计数/2-1
x=(相关系数+1)/2
x=np.式中(correl<0,x,1-x)
p=2*scipy.special.betainc(α,α,x)
返回idx,correl,p
#将返回值转换为正确的格式
索引,corr,p=corr1(df)
idx=pd.MultiIndex.from_元组(
[(索引中i,j的df.columns[i],df.columns[j])]+
[(索引中i的df.columns[j],df.columns[i]),j]
)
full_index=pd.MultiIndex.from_乘积([df.columns,df.columns])
结果=pd.DataFrame({
“corr”:np.tile(corr,2),
“p”:np.tile(p,2)
},index=idx).reindex(完整索引).unstack()
解决方案2 对于绝对最快的解决方案,您必须用Cython编写它。这将执行时间从30秒减少到5秒。我确信进一步的优化是可能的(但我懒得去探索它们)。取舍是一个更复杂的构建和部署过程

首先,确保您有一个C编译器。然后安装Cython软件包:

pip install cython
接下来,创建两个文件:
setup.py
utility.pyx

#################################################
#setup.py
#################################################
从distutils.core导入设置,扩展
从Cython.Build导入cythonize
进口numpy
编译器\u指令={
“语言水平”:“3”
}
设置(
ext_modules=cythonize(“utility.pyx”,compiler_指令=compiler_指令),
include_dirs=[numpy.get_include()]
)
#################################################
#实用程序.pyx
#################################################
进口赛昂
从cython进口Py\u ssize\t
将numpy作为np导入
来自numpy cimport(
恩达拉,
浮球,
uint8_t,
uint64_t,
)
进口特殊商品
@cython.boundscheck(错误)
@cython.wrapparound(假)
def corr2(对象df):
#这些变量进入“nogil”上下文(即进入C语言),因此
#必须是静态类型
cdef:
Py_-ssize_t n_行,n列,i,j,行,n,k
ndarray[uint8_t,ndim=2]掩码
ndarray[float64_t,ndim=2]corr
#
ndarray[uint64_t,ndim=2]idx
ndarray[float64_t,ndim=1]相关
ndarray[uint64_t,ndim=1]计数
#我们仍然在Python领域,因此可以完全访问Python中的所有函数
#努比和熊猫。将数据帧转换为二维numpy阵列
#提供了一个巨大的速度提升
pip install cython