熊猫滚动窗口Spearman相关

斯塔夫罗普

我想使用滚动窗口来计算DataFrame的两列之间的Spearman和/或Pearson相关。

我试过了df['corr'] = df['col1'].rolling(P).corr(df['col2'])
(P是窗口大小)

但我似乎无法定义该方法。(添加method='spearman'为参数会产生错误:

File "main.py", line 29, in __init__
_df['corr'] = g['col1'].rolling(P).corr(g['col2'], method = corr_function)
File "~\Python36\lib\site-packages\pandas\core\window.py", line 1287, in corr
**kwargs)
File "~\Python36\lib\site-packages\pandas\core\window.py", line 1054, in corr
_get_corr, pairwise=bool(pairwise))
File "~\Python36\lib\site-packages\pandas\core\window.py", line 1866, in _flex_binary_moment
return f(X, Y)
File "~\Python36\lib\site-packages\pandas\core\window.py", line 1051, in _get_corr
return a.cov(b, **kwargs) / (a.std(**kwargs) * b.std(**kwargs))
File "~\Python36\lib\site-packages\pandas\core\window.py", line 1280, in cov
ddof=ddof, **kwargs)
File "~\Python36\lib\site-packages\pandas\core\window.py", line 1020, in cov
_get_cov, pairwise=bool(pairwise))
File "~\Python36\lib\site-packages\pandas\core\window.py", line 1866, in _flex_binary_moment
return f(X, Y)
File "~\Python36\lib\site-packages\pandas\core\window.py", line 1015, in _get_cov
center=self.center).count(**kwargs)
TypeError: count() got an unexpected keyword argument 'method'

公平地说,我没想到这会起作用,因为阅读文档后,没有提及rolling.corr支持方法...

考虑到数据帧很大(> 1000万行),关于如何执行此操作的任何建议?

兰格·哈尔

rolling.corr皮尔逊(Pearson),所以您可以使用它。对于Spearman,请使用以下内容:

import pandas as pd
from numpy.lib.stride_tricks import as_strided
from numpy.lib import pad
import numpy as np
def rolling_spearman(seqa, seqb, window):
    stridea = seqa.strides[0]
    ssa = as_strided(seqa, shape=[len(seqa) - window + 1, window], strides=[stridea, stridea])
    strideb = seqa.strides[0]
    ssb = as_strided(seqb, shape=[len(seqb) - window + 1, window], strides =[strideb, strideb])
    ar = pd.DataFrame(ssa)
    br = pd.DataFrame(ssb)
    ar = ar.rank(1)
    br = br.rank(1)
    corrs = ar.corrwith(br, 1)
    return pad(corrs, (window - 1, 0), 'constant', constant_values=np.nan)

例如:

In [144]: df = pd.DataFrame(np.random.randint(0,1000,size=(10,2)), columns = list('ab'))
In [145]: df['corr'] = rolling_spearman(df.a, df.b, 4)
In [146]: df
Out[146]: 
     a    b  corr
0  429  922   NaN
1  618  382   NaN
2  476  517   NaN
3  267  536  -0.8
4  582  844  -0.4
5  254  895  -0.4
6  583  974   0.4
7  687  298  -0.4
8  697  447  -0.6
9  383   35   0.4

说明:numpy.lib.stride_tricks.as_strided是一种骇人听闻的方法,在这种情况下,我们可以看到序列的视图,该序列看起来像是2d数组,其中包含正在查看的序列的滚动窗口部分。

从那时起,这很简单。Spearman相关性等效于将序列转换为秩,并采用Pearson相关系数。熊猫有帮助,快速地实现了在DataFrames上逐行执行此操作然后最后,我们Series用NaN值填充结果的开头(因此您可以将其作为列添加到数据框或其他内容中)。

(个人说明:我花了很长时间试图弄清楚如何用numpy和scipy有效地做到这一点,然后才意识到您需要的一切都已经在熊猫中了!!)。

为了显示该方法相对于仅循环滑动窗口的速度优势,我制作了一个名为srsmall.pycontains的小文件

import pandas as pd
from numpy.lib.stride_tricks import as_strided
import scipy.stats
from numpy.lib import pad
import numpy as np

def rolling_spearman_slow(seqa, seqb, window):
    stridea = seqa.strides[0]
    ssa = as_strided(seqa, shape=[len(seqa) - window + 1, window], strides=[stridea, stridea])
    strideb = seqa.strides[0]
    ssb = as_strided(seqb, shape=[len(seqb) - window + 1, window], strides =[strideb, strideb])
    corrs = [scipy.stats.spearmanr(a, b)[0] for (a,b) in zip(ssa, ssb)]
    return pad(corrs, (window - 1, 0), 'constant', constant_values=np.nan)

def rolling_spearman_quick(seqa, seqb, window):
    stridea = seqa.strides[0]
    ssa = as_strided(seqa, shape=[len(seqa) - window + 1, window], strides=[stridea, stridea])
    strideb = seqa.strides[0]
    ssb = as_strided(seqb, shape=[len(seqb) - window + 1, window], strides =[strideb, strideb])
    ar = pd.DataFrame(ssa)
    br = pd.DataFrame(ssb)
    ar = ar.rank(1)
    br = br.rank(1)
    corrs = ar.corrwith(br, 1)
    return pad(corrs, (window - 1, 0), 'constant', constant_values=np.nan)

并比较性能:

In [1]: import pandas as pd
In [2]: import numpy as np
In [3]: from srsmall import rolling_spearman_slow as slow
In [4]: from srsmall import rolling_spearman_quick as quick
In [5]: for i in range(6):
   ...:     df = pd.DataFrame(np.random.randint(0,1000,size=(10*(10**i),2)), columns=list('ab'))
   ...:     print len(df), " rows"
   ...:     print "quick: ",
   ...:     %timeit quick(df.a, df.b, 4)
   ...:     print "slow: ",
   ...:     %timeit slow(df.a, df.b, 4)
   ...:     
10  rows
quick: 100 loops, best of 3: 3.52 ms per loop
slow: 100 loops, best of 3: 3.2 ms per loop
100  rows
quick: 100 loops, best of 3: 3.53 ms per loop
slow: 10 loops, best of 3: 42 ms per loop
1000  rows
quick: 100 loops, best of 3: 3.82 ms per loop
slow: 1 loop, best of 3: 430 ms per loop
10000  rows
quick: 100 loops, best of 3: 7.47 ms per loop
slow: 1 loop, best of 3: 4.33 s per loop
100000  rows
quick: 10 loops, best of 3: 50.2 ms per loop
slow: 1 loop, best of 3: 43.4 s per loop
1000000  rows
quick: 1 loop, best of 3: 404 ms per loop
slow:

在一百万行(在我的机器上)上,快速(熊猫)版本在不到半秒的时间内运行。上面没有显示,但是1000万只用了8.43秒。速度较慢的设备仍在运行,但假设线性增长仍在继续,则1M大约需要7分钟,而1000万则需要一个小时以上。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章