Pandas füllen fehlende Daten und Werte innerhalb der Gruppe aus

Lesezeit: 5 Minuten

Ich habe einen Datenrahmen, der wie folgt aussieht

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

Ich möchte in der Lage sein, das minimale und maximale Datum in der Datumsspalte zu finden und diese Spalte zu erweitern, um alle Daten dort zu haben, während Sie gleichzeitig ausfüllen 0 für die val Säule. Die gewünschte Ausgabe ist also

            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 die hier und hier erwähnte Lösung ausprobiert, aber sie sind nicht das, was ich suche. Alle mögliche Hinweise sehr geschätzt.

Pandas fullen fehlende Daten und Werte innerhalb der Gruppe aus
ayhan

Anfangsdatenrahmen:

            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

Konvertieren Sie zuerst die Daten in datetime:

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

Generieren Sie dann die Daten und eindeutigen Benutzer:

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)

Auf diese Weise können Sie einen MultiIndex erstellen:

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

Damit können Sie Ihren DataFrame neu 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 dann nach Benutzern sortiert werden können:

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

  • In diesem Fall teilen sich alle Benutzer denselben Zeitbereich. Was ist, wenn jeder Benutzer einen anderen Datumsbereich hat? [min, max]?

    – luoshao23

    26. Okt ’18 um 2:38

  • @luoshao23 .MultiIndex.from_product ist eine Komfortfunktion für das kartesische Produkt, aber der Index kann auch auf andere Weise aufgebaut werden. Was für Daten hast du dafür? Wie speichern Sie beispielsweise Min und Max für jeden Benutzer? Kommt es von einem DataFrame?

    – ayhan

    26. Okt ’18 um 17:34

  • @ayhan Ja, ich mache ein date_range Verwenden Sie den Min/Max-Wert und verwenden Sie dann .MultiIndex.from_product um einen mehrstufigen Index für jeden Benutzer zu generieren. Endlich ich concat alle DataFrames zu einem DataFrame. Es funktioniert, während es viel Zeit in Anspruch nimmt. Haben Sie eine Idee, um die Effizienz zu verbessern?

    – luoshao23

    27. Okt. 18 um 14:15

  • @luoshao23 Wenn alle von einem einzigen DataFrame stammen, wäre es wahrscheinlich effizienter, den Multiindex separat zu generieren und den Reindex zu verwenden. Sie können verwenden MultiIndex.from_tuples zum Beispiel. Ich denke, es wäre besser, wenn Sie eine neue Frage mit einem Beispiel-DataFrame posten.

    – ayhan

    27. Okt. 18 um 21:30 Uhr

  • Ich habe viele Stunden lang gesucht, um eine Dataframe-Indexfrequenz von None in H zu konvertieren. Das hat funktioniert! Danke. dates = x.set_index('dt').resample('H').asfreq().index

    – Kip

    20. März ’19 um 19:54

1641999714 800 Pandas fullen fehlende Daten und Werte innerhalb der Gruppe aus
piRSquared

Wie @ayhan vorschlägt

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

Einzeiler, der hauptsächlich @ayhans Ideen verwendet, während er integriert wird 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

  • Diese Lösung ist besser als die akzeptierte Antwort. Es funktioniert auch, wenn es ein doppeltes Datum für den Benutzer gibt. Wenn es beispielsweise eine weitere Zeile mit “2016-01-01” und Benutzer “b” gab, würde die akzeptierte Lösung mit einem Fehler fehlschlagen – kann nicht von einer doppelten Achse neu indiziert werden. Aber diese Lösung funktioniert auch für solche Szenarien

    – Benutzer131476

    17. August ’20 bei 4:29


  • Wie wird sich dies ändern, wenn wir die minimalen/maximalen Daten innerhalb der Gruppe verwenden müssen (in diesem Fall “Benutzer”)? Grundsätzlich nur innerhalb der Gruppe fortlaufende Termine generieren/befüllen.

    – Vivek Payasi

    24. Januar ’21 um 15:48

Eine alte Frage mit bereits ausgezeichneten Antworten; Dies ist eine Alternative, mit der Komplett Funktion von pyjanitor das könnte bei der Abstraktion helfen, wenn explizit fehlende Zeilen generiert werden:

#pip install pyjanitor
import pandas as pd
import janitor as jn

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

# generate complete list of dates
dates = dict(dt = pd.date_range(x.dt.min(), x.dt.max(), freq='1D'))

# build the new dataframe, and fill nulls with 0
x.complete('user', dates, sort = True).fillna(0, downcast="infer")

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

.

457090cookie-checkPandas füllen fehlende Daten und Werte innerhalb der Gruppe aus

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy