对于名为full_df
的给定pandas数据框,看起来像
index id timestamp data
------- ---- ------------ ------
1 1 2017-01-01 10.0
2 1 2017-02-01 11.0
3 1 2017-04-01 13.0
4 2 2017-02-01 1.0
5 2 2017-03-01 2.0
6 2 2017-05-01 9.0
开始和结束日期(以及开始和结束之间的时间差异)是变化的。
但我需要一个id明智的重采样版本(添加标有*
的行)
index id timestamp data
------- ---- ------------ ------ ----
1 1 2017-01-01 10.0
2 1 2017-02-01 11.0
3 1 2017-03-01 NaN *
4 1 2017-04-01 13.0
5 2 2017-02-01 1.0
6 2 2017-03-01 2.0
7 2 2017-04-01 NaN *
8 2 2017-05-01 9.0
因为数据集非常大,我想知道是否有比
更有效的方法full_df.groupby('id')
针对每个群组df
df.index = pd.DatetimeIndex(df['timestamp'])
all_days = pd.date_range(df.index.min(), df.index.max(), freq='MS')
df = df.reindex(all_days)
使用新索引再次合并所有组
耗费时间,而且不是很优雅。有什么想法吗?
答案 0 :(得分:3)
使用resample
In [1175]: (df.set_index('timestamp').groupby('id').resample('MS').asfreq()
.drop(['id', 'index'], 1).reset_index())
Out[1175]:
id timestamp data
0 1 2017-01-01 10.0
1 1 2017-02-01 11.0
2 1 2017-03-01 NaN
3 1 2017-04-01 13.0
4 2 2017-02-01 1.0
5 2 2017-03-01 2.0
6 2 2017-04-01 NaN
7 2 2017-05-01 9.0
详细
In [1176]: df
Out[1176]:
index id timestamp data
0 1 1 2017-01-01 10.0
1 2 1 2017-02-01 11.0
2 3 1 2017-04-01 13.0
3 4 2 2017-02-01 1.0
4 5 2 2017-03-01 2.0
5 6 2 2017-05-01 9.0
In [1177]: df.dtypes
Out[1177]:
index int64
id int64
timestamp datetime64[ns]
data float64
dtype: object
答案 1 :(得分:1)
编辑添加:这样可以full_df
的最短/最短日期,而不是df
。如果ID之间的开始/结束日期存在很大差异,那么遗憾的是数据框会膨胀,而@JohnGalt方法会更好。不过,我会把它留在这里作为一种替代方法,因为在适当的情况下,它应该比groupby / resample更快。
我认为最有效的方法可能是使用stack / unstack或melt / pivot。
你可以这样做,例如:
full_df.set_index(['timestamp','id']).unstack('id').stack('id',dropna=False)
index data
timestamp id
2017-01-01 1 1.0 10.0
2 NaN NaN
2017-02-01 1 2.0 11.0
2 4.0 1.0
2017-03-01 1 NaN NaN
2 5.0 2.0
2017-04-01 1 3.0 13.0
2 NaN NaN
2017-05-01 1 NaN NaN
2 6.0 9.0
如果您想要显示更像上面的内容,请添加reset_index().set_index('id')
。特别注意使用dropna=False
堆栈来保留NaN占位符。如果没有这个,stack / unstack方法就会让你回到你开始的地方。
此方法自动包含min&最多日期,以及至少一个时间戳的所有日期。如果每个人都缺少内部时间戳,那么您需要添加resample
这样的内容:
full_df.set_index(['timestamp','id']).unstack('id')\
.resample('MS').mean()\
.stack('id',dropna=False)