Pandas团体优雅的重新取样

时间:2017-09-15 09:22:46

标签: python pandas group-by

对于名为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  

因为数据集非常大,我想知道是否有比

更有效的方法
  1. full_df.groupby('id')
  2. 针对每个群组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)
    
  3. 使用新索引再次合并所有组

  4. 耗费时间,而且不是很优雅。有什么想法吗?

2 个答案:

答案 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)