将每月数据更改为每日数据,并将值分布在该月的每一天

Posted

技术标签:

【中文标题】将每月数据更改为每日数据,并将值分布在该月的每一天【英文标题】:Change monthly data to daily data and spread out values over each day of that month 【发布时间】:2021-01-08 11:06:44 【问题描述】:

我有一个包含每月数据的 df:

date       | type   | value1 | value2 
2020-04-01 | "a"    | 30     | 60     
2020-04-01 | "b"    | 60     | 120    
2020-04-01 | "c"    | 45     | 180    
...        | ...    | ...    | ...    
2021-02-01 | "a"    | 28     | 56    
2021-02-01 | "b"    | 21     | 42   
2021-02-01 | "c"    | 5.6    | 16.8    

我需要获取每个月的每日数据。 每个 value1 和 value2 应该每个月平均分布。

如果该月有 30 天 = "value1 / 30" 和 "value2 / 30" 该月的每一天。 如果该月有 28 天 = "value1 / 28" 和 "value2 / 28" 该月的每一天。

31 天不变。

结束数据框应该是:

    date   | type | value1 | value2 
2020-04-01 | "a"  | 1      | 2     # 30 days in April 2020
2020-04-02 | "a"  | 1      | 2
2020-04-03 | "a"  | 1      | 2
...        | ...  | ..
2020-04-01 | "b"  | 2      | 4     # 30 days in April 2020
2020-04-02 | "b"  | 2      | 4
2020-04-03 | "b"  | 2      | 4
...        | ...  | ..
2020-04-01 | "c"  | 1.5    | 3     # 30 days in April 2020
2020-04-02 | "c"  | 1.5    | 3
2020-04-03 | "c"  | 1.5    | 3
...        | ...  | ..
2021-02-01 | "a"  | 1      | 2     # 28 days in February 2021
2021-02-02 | "a"  | 1      | 2
2021-02-03 | "a"  | 1      | 2
...        | ...  | ..
2021-02-01 | "b"  | 0.75   | 1.5     # 28 days in February 2021
2021-02-02 | "b"  | 0.75   | 1.5
2021-02-03 | "b"  | 0.75   | 1.5
...        | ...  | ..
2021-02-01 | "c"  | 0.2    | 6     # 28 days in February 2021
2021-02-02 | "c"  | 0.2    | 6
2021-02-03 | "c"  | 0.2    | 6

我怎样才能用熊猫做到这一点?

【问题讨论】:

【参考方案1】:

首先将DataFrame.reindexdate_range 相加,然后除以DataFrame.divdaysinmonth 每月的天数:

df['date'] = pd.to_datetime(df['date'])
rng = pd.date_range(df['date'].min(), df['date'].max() + pd.offsets.MonthEnd(), name='date')

df = df.set_index('date').reindex(rng, method='ffill')
df = df.div(df.index.daysinmonth, axis=0).reset_index()

print (df)
          date    value1    value2
0   2020-04-01  1.000000  2.000000
1   2020-04-02  1.000000  2.000000
2   2020-04-03  1.000000  2.000000
3   2020-04-04  1.000000  2.000000
4   2020-04-05  1.000000  2.000000
..         ...       ...       ...
329 2021-02-24  0.714286  1.071429
330 2021-02-25  0.714286  1.071429
331 2021-02-26  0.714286  1.071429
332 2021-02-27  0.714286  1.071429
333 2021-02-28  0.714286  1.071429

[334 rows x 3 columns]

编辑:reindex 每个 type 列的解决方案分别使用自定义 lambda 函数:

df['date'] = pd.to_datetime(df['date'])

f = (lambda x: x.set_index('date')
                .reindex(pd.date_range(x['date'].min(), 
                                       x['date'].max() + pd.offsets.MonthEnd(), 
                                       name='date'), method='ffill'))
df = (df.groupby('type').apply(f)
       .reset_index(level=0, drop=True)
       .set_index('type', append=True))

df = df.div(df.index.get_level_values(0).daysinmonth, axis=0, level=0).reset_index()
print (df)
           date type    value1    value2
0    2020-04-01    a  0.033333  0.066667
1    2020-04-02    a  0.033333  0.066667
2    2020-04-03    a  0.033333  0.066667
3    2020-04-04    a  0.033333  0.066667
4    2020-04-05    a  0.033333  0.066667
        ...  ...       ...       ...
997  2021-02-24    c  0.007143  0.214286
998  2021-02-25    c  0.007143  0.214286
999  2021-02-26    c  0.007143  0.214286
1000 2021-02-27    c  0.007143  0.214286
1001 2021-02-28    c  0.007143  0.214286

【讨论】:

感谢您的回答,但我需要将一个月中的每一天作为一行,如末尾 df 示例所示。 我很抱歉,但我忘了补充一下,每个月都有一个类型列有大约 18 个不同的值(相应地更改了 df + df 最终结果)。我需要为每个类型列添加月份的天数,您的解决方案给了我“无法使用方法或列表重新索引非唯一索引”。如果你知道这个问题的解决方案,你会这么好心地改变你的答案吗?很抱歉给您带来麻烦。

以上是关于将每月数据更改为每日数据,并将值分布在该月的每一天的主要内容,如果未能解决你的问题,请参考以下文章

AppEngine cron (python) 中的每一天、每周、每月、每年

按日期显示多个值的数据透视表

获取具有相应索引值的每日数据帧的每月最大值

如何在 PostgreSQL 中获取表的每一天的第一个日期并将其转换为 JSON

oracle 如何查询两个时间段里的每一天数据之和。(只有开始日期和结束日期,没有每一天日期)

如何使用 Python 仅查找包含该月最后一天的日期的文件?