Pandas - 在多个列上使用`.rolling()`

7
考虑一个看起来像下面这样的pandas DataFrame
      A     B     C
0  0.63  1.12  1.73
1  2.20 -2.16 -0.13
2  0.97 -0.68  1.09
3 -0.78 -1.22  0.96
4 -0.06 -0.02  2.18

我想使用函数.rolling()来执行以下计算,对于t = 0,1,2

  • 选择从tt+2的行
  • 从所有列中获取这3行中包含的9个值。将此集合称为S
  • 计算S的第75个百分位数(或其他关于S的摘要统计信息)


例如,对于t = 1,我们有 S = { 2.2 , -2.16, -0.13, 0.97, -0.68, 1.09, -0.78, -1.22, 0.96 },第75个百分位数是0.97。

我找不到一种方法让.rolling()工作,因为它显然逐列进行操作。现在我依靠for循环,但速度非常慢。

你有更有效的方法建议吗?


这个怎么样?(https://pandas.pydata.org/pandas-docs/version/0.22/generated/pandas.DataFrame.rolling.html) - Rushabh Mehta
5
你的声望足够高,应该知道不要将数据以图片形式发布 - BENY
@RushabhMehta:这正是我想使用的函数,但我不明白如何将3列A、B和C中的数据一起提取出来计算百分位数。 - Abramodj
1
请阅读以下内容:https://dev59.com/O2Ij5IYBdhLWcg3wk182将其转化为代码格式。 - user3483203
我不喜欢那些涉及到重塑事物的答案。我使用了 scipy.ndimage.generic_filter 来正确地完成这个任务,尽管需要一些试错才能达到与 Pandas 的 rollingcenter=False 效果相同的效果。 - Ahmed Fasih
2个回答

4

一个解决方案是将数据 stack 然后将您的窗口大小乘以列数并通过列数切片结果。另外,由于您需要一个前瞻性窗口,请反转堆叠的 DataFrame 的顺序。

wsize = 3
cols = len(df.columns)

df.stack(dropna=False)[::-1].rolling(window=wsize*cols).quantile(0.75)[cols-1::cols].reset_index(-1, drop=True).sort_index()

输出:

0    1.12
1    0.97
2    0.97
3     NaN
4     NaN
dtype: float64

在许多列和较小的窗口情况下:
import pandas as pd
import numpy as np

wsize = 3
df2 = pd.concat([df.shift(-x) for x in range(wsize)], 1)
s_quant = df2.quantile(0.75, 1)

# Only necessary if you need to enforce sufficient data. 
s_quant[df2.isnull().any(1)] = np.NaN

输出结果: s_quant

0    1.12
1    0.97
2    0.97
3     NaN
4     NaN
Name: 0.75, dtype: float64

这并不等同,因为它会计算更多次的统计数据。这是因为窗口每次移动一个条目而不是每三个移动一次。在我的真实数据集中,我有比3更多的列,因此从计算的角度来看,这实际上会产生巨大的差异。 - Abramodj
@Abramodj 我发现处理1000倍列数需要8倍的时间。因此,只要您有合理数量的列,多余的列可能不会影响您的程序性能。我不确定您是否需要一个极高性能的解决方案,还是只需要解决问题的方案。让我看看我能做些什么。 - ALollz
实际上,我有超过10,000列。 - Abramodj
大约有一千个,所以在这种情况下for循环实际上是可行的。我只是想了解是否可以做到这一点,因为在其他情况下这可能非常有用。 - Abramodj
1
@ALollz 我认为你应该在stack中指定dropna=True,否则窗口大小将保持一致。 - FLab
是的,那是个笔误...应该是:stack(dropna=False)。 - FLab

0
你可以使用NumPy的ravel函数。不过,你可能仍需要使用for循环。
for i in range(0,3):
    print(df.iloc[i:i+3].values.ravel())

如果您的 t 步长为 3 秒,您可以使用 numpy 的 reshape 函数创建一个 n*9 数据框。

这是我目前正在使用的解决方案,它需要一个for循环。它不像“rolling”那样快,因为它没有向量化。 - Abramodj
2
@Abramodj,你试过这个吗: x = pd.concat([df, df.shift(-1),df.shift(-2)], axis=1) 然后 x['m'] = x.mean(axis=1)。对于四分位数,你可以使用 x['q3'] = x.quantile(0.75, axis=1) - Dhanush1215

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接