【问题标题】:Creating sum of date ranges in Pandas在 Pandas 中创建日期范围的总和
【发布时间】:2022-11-17 04:35:14
【问题描述】:

我有以下 DataFrame,有超过 300 万行:

VALID_FROM   VALID_TO  VALUE
0 2022-01-01 2022-01-02      5
1 2022-01-01 2022-01-03      2
2 2022-01-02 2022-01-04      7
3 2022-01-03 2022-01-06      3

我想创建一个大的 date_range,其中包含每个时间戳的值之和。

对于上面的 DataFrame,结果是:

       dates  val
0 2022-01-01    7
1 2022-01-02   14
2 2022-01-03   12
3 2022-01-04   10
4 2022-01-05    3
5 2022-01-06    3

但是,由于 DataFrame 有超过 300 万行,我不想遍历每一行,而且我不确定如何在不迭代的情况下执行此操作。有什么建议么?

目前我的代码如下所示:

new_df = pd.DataFrame()
for idx, row in dummy_df.iterrows():
    dr = pd.date_range(row["VALID_FROM"], end = row["VALID_TO"], freq = "D")
    tmp_df = pd.DataFrame({"dates": dr, "val": row["VALUE"]})
    new_df = pd.concat(objs=[new_df, tmp_df], ignore_index=True)

new_df.groupby("dates", as_index=False, group_keys=False).sum()

groupby 的结果将是我想要的输出。

【问题讨论】:

    标签: python pandas dataframe datetime date-range


    【解决方案1】:

    如果性能很重要,请使用Index.repeatDataFrame.loc作为新行,创建date列,计数器由GroupBy.cumcount和最后聚合sum组成:

    df['VALID_FROM'] = pd.to_datetime(df['VALID_FROM'])
    df['VALID_TO'] = pd.to_datetime(df['VALID_TO'])
    
    df1 = df.loc[df.index.repeat(df['VALID_TO'].sub(df['VALID_FROM']).dt.days + 1)]
    df1['dates'] = df1['VALID_FROM'] + pd.to_timedelta(df1.groupby(level=0).cumcount(),unit='d')
    
    df1 = df1.groupby('dates', as_index=False)['VALUE'].sum()
    print (df1)
           dates  VALUE
    0 2022-01-01      7
    1 2022-01-02     14
    2 2022-01-03     12
    3 2022-01-04     10
    4 2022-01-05      3
    5 2022-01-06      3
    

    【讨论】:

      【解决方案2】:

      一种选择是构建一个日期列表,从原始数据帧的最小值到最大值,使用与conditional_join 的非等值连接来获取匹配项,最后是 groupby 和 sum:

      # pip install pyjanitor
      import pandas as pd
      import janitor
      
      # build the date pandas object:
      dates = df.filter(like='VALID').to_numpy()
      dates = pd.date_range(dates.min(), dates.max(), freq='1D')
      dates = pd.Series(dates, name='dates')
      
      # compute the inequality join between valid_from and valid_to, 
      # followed by the aggregation on a groupby:
      (df
      .conditional_join(
          dates, 
          ('VALID_FROM', 'dates', '<='),
          ('VALID_TO','dates', '>='), 
          # if you have numba installed, 
          # it can improve performance
          use_numba=False, 
          df_columns='VALUE')
      .groupby('dates')
      .VALUE
      .sum()
      ) 
      dates
      2022-01-01     7
      2022-01-02    14
      2022-01-03    12
      2022-01-04    10
      2022-01-05     3
      2022-01-06     3
      Name: VALUE, dtype: int64
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-04-15
        • 2021-09-12
        • 2019-05-03
        • 1970-01-01
        • 2012-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多