【问题标题】:Pandas rolling window to return an arrayPandas 滚动窗口返回一个数组
【发布时间】:2018-05-08 23:37:34
【问题描述】:

这是一个示例代码。

df = pd.DataFrame(np.random.randn(10, 2), columns=list('AB'))
df['C'] = df.B.rolling(window=3)

输出:

           A         B                                       C
0 -0.108897  1.877987  Rolling [window=3,center=False,axis=0]
1 -1.276055 -0.424382  Rolling [window=3,center=False,axis=0]
2  1.578561 -1.094649  Rolling [window=3,center=False,axis=0]
3 -0.443294  1.683261  Rolling [window=3,center=False,axis=0]
4  0.674124  0.281077  Rolling [window=3,center=False,axis=0]
5  0.587773  0.697557  Rolling [window=3,center=False,axis=0]
6 -0.258038 -1.230902  Rolling [window=3,center=False,axis=0]
7 -0.443269  0.647107  Rolling [window=3,center=False,axis=0]
8  0.347187  0.753585  Rolling [window=3,center=False,axis=0]
9 -0.369179  0.975155  Rolling [window=3,center=False,axis=0]

我希望我的“C”列是一个类似 [0.1231, -1.132, 0.8766] 的数组。 我尝试使用滚动应用,但没有成功。

预期输出:

       A         B                 C
0 -0.108897  1.877987  []
1 -1.276055 -0.424382  []
2  1.578561 -1.094649  [-1.094649, -0.424382, 1.877987]
3 -0.443294  1.683261  [1.683261, -1.094649, -0.424382]
4  0.674124  0.281077  [0.281077, 1.683261, -1.094649]
5  0.587773  0.697557  [0.697557, 0.281077, 1.683261]
6 -0.258038 -1.230902  [-1.230902, 0.697557, 0.281077]
7 -0.443269  0.647107  [0.647107, -1.230902, 0.697557]
8  0.347187  0.753585  [0.753585, 0.647107, -1.230902]
9 -0.369179  0.975155  [0.975155, 0.753585, 0.647107]

【问题讨论】:

  • 不,这是不可能的。每个滚动窗口计算必须返回一个聚合结果。如果您的函数不能保证这一点,那么您可能需要考虑其他选项。
  • 谢谢。 loc/iloc/ix/others 可以吗?我想回顾一个窗口并获取数组。
  • 我想看看你的实际功能和该数据的预期输出。你到底想做什么?显然,除非我知道您的实际功能是做什么的,否则我无法帮助您。
  • 当然。我试图通过数组乘以 X 因子。例如:[ 1, 2, 3, 4] 将在因子为 1.5 时返回 [ 1.5, 3, 4.5, 6]。我试图提供一个清晰的数据框
  • 好的。为什么需要滚动窗口?每个窗口计算如何相互关联?它们如何适应最终的数据框?比如说,对于[1, 2, 3, 4, 5, 6, 7, 8]window_size=3 的列,你想要的输出是什么? (这是非常重要的信息,我还希望您编辑您的问题...谢谢)

标签: python pandas numpy dataframe


【解决方案1】:

由于 pandas 1.1 滚动对象是可迭代的,所以你可以只使用列表构造函数:

df['C'] = list(df.B.rolling(window=3))

或者,如果您想将窗口作为列表而不是 Series 的做法:

df['C'] = [window.to_list() for window in df.B.rolling(window=3)]

这是简短,您可以使用rolling 函数的所有便捷参数。

【讨论】:

  • 正是我所需要的,您可以用任何列表替换window.to_list() 并返回列表列表,您可以轻松地将其转换为数据框等。
  • 这是 2021 年的最佳答案。
【解决方案2】:

你可以使用np.stride_tricks:

import numpy as np
as_strided = np.lib.stride_tricks.as_strided  

df

          A         B
0 -0.272824 -1.606357
1 -0.350643  0.000510
2  0.247222  1.627117
3 -1.601180  0.550903
4  0.803039 -1.231291
5 -0.536713 -0.313384
6 -0.840931 -0.675352
7 -0.930186 -0.189356
8  0.151349  0.522533
9 -0.046146  0.507406

