代码之家  ›  专栏  ›  技术社区  ›  Engineero

从大熊猫滚动窗口生成值组合

  •  4
  • Engineero  · 技术社区  · 6 年前

    对于数据帧中的每一行,我需要创建列的两个值的每个组合 a 从一个三天的滑动窗口到那排 .我的数据框架如下:

    import pandas as pd    
    df = pd.DataFrame({'a': [1, 2, 3, 4, 5]},
                       index=[pd.Timestamp('20180101'),
                              pd.Timestamp('20180102'),
                              pd.Timestamp('20180103'),
                              pd.Timestamp('20180105'),
                              pd.Timestamp('20180106')])
    

    请注意,时间索引参差不齐(行之间的间隔不一致)。组合应该是:

    row0: None
    row1: [(1, 2)]
    row2: [(1, 2), (1, 3), (2, 3)]
    row4: [(3, 4)]
    row5: [(4, 5)]
    

    我可以很容易地做到这一点 没有 窗户,就用 itertools.combinations 生成列的两个元素的每个组合 使用:

    import itertools as it
    combos = it.combinations(df['a'], 2)
    for c in combos:
        print(c)
    # (1, 2)
    # (1, 3)
    # (1, 4)
    # (1, 5)
    # etc.
    

    但我需要我的应用程序的窗口版本。到目前为止我最好的选择是 df.rolling .我可以做一些简单的事情,比如在三天的窗口中求和元素,比如:

    df.rolling('3d').sum()
    # get [1, 3, 6, 7, 9] which we expect
    

    但我似乎无法在滚动窗口上执行更复杂的操作(或返回比操作实数更复杂的类型)。


    问题

    我怎么用 df.滚动 在滚动的窗口上进行组合?或者有其他的工具来做这个吗?


    尝试

    到目前为止我的想法是有某种方法可以使用 df.滚动 df.apply 随着 it.combinations 为数据帧中的每个窗口生成迭代器,然后将该迭代器插入到数据帧的新列中。比如:

    df.rolling('3d').apply(lambda x: it.combinations(x, 2))
    

    它给出了一个 TypeError 以下内容:

    类型错误:必须是实数,而不是ITertools.combinations

    因为 df.rolling.apply 要求其参数返回单个实值,而不是对象或列表。

    我也试过用 IT.组合 直接在滚动窗口上:

    it.combinations(df.rolling('3d'), 2)
    

    它给出:

    keyror:'找不到列:0'

    如果我选择列 明确地:

    it.combinations(df.rolling('3d')['a'], 2)
    

    我得到:

    例外:列A已选定

    那么有没有一种方法可以定义一个我可以调用的函数 df.应用 它会将滚动窗口上的迭代器插入到数据帧每一行的新列中吗?我甚至可以在传递给的函数中对当前行以外的行进行操作吗? apply 是吗?

    1 回复  |  直到 6 年前
        1
  •  4
  •   DSM    6 年前

    好吧,这是一个黑客,但可能有用。

    我们要做的就是重复使用df.rolling的开窗设备。我们可以尝试查看代码的一些非公共部分,但是让我们利用这样一个事实:在返回float之前,我们可以强制在apply中调用函数:

    In [28]: dummy = df.rolling("3d")["a"].apply((lambda x: print(x) or 0), raw=False)
    2018-01-01    1.0
    dtype: float64
    2018-01-01    1.0
    2018-01-02    2.0
    dtype: float64
    2018-01-01    1.0
    2018-01-02    2.0
    2018-01-03    3.0
    dtype: float64
    2018-01-03    3.0
    2018-01-05    4.0
    dtype: float64
    2018-01-05    4.0
    2018-01-06    5.0
    dtype: float64
    

    所以:

    In [29]: roll_slices = []
    
    In [30]: dummy = df.rolling("3d")["a"].apply((lambda x: roll_slices.append(list(combinations(x, 2))) or 0), raw=False)
    
    In [31]: roll_slices
    Out[31]: 
    [[],
     [(1.0, 2.0)],
     [(1.0, 2.0), (1.0, 3.0), (2.0, 3.0)],
     [(3.0, 4.0)],
     [(4.0, 5.0)]]
    

    之后你就可以随心所欲了。