【问题标题】:How to create new column by calculating on specific time range in python?如何通过计算python中的特定时间范围来创建新列?
【发布时间】:2020-01-27 04:33:28
【问题描述】:

我有一个这样的数据框,

ID   col1            col2   
A    2018/07/01       3     
A    2018/08/01       5   
A    2018/10/01       10      
B    2018/07/01       4        
B    2018/10/01       7         
B    2019/01/01       9       
B    2019/04/01       12       
C    2018/07/01       6        
C    2018/09/01       5  
C    2018/10/01       7   

我尝试创建一个新列col3,该列由col2 为每个 ID 减去自身后 3 个月计算得出。

结果会是这样,

 ID   col1            col2       col3
    A    2018/07/01       3          -7
    A    2018/08/01       5          NaN
    A    2018/10/01       10         NaN
    B    2018/07/01       4          -3
    B    2018/10/01       7          -2
    B    2019/01/01       9          -3
    B    2019/04/01       12         NaN
    C    2018/07/01       6          -1
    C    2018/09/01       5          NaN
    C    2018/10/01       7          NaN

如果 3 个月后没有为每个 ID 找到月份,则返回 NaN。

【问题讨论】:

    标签: python pandas numpy dataframe datetime


    【解决方案1】:

    您可以在数据框组中使用“重新索引”(无需重新采样和移位):

    def get_col2(grp):
        return grp.set_index("col1").reindex(grp["date2"],axis="index")["col2"]      
    
    df["col3"]= df.assign(date2=df["col1"]+pd.offsets.MonthBegin(3)).groupby("ID").apply(get_col2).values
    
    df["col3"]= df["col2"]-df["col3"]
    

    输出:

    ID       col1  col2  col3
    0  A 2018-07-01     3  -7.0
    1  A 2018-08-01     5   NaN
    2  A 2018-10-01    10   NaN
    3  B 2018-07-01     4  -3.0
    4  B 2018-10-01     7  -2.0
    5  B 2019-01-01     9  -3.0
    6  B 2019-04-01    12   NaN
    7  C 2018-07-01     6  -1.0
    8  C 2018-09-01     5   NaN
    9  C 2018-10-01     7   NaN
    

    【讨论】:

      【解决方案2】:

      按 ID 分组并将日期列设置为您的索引和重新采样。然后移动 -3。

      在:

      def func(df):
          df = df.set_index(df.col1).resample('MS').asfreq()
          df['col3'] = df.col2 - df.col2.shift(-3)
      
          # Clean Up DataFrame        
          df = df.reset_index(0, drop=True).reset_index(drop=True).dropna(how='all')
      
          return df
      
      df = pd.read_clipboard()
      df.col1 = pd.to_datetime(df.col1)
      group = df.groupby('ID', as_index=False)
      
      df = group.apply(func).reset_index(drop=True)
      

      输出:

      |    | ID | col1       | col2 | col3 |
      |----|----|------------|------|------|
      | 0  | A  | 2018-07-01 | 3.0  | -7.0 |
      | 1  | A  | 2018-08-01 | 5.0  | NaN  |
      | 2  | A  | 2018-10-01 | 10.0 | NaN  |
      | 3  | B  | 2018-07-01 | 4.0  | -3.0 |
      | 4  | B  | 2018-10-01 | 7.0  | -2.0 |
      | 5  | B  | 2019-01-01 | 9.0  | -3.0 |
      | 6  | B  | 2019-04-01 | 12.0 | NaN  |
      | 7  | C  | 2018-07-01 | 6.0  | -1.0 |
      | 8  | C  | 2018-09-01 | 5.0  | NaN  |
      | 9  | C  | 2018-10-01 | 7.0  | NaN  |
      

      【讨论】:

        【解决方案3】:

        据说shift(freq='-3M') 很容易,但不知何故,这不适用于月份开始。所以我们可以这样做:

        # month end date
        df['col1e'] = df.col1 + pd.DateOffset(months=3) - pd.DateOffset(days=1)
        
        # shift by group
        new_df = df.set_index('col1e').col2.shift(freq='-3M').reset_index(name='col3')
        
        # copy the ID values
        new_df['ID'] = df['ID'].values
        
        # merge
        df = df.merge(new_df, on=['col1e','ID'],how='left')
        
        #final result
        df['col3'] = df['col2'] - df['col3']
        

        输出:

          ID       col1  col2      col1e  col3
        0  A 2018-07-01     3 2018-09-30  -7.0
        1  A 2018-08-01     5 2018-10-31   NaN
        2  A 2018-10-01    10 2018-12-31   NaN
        3  B 2018-07-01     4 2018-09-30  -3.0
        4  B 2018-10-01     7 2018-12-31  -2.0
        5  B 2019-01-01     9 2019-03-31  -3.0
        6  B 2019-04-01    12 2019-06-30   NaN
        7  C 2018-07-01     6 2018-09-30  -1.0
        8  C 2018-09-01     5 2018-11-30   NaN
        9  C 2018-10-01     7 2018-12-31   NaN
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多