【问题标题】:Pandas - Sum Previous Rows if Value In Column Meets ConditionPandas - 如果列中的值满足条件,则对前几行求和
【发布时间】:2019-09-09 18:41:11
【问题描述】:

我有一个以下类型的数据框。除了我希望创建的最后一列“Total Previous Points 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”列。

创建方式:

  • 对于每一行,检查日期(称为 DATE_VAL)和 P1_id(称为 ID_VAL)
  • 现在,对于 DATE_VAL AND 其中 P1 id == ID_VAL 之前的所有行,总结之前的点。
  • 将此总和放在当前行的最后一列中

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

谢谢!

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

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

    假设每个组中的日期都是唯一的(在您的示例中它们是唯一的), 正确的 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
    

    然后在 P1_idDate 上将 dfsumPrev 合并(在 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-09both 行,之前的总和 点数为 5(在 Date == 2015-10-08 的行中)。

    【讨论】:

      【解决方案2】:

      试试:

      df['Total_Previous_Points_P1'] = df.groupby(['P1_id'])['Points_P1'].cumsum()
      

      工作原理

      首先,它使用P1_id 功能对数据进行分组。

      然后它访问分组数据帧上的Points_P1 值并应用累积求和函数cumsum(),该函数返回每个组的当前行(包括当前行)的总和。

      【讨论】:

      • 谢谢,这几乎可以工作,但我收到以下错误:'A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead'。相反,如果我创建一个新变量 newcol = df.groupby(['P1_id'])['Points_P1'].cumsum(),则不会返回错误。如果我稍后尝试做df['Total_Previous_Points_P1'] = newcol,我会遇到类似的问题
      猜你喜欢
      • 2021-05-15
      • 1970-01-01
      • 2022-10-07
      • 2014-02-11
      • 1970-01-01
      • 2020-05-16
      • 1970-01-01
      • 1970-01-01
      • 2017-01-13
      相关资源
      最近更新 更多