在 pandas 中填充 multiIndex 数据框的所有月份
Populate all months for multiIndex dataframe in pandas
我有一个 table,其中包含 2015 年至 2017 年数千种产品的每月销售额和预测。
我的数据给出了每个站点、类型、产品和日期(仅几个月)的需求和预测
问题是,如果一个月内没有销售和预测,我看不到具体的行。在下面的示例中,您会看到缺少“2015-08-31”行。
我希望这条线的需求为 0,预测为 0。
(请参阅下面的 df_expected 示例)。
基本上,对于所有 Product/Type/Site 组合,我想为 2015-06-30 到 2017-09-30 之间的所有日期用 0 填充此 table。
正如你在代码中看到的,我没有定义任何索引,但基本上可以看到 ["Site","Type","Product","Date"]作为 multiIndex.
请注意,我有数百万行。
import pandas as pd
data = [("W1","G1",1234,pd.to_datetime("2015-07-31"),8,4),
("W1","G1",1234,pd.to_datetime("2015-09-30"),2,4),
("W1","G1",1234,pd.to_datetime("2015-10-31"),2,4),
("W1","G1",1234,pd.to_datetime("2015-11-30"),4,4),
("W1","G2",2345,pd.to_datetime("2015-07-31"),5,0),
("W1","G2",2345,pd.to_datetime("2015-08-31"),1,3),
("W1","G2",2345,pd.to_datetime("2015-10-31"),1,3),
("W1","G2",2345,pd.to_datetime("2015-11-30"),3,3)]
labels = ["Site","Type","Product","Date","Demand","Forecast"]
df = pd.DataFrame(data,columns=labels)
df
Site Type Product Date Demand Forecast
0 W1 G1 1234 2015-07-31 8 4
1 W1 G1 1234 2015-09-30 2 4
2 W1 G1 1234 2015-10-31 2 4
3 W1 G1 1234 2015-11-30 4 4
4 W1 G2 2345 2015-07-31 5 0
5 W1 G2 2345 2015-08-31 1 3
6 W1 G2 2345 2015-10-31 1 3
7 W1 G2 2345 2015-11-30 3 3
这是我期待的结果
data_expected = [("W1","G1",1234,pd.to_datetime("2015-07-31"),8,4),
("W1","G1",1234,pd.to_datetime("2015-08-31"),0,0),
("W1","G1",1234,pd.to_datetime("2015-09-30"),2,4),
("W1","G1",1234,pd.to_datetime("2015-10-31"),2,4),
("W1","G1",1234,pd.to_datetime("2015-11-30"),4,4)]
df_expected = pd.DataFrame(data_expected,columns=labels)
df_expected
Site Type Product Date Demand Forecast
0 W1 G1 1234 2015-07-31 8 4
1 W1 G1 1234 2015-08-31 0 0
2 W1 G1 1234 2015-09-30 2 4
3 W1 G1 1234 2015-10-31 2 4
4 W1 G1 1234 2015-11-30 4 4
我本来想stack/unstack确保我有所有的月份。但这对于具有数百万行的数据框来说并不是最佳选择。
df = (df
.set_index("Date")
.groupby(["Site","Product","Type",pd.TimeGrouper('M')])[["Forecast","Demand"]].sum()
.unstack()
.fillna(0)
.astype(int))
你怎么看?
您可以使用 DataFrameGroupBy.resample
with asfreq
:
df = (df.set_index('Date')
.groupby(["Site","Type","Product"])['Demand','Forecast']
.resample('M')
.asfreq()
.fillna(0)
.astype(int)
.reset_index())
print (df)
Site Type Product Date Demand Forecast
0 W1 G1 1234 2015-07-31 8 4
1 W1 G1 1234 2015-08-31 0 0
2 W1 G1 1234 2015-09-30 2 4
3 W1 G1 1234 2015-10-31 2 4
4 W1 G1 1234 2015-11-30 4 4
编辑:
我尝试使用 unstack
中的 fill_value
参数改进原始解决方案:
(df.set_index("Date")
.groupby(["Site","Product","Type",pd.TimeGrouper('M')])['Demand','Forecast'].sum()
.unstack(fill_value=0)
.stack())
stack/unstack 方法似乎工作得更快。
所有项目都有相同的开始日期和结束日期
df = (df.set_index("Date")
.groupby(["Site","Product","Type",pd.TimeGrouper('M')])['Demand','Forecast'].sum()
.unstack()
.fillna(0)
.astype(int)
.stack())
Demand Forecast
Site Product Type Date
W1 1234 G1 2015-07-31 8 4
2015-08-31 0 0
2015-09-30 2 4
2015-10-31 2 4
2015-11-30 4 4
2345 G2 2015-07-31 5 0
2015-08-31 1 3
2015-09-30 0 0
2015-10-31 1 3
2015-11-30 3 3
我有一个 table,其中包含 2015 年至 2017 年数千种产品的每月销售额和预测。 我的数据给出了每个站点、类型、产品和日期(仅几个月)的需求和预测
问题是,如果一个月内没有销售和预测,我看不到具体的行。在下面的示例中,您会看到缺少“2015-08-31”行。 我希望这条线的需求为 0,预测为 0。 (请参阅下面的 df_expected 示例)。
基本上,对于所有 Product/Type/Site 组合,我想为 2015-06-30 到 2017-09-30 之间的所有日期用 0 填充此 table。
正如你在代码中看到的,我没有定义任何索引,但基本上可以看到 ["Site","Type","Product","Date"]作为 multiIndex.
请注意,我有数百万行。
import pandas as pd
data = [("W1","G1",1234,pd.to_datetime("2015-07-31"),8,4),
("W1","G1",1234,pd.to_datetime("2015-09-30"),2,4),
("W1","G1",1234,pd.to_datetime("2015-10-31"),2,4),
("W1","G1",1234,pd.to_datetime("2015-11-30"),4,4),
("W1","G2",2345,pd.to_datetime("2015-07-31"),5,0),
("W1","G2",2345,pd.to_datetime("2015-08-31"),1,3),
("W1","G2",2345,pd.to_datetime("2015-10-31"),1,3),
("W1","G2",2345,pd.to_datetime("2015-11-30"),3,3)]
labels = ["Site","Type","Product","Date","Demand","Forecast"]
df = pd.DataFrame(data,columns=labels)
df
Site Type Product Date Demand Forecast
0 W1 G1 1234 2015-07-31 8 4
1 W1 G1 1234 2015-09-30 2 4
2 W1 G1 1234 2015-10-31 2 4
3 W1 G1 1234 2015-11-30 4 4
4 W1 G2 2345 2015-07-31 5 0
5 W1 G2 2345 2015-08-31 1 3
6 W1 G2 2345 2015-10-31 1 3
7 W1 G2 2345 2015-11-30 3 3
这是我期待的结果
data_expected = [("W1","G1",1234,pd.to_datetime("2015-07-31"),8,4),
("W1","G1",1234,pd.to_datetime("2015-08-31"),0,0),
("W1","G1",1234,pd.to_datetime("2015-09-30"),2,4),
("W1","G1",1234,pd.to_datetime("2015-10-31"),2,4),
("W1","G1",1234,pd.to_datetime("2015-11-30"),4,4)]
df_expected = pd.DataFrame(data_expected,columns=labels)
df_expected
Site Type Product Date Demand Forecast
0 W1 G1 1234 2015-07-31 8 4
1 W1 G1 1234 2015-08-31 0 0
2 W1 G1 1234 2015-09-30 2 4
3 W1 G1 1234 2015-10-31 2 4
4 W1 G1 1234 2015-11-30 4 4
我本来想stack/unstack确保我有所有的月份。但这对于具有数百万行的数据框来说并不是最佳选择。
df = (df
.set_index("Date")
.groupby(["Site","Product","Type",pd.TimeGrouper('M')])[["Forecast","Demand"]].sum()
.unstack()
.fillna(0)
.astype(int))
你怎么看?
您可以使用 DataFrameGroupBy.resample
with asfreq
:
df = (df.set_index('Date')
.groupby(["Site","Type","Product"])['Demand','Forecast']
.resample('M')
.asfreq()
.fillna(0)
.astype(int)
.reset_index())
print (df)
Site Type Product Date Demand Forecast
0 W1 G1 1234 2015-07-31 8 4
1 W1 G1 1234 2015-08-31 0 0
2 W1 G1 1234 2015-09-30 2 4
3 W1 G1 1234 2015-10-31 2 4
4 W1 G1 1234 2015-11-30 4 4
编辑:
我尝试使用 unstack
中的 fill_value
参数改进原始解决方案:
(df.set_index("Date")
.groupby(["Site","Product","Type",pd.TimeGrouper('M')])['Demand','Forecast'].sum()
.unstack(fill_value=0)
.stack())
stack/unstack 方法似乎工作得更快。 所有项目都有相同的开始日期和结束日期
df = (df.set_index("Date")
.groupby(["Site","Product","Type",pd.TimeGrouper('M')])['Demand','Forecast'].sum()
.unstack()
.fillna(0)
.astype(int)
.stack())
Demand Forecast
Site Product Type Date
W1 1234 G1 2015-07-31 8 4
2015-08-31 0 0
2015-09-30 2 4
2015-10-31 2 4
2015-11-30 4 4
2345 G2 2015-07-31 5 0
2015-08-31 1 3
2015-09-30 0 0
2015-10-31 1 3
2015-11-30 3 3