首页 > 解决方案 > Pandas 在 DataFrame 中填写缺失的每月日期,用零填充特定列

问题描述

我遇到了 Pandas 的问题,以及如何在 DataFrame 中填写缺失的日期。给定DataFrame的结构如下:

     Amount  Code     Type   Date
0     34.97  J36J     74343 2016-01-01
1     16.32  J36J     74343 2016-04-01
2     10.30  J36J     69927 2015-12-01
3     10.45  J36J     69927 2016-07-01
4      5.63  J36J     69927 2017-03-01
5     15.79  J36J     69927 2018-09-01
6     15.00  J36J     69927 2019-06-01
7      6.44  J36J     69926 2016-03-01
8      6.47  J36J     69926 2017-03-01
9     15.00  J36J     69926 2018-07-01
10    15.00  J36J     69926 2019-06-01

我的目标是为涵盖此时间跨度的每种类型提供每月条目。意思是,每个材料应该有 58 个条目。“人为”创建的每月条目的数量应为 0。因此,我的预期输出将是(仅针对一种类型,例如)

     Amount  Code     Type   Date
0     34.97  J36J     74343 2016-01-01
1     16.32  J36J     74343 2016-02-01
2     0      J36J     74343 2016-03-01
3     0      J36J     74343 2016-04-01
4     0      J36J     74343 2016-05-01
5     0      J36J     74343 2016-06-01
6     0      J36J     74343 2016-07-01
7     0      J36J     74343 2016-08-01
8     0      J36J     74343 2016-09-01
9     0      J36J     74343 2016-10-01
10    0      J36J     74343 2016-11-01
11    0      J36J     74343 2016-12-01

幸运的是,有人已经有同样的问题(Pandas 在 DataFrame 中用多列填充缺失的日期

我调整了对我的案例很有帮助的答案:

df.Date=pd.to_datetime(df.Date)
s=pd.date_range(df.Date.min(),df.Date.max(),freq='MS')

df=df.set_index(['Code','Type','Date']).\
      Amount.unstack().reindex(columns=s,fill_value=0).stack().reset_index()
df

这工作得很好,但我后来检查了生成的 DataFrame,似乎有些日期丢失了。

398     74343  J36J 2016-01-01  34.97
399     74343  J36J 2016-02-01   0.00
400     74343  J36J 2016-04-01  16.32
401     74343  J36J 2016-05-01   0.00
402     74343  J36J 2016-06-01   0.00
403     74343  J36J 2016-08-01   0.00
404     74343  J36J 2016-10-01   0.00
405     74343  J36J 2016-11-01   0.00
406     74343  J36J 2016-12-01   0.00

你们中有人知道这可能是什么原因吗?我假设可能是因为我选择的频率('MS')?但我认为其他任何一个都不合适。(https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html)或者我必须手动设置数据范围吗?在我最初的 DataFrame 中,显然并非所有日期都可用。

对此问题的任何帮助表示赞赏。

BR

标签: pythonpandasdataframe

解决方案


这是一个微妙的,很有趣。

import pandas as pd
data = {'Amount' :[34.97, 16.32, 10.3, 10.45, 5.63, 15.79, 15, 6.44, 6.47, 15, 15],
'Code': ['J36J','J36J','J36J','J36J','J36J','J36J','J36J','J36J','J36J','J36J','J36J'],
'Type': [74343,74343,69927,69927,9927,69927,69927,69926,69926,69926,69926],
'Date': ['1/1/2016','4/1/2016','12/1/2015','7/1/2016','3/1/2017','9/1/2018','6/1/2019','3/1/2016','3/1/2017','7/1/2018','6/1/2019']}
df = pd.DataFrame(data)
df['Date'] = pd.to_datetime(df['Date'], format='%m/%d/%Y')
df

这得到了上述值的起点。然后弄清楚发生了什么需要一段时间,问题是我们对所有类型使用相同的 s 而不是单独使用。因此,如果日期是另一种类型,则不会被覆盖。

为了解决这个问题,我把它分成几部分,这样我们就可以把它重新组装起来。

outdf = pd.DataFrame(columns = df.columns)
s=pd.date_range(df.Date.min(),df.Date.max(),freq='MS')
for name, subdf in df.groupby('Type'):
    thisdf=subdf.set_index(['Code','Type','Date']).\
        Amount.unstack().reindex(columns=s,fill_value=0).stack().reset_index()
    thisdf.rename(columns={0: "Amount", "level_2": "Date"}, errors="raise",inplace=True)
    thisdf.reset_index(inplace=True)
    thisdf = thisdf[['Code', 'Type', 'Date', 'Amount']]
    outdf = pd.concat([outdf,thisdf])
    outdf = outdf[['Code', 'Type', 'Date', 'Amount']]

outdf.reset_index(inplace=True)
outdf = outdf[['Code', 'Type', 'Date', 'Amount']]

所以我们所做的是将它分解成单独的项目,然后在每次通过 groupby 后将它们粘在一起。这样我们就不会错过其他类型的日期。


推荐阅读