2017-07-07 4 views
9

ich einen Datenrahmen haben, der wie folgtPandas fehlende Termine und Werte innerhalb der Gruppe Füllung

x = pd.DataFrame({'user': ['a','a','b','b'], 'dt': ['2016-01-01','2016-01-02', '2016-01-05','2016-01-06'], 'val': [1,33,2,1]}) 

sieht Was würde ich zu tun, um der Lage sein mag, ist die minimale und maximale Datum in der Datumsspalte finden und Erweitern Sie diese Spalte, um alle Daten dort zu haben, während Sie gleichzeitig 0 für die Spalte val ausfüllen. So ist die gewünschte Ausgabe ist

  dt user val 
0 2016-01-01 a 1 
1 2016-01-02 a 33 
2 2016-01-03 a 0 
3 2016-01-04 a 0 
4 2016-01-05 a 0 
5 2016-01-06 a 0 
6 2016-01-01 b 0 
7 2016-01-02 b 0 
8 2016-01-03 b 0 
9 2016-01-04 b 0 
10 2016-01-05 b 2 
11 2016-01-06 b 1 

Ich habe versucht, die Lösung erwähnt here und here aber sie sind nicht das, was ich bin nach. Alle Hinweise sehr geschätzt.

Antwort

8

Anfängliche Datenrahmen:

dt user val 
0 2016-01-01 a 1 
1 2016-01-02 a 33 
2 2016-01-05 b 2 
3 2016-01-06 b 1 

Zuerst konvertieren die Daten in Datetime:

x['dt'] = pd.to_datetime(x['dt']) 

Dann erzeugen die Daten und Unique User:

dates = x.set_index('dt').resample('D').asfreq().index 

>> DatetimeIndex(['2016-01-01', '2016-01-02', '2016-01-03', '2016-01-04', 
       '2016-01-05', '2016-01-06'], 
       dtype='datetime64[ns]', name='dt', freq='D') 

users = x['user'].unique() 

>> array(['a', 'b'], dtype=object) 

Dies wird Ihnen erlauben, Erstellen Sie einen MultiIndex:

idx = pd.MultiIndex.from_product((dates, users), names=['dt', 'user']) 

>> MultiIndex(levels=[[2016-01-01 00:00:00, 2016-01-02 00:00:00, 2016-01-03 00:00:00, 2016-01-04 00:00:00, 2016-01-05 00:00:00, 2016-01-06 00:00:00], ['a', 'b']], 
      labels=[[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5], [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]], 
      names=['dt', 'user']) 

Sie können das verwenden, um Ihre Datenrahmen indizieren:

x.set_index(['dt', 'user']).reindex(idx, fill_value=0).reset_index() 
Out: 
      dt user val 
0 2016-01-01 a 1 
1 2016-01-01 b 0 
2 2016-01-02 a 33 
3 2016-01-02 b 0 
4 2016-01-03 a 0 
5 2016-01-03 b 0 
6 2016-01-04 a 0 
7 2016-01-04 b 0 
8 2016-01-05 a 0 
9 2016-01-05 b 2 
10 2016-01-06 a 0 
11 2016-01-06 b 1 

, die von Nutzern sortiert können dann:

x.set_index(['dt', 'user']).reindex(idx, fill_value=0).reset_index().sort_values(by='user') 
Out: 
      dt user val 
0 2016-01-01 a 1 
2 2016-01-02 a 33 
4 2016-01-03 a 0 
6 2016-01-04 a 0 
8 2016-01-05 a 0 
10 2016-01-06 a 0 
1 2016-01-01 b 0 
3 2016-01-02 b 0 
5 2016-01-03 b 0 
7 2016-01-04 b 0 
9 2016-01-05 b 2 
11 2016-01-06 b 1 
+0

Das funktioniert. Vielen Dank. – broccoli

3

Wie @ayhan schlägt

x.dt = pd.to_datetime(x.dt) 

One-Liner Using meistens @ ayhans Ideen beim Einbauen stack/unstack und fill_value

x.set_index(
    ['dt', 'user'] 
).unstack(
    fill_value=0 
).asfreq(
    'D', fill_value=0 
).stack().sort_index(level=1).reset_index() 

      dt user val 
0 2016-01-01 a 1 
1 2016-01-02 a 33 
2 2016-01-03 a 0 
3 2016-01-04 a 0 
4 2016-01-05 a 0 
5 2016-01-06 a 0 
6 2016-01-01 b 0 
7 2016-01-02 b 0 
8 2016-01-03 b 0 
9 2016-01-04 b 0 
10 2016-01-05 b 2 
11 2016-01-06 b 1 
Verwandte Themen