win = 3  # window size

# https://stackoverflow.com/a/47483615/4909087
v = as_strided(df.B, (len(df) - (win - 1), win), (df.B.values.strides * 2))

v
array([[ -1.60635669e+00,   5.10129842e-04,   1.62711678e+00],
       [  5.10129842e-04,   1.62711678e+00,   5.50902812e-01],
       [  1.62711678e+00,   5.50902812e-01,  -1.23129111e+00],
       [  5.50902812e-01,  -1.23129111e+00,  -3.13383794e-01],
       [ -1.23129111e+00,  -3.13383794e-01,  -6.75352179e-01],
       [ -3.13383794e-01,  -6.75352179e-01,  -1.89356194e-01],
       [ -6.75352179e-01,  -1.89356194e-01,   5.22532550e-01],
       [ -1.89356194e-01,   5.22532550e-01,   5.07405549e-01]])

df['C'] = pd.Series(v.tolist(), index=df.index[win - 1:])
df

          A         B                                                  C
0 -0.272824 -1.606357                                                NaN
1 -0.350643  0.000510                                                NaN
2  0.247222  1.627117  [-1.606356691642917, 0.0005101298424200881, 1....
3 -1.601180  0.550903  [0.0005101298424200881, 1.6271167809032248, 0....
4  0.803039 -1.231291  [1.6271167809032248, 0.5509028122535129, -1.23...
5 -0.536713 -0.313384  [0.5509028122535129, -1.2312911105674484, -0.3...
6 -0.840931 -0.675352  [-1.2312911105674484, -0.3133837943758246, -0....
7 -0.930186 -0.189356  [-0.3133837943758246, -0.6753521794378446, -0....
8  0.151349  0.522533  [-0.6753521794378446, -0.18935619377656243, 0....
9 -0.046146  0.507406  [-0.18935619377656243, 0.52253255045267, 0.507...

【讨论】:

  • 天哪,我一直在这里stackoverflow.com/a/46199050/4800652,想回答你已经发布了
  • @Bharath 是的...我从这里得到了一些帮助:stackoverflow.com/a/47483615/4909087
  • 非常感谢!这也适用于前瞻性吗?喜欢将下 n 行作为数组获取?
  • @revendar 嗯...我不是 100% 确定,但我认为 stride_tricks 代码是适用的。之后,您只需要弄清楚如何将其插入数据框中(例如,您将如何移动数据以及移动多少)。希望这是有道理的。
  • @cᴏʟᴅsᴘᴇᴇᴅ 如何看待压缩方法?
【解决方案3】:

让我们使用这种带有滚动应用技巧的 pandas 方法:

df = pd.DataFrame(np.random.randn(10, 2), columns=list('AB'))
list_of_values = []
df.B.rolling(3).apply(lambda x: list_of_values.append(x.values) or 0, raw=False)
df.loc[2:,'C'] = pd.Series(list_of_values).values
df

输出:

          A         B                                                                  C
0  1.610085  0.354823                                                                NaN
1 -0.241446 -0.304952                                                                NaN
2  0.524812 -0.240972  [0.35482336179318674, -0.30495156795594963, -0.24097191924555197]
3  0.767354  0.281625   [-0.30495156795594963, -0.24097191924555197, 0.2816249674055174]
4 -0.349844 -0.533781    [-0.24097191924555197, 0.2816249674055174, -0.5337811449574766]
5 -0.174189  0.133795     [0.2816249674055174, -0.5337811449574766, 0.13379518286397707]
6  2.799437 -0.978349    [-0.5337811449574766, 0.13379518286397707, -0.9783488211443795]
7  0.250129  0.289782     [0.13379518286397707, -0.9783488211443795, 0.2897823417165459]
8 -0.385259 -0.286399    [-0.9783488211443795, 0.2897823417165459, -0.28639931887491943]
9 -0.755363 -1.010891    [0.2897823417165459, -0.28639931887491943, -1.0108913605575793]

【讨论】:

  • 不错的把戏。它也适用于raw=True,然后您可以直接附加x,而无需将系列转换为np.array
  • 我的意思是这一行:df.B.rolling(3).apply(lambda x: list_of_values.append(x) or 0, raw=True)
【解决方案4】:

也许 zipping 对您的情况也有帮助,即

def get_list(x,m) : return list(zip(*(x[i:] for i in range(m))))

# get_list(df['B'],3) would return 

[(-1.606357, 0.0005099999999999999, 1.627117),
 (0.0005099999999999999, 1.627117, 0.5509029999999999),
 (1.627117, 0.5509029999999999, -1.231291),
 (0.5509029999999999, -1.231291, -0.313384),
 (-1.231291, -0.313384, -0.6753520000000001),
 (-0.313384, -0.6753520000000001, -0.189356),
 (-0.6753520000000001, -0.189356, 0.522533),
 (-0.189356, 0.522533, 0.507406)]

df['C'] = pd.Series(get_list(df['B'],3), index=df.index[3 - 1:])
# Little help form @coldspeed

print(df)

          A         B                                                  C
0 -0.272824 -1.606357                                                NaN
1 -0.350643  0.000510                                                NaN
2  0.247222  1.627117       (-1.606357, 0.0005099999999999999, 1.627117)
3 -1.601180  0.550903  (0.0005099999999999999, 1.627117, 0.5509029999...
4  0.803039 -1.231291          (1.627117, 0.5509029999999999, -1.231291)
5 -0.536713 -0.313384         (0.5509029999999999, -1.231291, -0.313384)
6 -0.840931 -0.675352        (-1.231291, -0.313384, -0.6753520000000001)
7 -0.930186 -0.189356        (-0.313384, -0.6753520000000001, -0.189356)
8  0.151349  0.522533         (-0.6753520000000001, -0.189356, 0.522533)
9 -0.046146  0.507406                    (-0.189356, 0.522533, 0.507406)

【讨论】:

    【解决方案5】:

    在较新的 numpy 版本中,有一个 sliding_window_view()

    它提供与as_strided() 数组相同的功能,但语法更透明。

    import pandas as pd
    from numpy.lib.stride_tricks import sliding_window_view
    
    x = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9])
    sliding_window_view(x, 3)
    
    >>>
    array([[1, 2, 3],
           [2, 3, 4],
           [3, 4, 5],
           [4, 5, 6],
           [5, 6, 7],
           [6, 7, 8],
           [7, 8, 9]])
    

    但请注意,pandas rolling 会在开始时添加一些 nans (window_size - 1),因为它使用填充。你可以这样检查:

    x.rolling(3).sum()
    
    >>>
    0     NaN
    1     NaN
    2     6.0
    3     9.0
    4    12.0
    5    15.0
    6    18.0
    7    21.0
    8    24.0
    dtype: float64
    
    sliding_window_view(x, 3).sum(axis=1)
    >>>
    array([ 6,  9, 12, 15, 18, 21, 24])
    

    所以真正对应的数组应该是:

    c = np.array([[nan, nan,  1.],
                  [nan,  1.,  2.],
                  [ 1.,  2.,  3.],
                  [ 2.,  3.,  4.],
                  [ 3.,  4.,  5.],
                  [ 4.,  5.,  6.],
                  [ 5.,  6.,  7.],
                  [ 6.,  7.,  8.],
                  [ 7.,  8.,  9.]])
    
    c.sum(axis=1)
    >>>
    array([nan, nan,  6.,  9., 12., 15., 18., 21., 24.])
    

    【讨论】:

      【解决方案6】:

      这是另一种方式:

      df.join(pd.concat(df['B'].rolling(window=3),axis=1).apply(lambda x: x.dropna().tolist()).reset_index(drop=True).loc[2:].rename('C'))
      

      【讨论】:

        猜你喜欢
        • 2021-03-13
        • 2016-08-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-12
        • 1970-01-01
        相关资源
        最近更新 更多