2017-05-31 2 views
2

Ich versuche, einen Datenrahmen relativ zur zweiten Ebene eines Index neu zu indizieren. Ich habe einen Datenrahmen, wo die erste Ebene des Index Benutzerkennung ist und die zweite Ebene ist Datum. Zum Beispiel:Pandas Reindexing MultiIndex relativ zu Arbitrary Level

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']) 

Ich mag die Daten indizieren die fehlenden Daten zu füllen, aber nur für die Tage zwischen dem maximalen und minimalen Daten für jede „id“ -Gruppe. Der Benutzer "A" sollte fortlaufende monatliche Daten von Januar bis Dezember 2010 haben und Benutzer "B" sollte fortlaufende Daten zwischen April 2015 und Mai 2016 haben. Der Einfachheit halber nehmen wir an, dass ich die NaNs mit Nullen füllen möchte.

Andere ähnliche Fragen gehen davon aus, dass ich den gleichen date_range für alle Benutzer verwenden möchte, was in diesem Anwendungsfall nicht funktioniert. Irgendwelche Ideen?

Antwort

5

Ich glaube, Sie brauchen 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 

Aber wenn nur verarbeiten muss max und min dates müssen zuerst auswählen, um Daten mit agg von idxmax idxmin mit loc:

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

Das ist nahe, aber ich brauche keine täglichen Daten. Ich brauche es monatlich. Leider funktioniert das Ändern von "D" auf "M" nicht, weil es Monatsenddaten gibt (für die es keine Daten gibt, also erhalten Sie nur Nullen " – Charles

+2

Und wenn" MS "anstatt" M "verwenden? – jezrael

+0

Funktioniert perfekt. Vielen Dank! – Charles

4

Wollen Sie das?

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 i date in Datetime dtype erste umgewandelt haben ...

+0

Hallo, ich denke, das ist ähnlich zu dem, was ich versuche zu erreichen, aber ich versuche nicht, die Daten downsample. Ich habe monatliche Daten und brauche monatliche Daten, ich muss nur die fehlenden Monate ausfüllen. – Charles

+0

@Charles, bedeutet das, dass "12 -01-2010" der 1. Dezember 2010 ist? – MaxU

+0

Ja, Entschuldigung für Verwirrung. – Charles

3

Verwendung groupby und agg'start' und 'end' Daten zu erhalten und tuple s reindex mit aufgebaut bauen.

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 
Verwandte Themen