【问题标题】:Pandas: add row to each group depending on condition熊猫:根据条件向每个组添加行
【发布时间】:2017-09-25 15:28:07
【问题描述】:

假设我有一个这样的 DataFrame:

         date  id  val
0  2017-01-01   1   10
1  2019-01-01   1   20
2  2017-01-01   2   50

我想按id 对这个数据集进行分组。
对于每个组,我想添加一个新行,日期是从现在开始的 1 年。仅当该行晚于组中的最后一个日期时才应添加此行。该行的 val 应该与组中的最后一行相同。

决赛桌应该是这样的:

         date  id  val
0  2017-01-01   1   10
1  2019-01-01   1   20
2  2017-01-01   2   50
3  2018-09-25   2   50   <-- new row

当前代码如下。我可以得到一个掩码,显示哪些组需要附加一行,但不确定下一步该做什么。

>>> df = pd.DataFrame(data={'d': [datetime.date(2017, 1, 1), datetime.date(2019,1,1), datetime.date(2017,1,1)], 'id': [1,1,2], 'val': [10,20,50]})
>>> df = df.sort_values(by='d')
>>> future_date = (pd.datetime.now().date() + pd.DateOffset(years=1)).date()
>>> maxd = df.groupby('id')['d'].max()
>>> maxd < future_date
id
1    False
2     True
Name: d, dtype: bool

【问题讨论】:

    标签: python pandas pandas-groupby


    【解决方案1】:

    这是一种方法

    In [3481]: def add_row(x):
          ...:     next_year = pd.to_datetime('today') + pd.DateOffset(years=1)
          ...:     if x['date'].max() < next_year:
          ...:         last_row = x.iloc[-1]
          ...:         last_row['date'] = next_year
          ...:         return x.append(last_row)
          ...:     return x
          ...:
    
    In [3482]: df.groupby('id').apply(add_row).reset_index(drop=True)
    Out[3482]:
            date  id  val
    0 2017-01-01   1   10
    1 2019-01-01   1   20
    2 2017-01-01   2   50
    3 2018-09-25   2   50
    

    【讨论】:

      【解决方案2】:

      您可以将idxmaxloc 用于带有max date 的行:

      future_date = pd.to_datetime('today') + pd.DateOffset(years=1)
      maxd = df.loc[df.groupby('id')['d'].idxmax()]
      
      maxd = maxd[maxd['d'] < future_date]
      maxd['d'] = future_date
      print (maxd)
                 d  id  val
      2 2018-09-25   2   50
      
      df = pd.concat([df, maxd]).sort_values(['id','d']).reset_index(drop=True)
      print (df)
                 d  id  val
      0 2017-01-01   1   10
      1 2019-01-01   1   20
      2 2017-01-01   2   50
      3 2018-09-25   2   50
      

      【讨论】:

        【解决方案3】:

        另一种查看方式,使用duplicated 查找每个'id' 的最后一行

        t = df[~df.duplicated('id', 'last')]
        df.append(
            t.assign(
                date=pd.to_datetime('today') + pd.DateOffset(years=1)
            ).pipe(lambda d: d[d.date > t.date]),
            ignore_index=True).sort_values(['id', 'date'])
        
                date  id  val
        0 2017-01-01   1   10
        1 2019-01-01   1   20
        2 2017-01-01   2   50
        3 2018-09-24   2   50
        

        【讨论】:

          猜你喜欢
          • 2021-07-18
          • 2019-08-29
          • 2019-11-03
          • 2020-04-05
          • 1970-01-01
          • 2016-12-25
          • 1970-01-01
          • 1970-01-01
          • 2017-11-03
          相关资源
          最近更新 更多