【问题标题】:Adding rows for each month in a dataframe based on column date根据列日期在数据框中添加每个月的行
【发布时间】:2019-09-14 14:16:28
【问题描述】:

我正在处理需要推断不同月份的财务数据。这是我的数据框:

invoice_id,date_from,date_to
30492,2019-02-04,2019-09-18

我想将它分解为 date_fromdate_to 之间的不同月份。因此,我需要为每个月添加行,从开始日期到结束日期。最终输出应如下所示:

invoice_id,date_from,date_to
30492,2019-02-04,2019-02-28
30492,2019-03-01,2019-03-31
30492,2019-04-01,2019-04-30
30492,2019-05-01,2019-05-31
30492,2019-06-01,2019-06-30
30492,2019-07-01,2019-07-31
30492,2019-08-01,2019-08-30
30492,2019-09-01,2019-09-18

还需要处理闰年的情况。 pandas datetime 包中是否有任何本机方法可以用来实现所需的输出?

【问题讨论】:

    标签: python pandas datetime calendar


    【解决方案1】:

    用途:

    print (df)
       invoice_id  date_from    date_to
    0       30492 2019-02-04 2019-09-18
    1       30493 2019-01-20 2019-03-10
    
    #added months between date_from and date_to
    df1 = pd.concat([pd.Series(r.invoice_id,pd.date_range(r.date_from, r.date_to, freq='MS')) 
                     for r in df.itertuples()]).reset_index()
    df1.columns = ['date_from','invoice_id']
    
    #added starts of months - sorting for correct positions
    df2 = (pd.concat([df[['invoice_id','date_from']], df1], sort=False, ignore_index=True)
             .sort_values(['invoice_id','date_from'])
             .reset_index(drop=True))
    
    #added MonthEnd and date_to  to last rows
    mask = df2['invoice_id'].duplicated(keep='last')
    s = df2['invoice_id'].map(df.set_index('invoice_id')['date_to'])
    df2['date_to'] = np.where(mask, df2['date_from'] + pd.offsets.MonthEnd(), s)
    
    print (df2)
        invoice_id  date_from    date_to
    0        30492 2019-02-04 2019-02-28
    1        30492 2019-03-01 2019-03-31
    2        30492 2019-04-01 2019-04-30
    3        30492 2019-05-01 2019-05-31
    4        30492 2019-06-01 2019-06-30
    5        30492 2019-07-01 2019-07-31
    6        30492 2019-08-01 2019-08-31
    7        30492 2019-09-01 2019-09-18
    8        30493 2019-01-20 2019-01-31
    9        30493 2019-02-01 2019-02-28
    10       30493 2019-03-01 2019-03-10
    

    【讨论】:

      【解决方案2】:

      您可以将pandas.date_range 与开始日期和结束日期结合使用,并结合使用作为月初的freq='MS' 和作为月底的freq='M'

      x = pd.date_range(start=df.iloc[0]['date_from'], end=df.iloc[0]['date_to'], freq='MS')
      y = pd.date_range(start=df.iloc[0]['date_from'], end=df.iloc[0]['date_to'], freq='M')
      
      df_new = pd.DataFrame({'date_from':x,
                             'date_to':y})
      
      df_new['invoice_id'] = df.iloc[0]['invoice_id']
      
      print(df_new)
         date_from    date_to  invoice_id
      0 2019-03-01 2019-02-28       30492
      1 2019-04-01 2019-03-31       30492
      2 2019-05-01 2019-04-30       30492
      3 2019-06-01 2019-05-31       30492
      4 2019-07-01 2019-06-30       30492
      5 2019-08-01 2019-07-31       30492
      6 2019-09-01 2019-08-31       30492
      

      【讨论】:

        【解决方案3】:

        另一种方式,使用日期时间索引的resample 方法:

        # melt, so we have start and end dates in 1 column
        df = pd.melt(df, id_vars='invoice_id')
        # now set the date column as index
        df.set_index(inplace=True, keys='value')
        # resample to daily level
        df = df.resample('D').ffill().reset_index()
        # get the yr-month value of each daily row
        df['yr_month'] = df['value'].dt.strftime("%Y-%m")
        
        # Now group by month and take min/max day values
        output = (df.groupby(['invoice_id', 'yr_month'])['value']
                  .agg({'date_from': 'min', 'date_to': 'max'})
                  .reset_index()
                  .drop(labels='yr_month', axis=1))
        
        print(output)
        
           invoice_id  date_from    date_to
        0       30492 2019-02-04 2019-02-28
        1       30492 2019-03-01 2019-03-31
        2       30492 2019-04-01 2019-04-30
        3       30492 2019-05-01 2019-05-31
        4       30492 2019-06-01 2019-06-30
        5       30492 2019-07-01 2019-07-31
        6       30492 2019-08-01 2019-08-31
        7       30492 2019-09-01 2019-09-18
        

        【讨论】:

          猜你喜欢
          • 2019-12-01
          • 2016-08-22
          • 1970-01-01
          • 2017-08-09
          • 2017-02-06
          • 1970-01-01
          • 2022-01-22
          • 1970-01-01
          相关资源
          最近更新 更多