2017-05-31 46 views
2

我試圖重新索引一個數據幀相對於索引的第二級。我有一個數據框,第一級索引是用戶ID,第二級是日期。例如:大熊貓馴化MultiIndex相對於任意級別

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,但在此用例中不起作用。有任何想法嗎?

回答

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首先需要通過idxmax idxminloc選擇具有agg數據:

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)) 
+0

這很接近,但我不需要每日數據。我每月都需要它。不幸的是,將「D」更改爲「M」不起作用,因爲它提供了月結束日期(沒有數據,因此您只能得到全零「 – Charles

+2

並且如果使用'MS'而不是'M'? – jezrael

+0

完美工作。謝謝! – Charles

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爲datetime D型第一...

+0

嗨,我認爲這是類似於我想要完成的,但我不是試圖縮減數據的樣本。我有每月的數據,我需要每月的數據,我只需要填寫缺失的月份。 – Charles

+0

@Charles,這是否意味着「12-01-2010」是「2010年12月1日」? – MaxU

+0

是的,抱歉有任何混淆。 – Charles

3

使用groupbyagg得到'start''end'日期和共建成立tuple s到reindex用。

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