我有一个非常大的DataFrame(10M +记录),我试图在每个Sku / Store组合的 datetime 列上执行转换。
这是我目前工作的(但不是可扩展的)版本:
for sku in sales_inv.Sku.unique():
for store in sales_inv[sales_inv.Sku == sku].Location.unique():
temp = sales_inv.loc[((sales_inv.Location == store) & (sales_inv.Sku == sku))]
temp.loc[:,'dt'] = pd.date_range(end=temp.dt.max(), periods=temp.shape[0])
我需要进行此转换的原因是因为缺少日期,我想通过用连续的日期时间替换整个 dt 系列来填充缺少的日期数组以每个Sku / Store组的最后观察日期结束。数据的有效性并不重要 - 即我不需要数据与实际日期相匹配。
我认为 pd.DataFrame.groupby()。apply()可以在这里使用,但我还没有成功。我尝试使用以下方法:
Apply multiple functions to multiple groupby columns
我尝试了两种方法:
pad_dates = lambda x: pd.date_range(end=x.max(), periods=x.size)
sales_inv.group_by(all_cols_but_dt).apply(pad_dates)
以及
f = {'dt': pad_dates}
sales_inv.group_by(all_cols_but_dt).apply(f)
没有运气。寻找与for循环更快的方法。任何帮助都非常感谢。
编辑:
示例
n = 5
d1 = {'Sku': ['one'] * n,
'Location': ['loc1'] * n,
'dt': pd.date_range(end=dt.datetime.now().date(), periods=n),
'on_hand': [1] * n,
'sales': [2] * n}
d2 = {'Sku': ['two'] * n,
'Location': ['loc2'] * n,
'dt': pd.date_range(end=dt.datetime.now().date(), periods=n),
'on_hand': [2] * n,
'sales': [4] * n}
df = pd.DataFrame(d1).drop(3, axis=0).append(pd.DataFrame(d2).drop(4,axis=0))
正确应该如下:
n = 4
# assign d1 and d2 using new 'n'
df = pd.DataFrame(d1).append(pd.DataFrame(d2))
由于
答案 0 :(得分:1)
这就是你想要的吗?
In [62]: dt_rng = pd.date_range(df['dt'].min(), df['dt'].max())
In [63]: df.groupby('Sku') \
.apply(lambda x: x.set_index('dt').reindex(dt_rng).ffill()) \
.reset_index('Sku', drop=True)
编辑:
Corrent回答:
警告:有一种hack-y解决方法,但它使用apply因此在30秒内运行此大小的DataFrame。
cols = df.columns
df = df.groupby(['Sku','Location']) \
.apply(lambda x: x.set_index(pd.date_range(end=x.dt.max(), periods=x.shape[0]))) \
.drop(['Sku','Location','dt'], axis = 1)
df = df.reset_index()
df.columns = cols
结果:
DF
Out[59]:
Location Sku dt on_hand sales
0 one loc1 2017-01-30 1 2
1 one loc1 2017-01-31 1 2
2 one loc1 2017-02-01 1 2
3 one loc1 2017-02-02 1 2
4 two loc2 2017-01-29 2 4
5 two loc2 2017-01-30 2 4
6 two loc2 2017-01-31 2 4
7 two loc2 2017-02-01 2 4
答案 1 :(得分:0)
如果您只想填写缺少日期的索引,那么使用reindex
就可以了:
idx = pd.date_range('01.01.2017', '01.10.2017')
idx_missing = idx[0:3].union(idx[5:])
vals = range(len(idx_missing))
df = pd.DataFrame(index=idx_missing, data=vals)
df
>>>
0
2017-01-01 0
2017-01-02 1
2017-01-03 2
2017-01-06 3
2017-01-07 4
2017-01-08 5
2017-01-09 6
2017-01-10 7
df = df.reindex(idx, fill_value=999)
df
>>>
0
2017-01-01 0
2017-01-02 1
2017-01-03 2
2017-01-04 999
2017-01-05 999
2017-01-06 3
2017-01-07 4
2017-01-08 5
2017-01-09 6
2017-01-10 7