【问题标题】:Rolling sum filling intermediate values on grouped DataFrames滚动和填充分组数据帧上的中间值
【发布时间】:2017-08-24 23:53:38
【问题描述】:

我现在正在将我的一个 Spark 项目迁移到 Pandas,我遇到的一个问题是在每个组内的 pandas 中实现一个类似滚动求和的函数。

假设我有:

key time value
A   1    10
A   2    20
A   4    30
A   8    10
B   1    15
B   2    30
B   3    15

我想首先按key 分组,然后计算一个类似滚动和的函数,该函数填充value 上相对于time 的中间时隙。例如,如果窗口大小为 2,我想要的输出将是:

key time output
A   1    10    
A   2    30 (10+20)    
A   3    30 (10+20+0)
A   4    50 (20+0+30) 
A   5    30 (0+30+0)
A   6    30 (the same as above)
A   8    10 (7 is 0 so it is omitted)
A   9    10
A   10   10
B   1    15
B   2    45
B   3    60
B   4    45
B   5    15

我在group by 和apply 上挣扎了整整一个下午。有没有聪明的方法来做到这一点?在 spark 中,我可以 collect_list 然后 select 一个 udf 到 time 和 value 来执行此操作,但 pandas 的想法似乎与 Spark 不同。

谢谢!

【问题讨论】:

  • 您似乎在“创建”数据。目前尚不清楚 A 的输出时间如何从 1 到 5,而 B 的时间只有 1 到 4。
  • @COLDSPEED 不清楚,记录的最后一个值持续1个时间槽,因为窗口大小为1。
  • 您的结果是窗口大小为 2 还是 3?

标签: pandas


【解决方案1】:

IIUIC,这是一种方法。

首先用新的时间窗口创建dff

In [1458]: dff = (df.groupby('key')
                    .apply(lambda x: pd.Series(range(x.time.min(), x.time.max()+2)))
                    .reset_index(name='time').drop('level_1', 1))
In [1459]: dff
Out[1459]:
  key  time
0   A     1
1   A     2
2   A     3
3   A     4
4   A     5
5   B     1
6   B     2
7   B     3
8   B     4

然后,在之前的df 上合并,在key 上进行分组,使用shift 添加当前和之前的value

In [1460]: dff.assign(ouput=dff.merge(df, how='left')
                               .fillna(0).groupby('key').value
                               .apply(lambda x: x+x.shift().fillna(0)))
Out[1460]:
  key  time  ouput
0   A     1   10.0
1   A     2   30.0
2   A     3   20.0
3   A     4   30.0
4   A     5   30.0
5   B     1   15.0
6   B     2   45.0
7   B     3   45.0
8   B     4   15.0

【讨论】:

  • 谢谢,但是不知道这种做法有两个问题:第一,它生成从time.min到time.max的连续时间槽,如果时间是1, 2, 8, 16,就会有产生了大量浪费的插槽。其次,shift 仅适用于窗口大小为 1 的情况,但并非总是如此...
  • 我现在更改了问题描述中的示例数据。
【解决方案2】:

解决此问题的一种方法是在某个组中生成time 的整个范围,然后在之后执行dropna

def make_rolling_sum(key, group, window):
    time_range = range(group['time'].min(), group['time'].max() + 1 + window, )
    df = group.set_index('time').reindex(time_range)
    result = df.rolling(window, min_periods=1).sum()
    result['key'] = key  # the reindex drops a lot of NaN's in this column
    return result.dropna().reset_index().reindex(columns=group.columns)

window = 3
pd.concat((make_rolling_sum(*group, window)for group in df.groupby('key')), ignore_index=True)

产量

    key     time    value
0   A   1   10.0
1   A   2   30.0
2   A   3   30.0
3   A   4   50.0
4   A   5   30.0
5   A   6   30.0
6   A   8   10.0
7   A   9   10.0
8   A   10  10.0
9   B   1   15.0
10  B   2   45.0
11  B   3   60.0
12  B   4   45.0
13  B   5   15.0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-09
    • 1970-01-01
    • 2021-12-02
    • 2019-04-14
    • 2022-07-06
    • 2019-11-18
    • 1970-01-01
    相关资源
    最近更新 更多