首页 > 解决方案 > Pandas:分组方式,Cumsum + Shift 与“where 子句”

问题描述

我正在尝试学习一些我会在 SQL 窗口函数中做的 Pandas。

假设我有以下数据框,它显示了不同玩家之前的比赛以及他们在每场比赛中获得的击杀数。

 date          player        kills 
 2019-01-01      a             15
 2019-01-02      b             20
 2019-01-03      a             10
 2019-03-04      a             20

在下面的代码中,我设法创建了一个 groupby,其中我只显示了之前的总击杀数(玩家击杀数的总和,不包括他在当前行的游戏中获得的击杀数)。

df['sum_kills'] =    df.groupby('player')['kills'].transform(lambda x: x.cumsum().shift())

这将创建以下值:

 date          player        kills    sum_kills
 2019-01-01      a             15      NaN
 2019-01-02      b             20      NaN
 2019-01-03      a             10      15
 2019-03-04      a             20      25

但是,我理想中想要的是在分组值中包含过滤器/where 子句的选项。因此,假设我只想获取前 30 天(1 个月)的总和值。然后我的新数据框应该如下所示:

 date          player        kills    sum_kills
 2019-01-01      a             15      NaN
 2019-01-02      b             20      NaN
 2019-01-03      a             10      15
 2019-03-04      a             20      NaN

最后一行将提供零 summed_kills,因为上个月没有玩过玩家 a 的游戏。这有可能吗?

标签: pythonpandas

解决方案


groupby我认为您使用and有点紧张transform。正如这里所解释的,transform对单个系列进行操作,因此您无法访问其他列的数据。
groupby并且apply似乎也不是正确的方法,因为自定义函数预计会为传递的组返回聚合结果groupby,但您希望每一行都有不同的结果。

因此,我可以提出的最佳解决方案是不使用applygroupy并在自定义函数中自行执行所有选择:

def killcount(x, data, timewin):
    """count the player's kills in a time window before the time of current row.
    x: dataframe row
    data: full dataframe
    timewin: a pandas.Timedelta
    """
    return data.loc[(data['date'] < x['date']) #select dates preceding current row
            & (data['date'] >= x['date']-timewin) #select dates in the timewin                
            & (data['player'] == x['player'])]['kills'].sum() #select rows with same player

df['sum_kills'] = df.apply(lambda r : killcount(r, df, pd.Timedelta(30, 'D')), axis=1)

这将返回:

        date player  kills  sum_kills
0 2019-01-01      a     15          0
1 2019-01-02      b     20          0
2 2019-01-03      a     10         15
3 2019-03-04      a     20          0

如果您还没有完成,请记住'date'使用pandas.to_datetime将列解析为日期时间类型,否则您无法执行日期比较。


推荐阅读