首页 > 解决方案 > Pandas - 如果列中的值满足条件,则对前几行求和

问题描述

我有一个以下类型的数据框。除了我希望创建的最后一列“以前的总点数 P1”之外,我有所有列:

数据按“日期”列排序。

   Date   |  Points_P1 |   P1_id       | P2_id    | Total_Previous_Points_P1
-------------+---------------+----------+-----------------------------------
10/08/15  |     5      |           100 |       90 |   500
-------------+---------------+----------+-----------------------------------
11/09/16  |     5      |           100 |       90 |   500
-------------+---------------+----------+-----------------------------------
20/09/19  |     10     |         10000 |      360 | 4,200
-------------+---------------+----------+-----------------------------------
...       |            |         ...   |      ... | ... 
-------------+---------------+----------+-----------------------------------
n         |            |               |          | 

现在我要创建的列是上面显示的“Total_Previous_Points_P1”列。

创建方式:

有没有一种快速的 pandas pythonic 方法可以做到这一点?我的数据集非常大。

谢谢!

标签: pythonpandasdataframe

解决方案


SIA的解决方案计算Points_P1的总和,包括Points_P1 的当前值,而要求是对 先前的点求和(对于...之前的所有行)。

假设每个组中的日期都是唯一的(在您的示例中它们是唯一的),正确的pandasonic解决方案应包括以下步骤:

  • 日期排序。
  • P1_id 分组,然后为每个组:
  • Points_P1列。
  • 计算累积总和
  • 减去Points_P1的当前值。

所以整个代码应该是:

df['Total_Previous_Points_P1'] = df.sort_values('Date')\
    .groupby(['P1_id']).Points_P1.cumsum() - df.Points_P1

编辑

如果Date不是唯一的(在具有某些P1_id的行组内),则情况会更复杂,可以在此类源 DataFrame 上显示什么:

        Date  Points_P1  P1_id
0 2016-11-09          5    100
1 2016-11-09          3    100
2 2015-10-08          5    100
3 2019-09-20         10  10000
4 2019-09-21          7    100
5 2019-07-10         12  10000
6 2019-12-10         12  10000

请注意,对于P1_id2016-11-09

在这种情况下,从为每个P1_idDate计算先前点的“组”总和开始:

sumPrev = df.groupby(['P1_id', 'Date']).Points_P1.sum()\
    .groupby(level=0).apply(lambda gr: gr.shift(fill_value=0).cumsum())\
    .rename('Total_Previous_Points_P1')

结果是:

P1_id  Date      
100    2015-10-08     0
       2016-11-09     5
       2019-09-21    13
10000  2019-07-10     0
       2019-09-20    12
       2019-12-10    22
Name: Total_Previous_Points_P1, dtype: int64

然后将dfP1_idDate上的sumPrev合并(在索引上的sumPrev中):

df = pd.merge(df, sumPrev, left_on=['P1_id', 'Date'], right_index=True)

为了显示结果,在['P1_id', 'Date']上对df进行排序更有指导意义:

        Date  Points_P1  P1_id  Total_Previous_Points_P1
2 2015-10-08          5    100                         0
0 2016-11-09          5    100                         5
1 2016-11-09          3    100                         5
4 2019-09-21          7    100                        13
5 2019-07-10         12  10000                         0
3 2019-09-20         10  10000                        12
6 2019-12-10         12  10000                        22

如你看到的:

  • 每个P1_id的第一个总和为0(没有来自先前日期的点)。
  • 例如,对于Date == 2016-11-09的行,先前点的总和为5(在Date == 2015-10-08的行中)。

推荐阅读