Pandas重新索引MultiIndex相对于任意级别

时间:2017-05-31 17:32:50

标签: python pandas multi-index

我试图相对于索引的第二级重新索引数据帧。我有一个数据框,其中索引的第一级是用户ID,第二级是日期。例如:

pd.DataFrame({
'id': 3*['A'] + 5*['B'] + 4*['C'],
'date': ['01-01-2010', '02-01-2010', '12-01-2010',
         '04-01-2015', '05-01-2015', '03-01-2016', '04-01-2016', '05-01-2016',
         '01-01-2015', '02-01-2015', '03-01-2015', '04-01-2015'],
'value': np.random.randint(10,100, 12)})\
.set_index(['id', 'date'])

我想重新索引日期以填写缺失的日期,但仅限于每个" id"的最大日期和最小日期之间的日期。基。

例如用户" A"应该有2010年1月至12月的连续月度数据和用户" B"应该在2015年4月到2016年5月之间有连续日期。为简单起见,我们假设我想用零填充NaN。

与此类似的其他问题假设我想对所有用户使用相同的date_range,这在本用例中不起作用。有什么想法吗?

3 个答案:

答案 0 :(得分:5)

我认为您需要reset_index + groupby + resample + asfreq + fillna

np.random.seed(123)
df = pd.DataFrame({
'id': 3*['A'] + 5*['B'] + 4*['C'],
'date': ['01-01-2010', '02-01-2010', '12-01-2010',
         '04-01-2015', '05-01-2015', '03-01-2016', '04-01-2016', '05-01-2016',
         '01-01-2015', '02-01-2015', '03-01-2015', '04-01-2015'],
'value': np.random.randint(10,100, 12)})

df['date'] = pd.to_datetime(df['date'])
df = df.set_index(['id', 'date'])
print (df)
               value
id date             
A  2010-01-01     76
   2010-02-01     27
   2010-12-01     93
B  2015-04-01     67
   2015-05-01     96
   2016-03-01     57
   2016-04-01     83
   2016-05-01     42
C  2015-01-01     56
   2015-02-01     35
   2015-03-01     93
   2015-04-01     88
df1 = df.reset_index(level='id').groupby('id')['value'].resample('D').asfreq().fillna(0)
print (df1.head(10))
               value
id date             
A  2010-01-01   76.0
   2010-01-02    0.0
   2010-01-03    0.0
   2010-01-04    0.0
   2010-01-05    0.0
   2010-01-06    0.0
   2010-01-07    0.0
   2010-01-08    0.0
   2010-01-09    0.0
   2010-01-10    0.0

但是,如果只需要处理最大值和最小值dates,首先需要agg选择数据idxmax idxminloc

df = df.reset_index()
df1 = df.loc[df.groupby('id')['date'].agg(['idxmin', 'idxmax']).stack()]
print (df1)
   id       date  value
0   A 2010-01-01     76
2   A 2010-12-01     93
3   B 2015-04-01     67
7   B 2016-05-01     42
8   C 2015-01-01     56
11  C 2015-04-01     88

df1 = df1.set_index('date').groupby('id')['value'].resample('MS').asfreq().fillna(0)
print (df1.head(10))

答案 1 :(得分:4)

这就是你想要的吗?

In [52]: (df.reset_index().groupby('id')
    ...:    .apply(lambda x: x.set_index('date').resample('D').mean().fillna(0))
    ...: )
Out[52]:
               value
id date
A  2010-01-01   91.0
   2010-01-02    0.0
   2010-01-03    0.0
   2010-01-04    0.0
   2010-01-05    0.0
   2010-01-06    0.0
   2010-01-07    0.0
   2010-01-08    0.0
   2010-01-09    0.0
   2010-01-10    0.0
...              ...
C  2015-03-23    0.0
   2015-03-24    0.0
   2015-03-25    0.0
   2015-03-26    0.0
   2015-03-27    0.0
   2015-03-28    0.0
   2015-03-29    0.0
   2015-03-30    0.0
   2015-03-31    0.0
   2015-04-01   11.0

[823 rows x 1 columns]

PS我首先将date转换为日期时间dtype ...

答案 2 :(得分:3)

使用groupbyagg来获取'start''end'个日期,并使用。{/ p建立tuplereindex的设置。 >

m = dict(min='start', max='end')
df = df.reset_index().groupby('id').date.agg(['min', 'max']).rename(columns=m)
idx = [(i, d) for i, row in d2.iterrows() for d in pd.date_range(freq='MS', **row)]

df.reindex(idx, fill_value=0)

               value
id date             
A  2010-01-01     27
   2010-02-01     15
   2010-03-01      0
   2010-04-01      0
   2010-05-01      0
   2010-06-01      0
   2010-07-01      0
   2010-08-01      0
   2010-09-01      0
   2010-10-01      0
   2010-11-01      0
   2010-12-01     11
B  2015-04-01     10
   2015-05-01     94
   2015-06-01      0
   2015-07-01      0
   2015-08-01      0
   2015-09-01      0
   2015-10-01      0
   2015-11-01      0
   2015-12-01      0
   2016-01-01      0
   2016-02-01      0
   2016-03-01     42
   2016-04-01     15
   2016-05-01     71
C  2015-01-01     17
   2015-02-01     51
   2015-03-01     99
   2015-04-01     58