Resampling innerhalb eines Pandas MultiIndex

Lesezeit: 9 Minuten

Resampling innerhalb eines Pandas
Schlangen McGee

Ich habe einige hierarchische Daten, die zu Zeitreihendaten führen, die ungefähr so ​​​​aussehen:

df = pandas.DataFrame(
    {'value_a': values_a, 'value_b': values_b},
    index=[states, cities, dates])
df.index.names = ['State', 'City', 'Date']
df

                               value_a  value_b
State   City       Date                        
Georgia Atlanta    2012-01-01        0       10
                   2012-01-02        1       11
                   2012-01-03        2       12
                   2012-01-04        3       13
        Savanna    2012-01-01        4       14
                   2012-01-02        5       15
                   2012-01-03        6       16
                   2012-01-04        7       17
Alabama Mobile     2012-01-01        8       18
                   2012-01-02        9       19
                   2012-01-03       10       20
                   2012-01-04       11       21
        Montgomery 2012-01-01       12       22
                   2012-01-02       13       23
                   2012-01-03       14       24
                   2012-01-04       15       25

Ich würde gerne Zeit-Resampling pro Stadt durchführen, also so etwas wie

df.resample("2D", how="sum")

würde ausgeben

                             value_a  value_b
State   City       Date                        
Georgia Atlanta    2012-01-01        1       21
                   2012-01-03        5       25
        Savanna    2012-01-01        9       29
                   2012-01-03       13       33
Alabama Mobile     2012-01-01       17       37
                   2012-01-03       21       41
        Montgomery 2012-01-01       25       45
                   2012-01-03       29       49

wie es ist, df.resample('2D', how='sum') erwischt mich

TypeError: Only valid with DatetimeIndex or PeriodIndex

Fair genug, aber ich würde erwarten, dass dies funktioniert:

>>> df.swaplevel('Date', 'State').resample('2D', how='sum')
TypeError: Only valid with DatetimeIndex or PeriodIndex

An diesem Punkt gehen mir wirklich die Ideen aus … kann mir Stack und Unstack irgendwie helfen?

1641746846 145 Resampling innerhalb eines Pandas
unutbu

pd.Grouper

ermöglicht die Angabe einer “groupby-Anweisung für ein Zielobjekt”. Insbesondere können Sie damit nach Datum gruppieren, auch wenn df.index ist kein DatetimeIndex:

df.groupby(pd.Grouper(freq='2D', level=-1))

Der level=-1 erzählt pd.Grouper um nach den Daten in der letzten Ebene des MultiIndex zu suchen. Darüber hinaus können Sie dies in Verbindung mit anderen Stufenwerten aus dem Index verwenden:

level_values = df.index.get_level_values
result = (df.groupby([level_values(i) for i in [0,1]]
                      +[pd.Grouper(freq='2D', level=-1)]).sum())

Sieht etwas komisch aus, aber using_Grouper erweist sich als viel schneller als mein ursprünglicher Vorschlag, using_reset_index:

import numpy as np
import pandas as pd
import datetime as DT

def using_Grouper(df):
    level_values = df.index.get_level_values
    return (df.groupby([level_values(i) for i in [0,1]]
                       +[pd.Grouper(freq='2D', level=-1)]).sum())

def using_reset_index(df):
    df = df.reset_index(level=[0, 1])
    return df.groupby(['State','City']).resample('2D').sum()

def using_stack(df):
    # http://stackoverflow.com/a/15813787/190597
    return (df.unstack(level=[0,1])
              .resample('2D').sum()
              .stack(level=[2,1])
              .swaplevel(2,0))

def make_orig():
    values_a = range(16)
    values_b = range(10, 26)
    states = ['Georgia']*8 + ['Alabama']*8
    cities = ['Atlanta']*4 + ['Savanna']*4 + ['Mobile']*4 + ['Montgomery']*4
    dates = pd.DatetimeIndex([DT.date(2012,1,1)+DT.timedelta(days = i) for i in range(4)]*4)
    df = pd.DataFrame(
        {'value_a': values_a, 'value_b': values_b},
        index = [states, cities, dates])
    df.index.names = ['State', 'City', 'Date']
    return df

def make_df(N):
    dates = pd.date_range('2000-1-1', periods=N)
    states = np.arange(50)
    cities = np.arange(10)
    index = pd.MultiIndex.from_product([states, cities, dates], 
                                       names=['State', 'City', 'Date'])
    df = pd.DataFrame(np.random.randint(10, size=(len(index),2)), index=index,
                      columns=['value_a', 'value_b'])
    return df

df = make_orig()
print(using_Grouper(df))

ergibt

                               value_a  value_b
State   City       Date                        
Alabama Mobile     2012-01-01       17       37
                   2012-01-03       21       41
        Montgomery 2012-01-01       25       45
                   2012-01-03       29       49
Georgia Atlanta    2012-01-01        1       21
                   2012-01-03        5       25
        Savanna    2012-01-01        9       29
                   2012-01-03       13       33

Hier ist ein Benchmark-Vergleich using_Grouper, using_reset_index, using_stack auf einem 5000-Zeilen-DataFrame:

In [30]: df = make_df(10)

In [34]: len(df)
Out[34]: 5000

In [32]: %timeit using_Grouper(df)
100 loops, best of 3: 6.03 ms per loop

In [33]: %timeit using_stack(df)
10 loops, best of 3: 22.3 ms per loop

In [31]: %timeit using_reset_index(df)
1 loop, best of 3: 659 ms per loop

  • Tut mir leid, ich habe nicht genug Erfahrung mit Pandas, um das zu sagen. Das obige ist eher ein Workaround als eine Lösung. df.reset_index kann eine langsame Operation sein und es wäre viel schöner, wenn dies ohne sie getan werden könnte.

    – unutbu

    4. Apr. ’13 um 13:26

  • Interessanterweise ist dies performanter als das Stapeln und Entstapeln: In [561]: timeit.timeit(“von hauptsächlich df importieren; df.reset_index(level=[0,1]).gruppiere nach([‘State’, ‘City’]).resample(‘2D’, how=’sum’)”, number=1000) Out[561]: 7.496185064315796 Zoll [562]: timeit.timeit(“von hauptsächlich df importieren; df.unstack(level=[0,1]).resample(‘2D’, how=’sum’).stack(level=[2,1]).swaplevel(2,0)”, Zahl=1000) Aus[562]: 10.618878841400146

    – Schlangen McGee

    4. Apr. ’13 um 15:43


  • Ich denke, die wahre Antwort hier lautet: “Wenn Sie diese Art von Berechnungen durchführen, sollten Sie mit einem Groupby-Objekt arbeiten, nicht mit einem hierarchischen Index.”

    – Schlangen McGee

    4. Apr. ’13 um 15:44

  • @unutbu “Entschuldigung, ich habe nicht genug Erfahrung mit Pandas, um das zu sagen.” Lustig das zu lesen, 1000+ Antworten später…

    – Def_Os

    16. September ’16 um 1:45

  • @Def_Os: Glücklicherweise 1000+ Antworten später kann ich sagen, dass es eine schnellere Lösung gibt – verwenden Sie pd.Grouper.

    – unutbu

    16. Sep. ’16 um 9:19

Resampling innerhalb eines Pandas
fpersyn

Du brauchst die groupby() Methode und versehen sie mit a pd.Grouper für jede Ebene Ihres MultiIndex, die Sie im resultierenden DataFrame beibehalten möchten. Sie können dann eine Operation Ihrer Wahl anwenden.

Um Datums- oder Zeitstempelebenen neu abzutasten, müssen Sie die freq Argument mit der Häufigkeit der Wahl — ein ähnlicher Ansatz mit pd.TimeGrouper() wird zu Gunsten von verworfen pd.Grouper() mit dem freq Argumente gesetzt.

Dies sollte Ihnen den DataFrame geben, den Sie benötigen:

df.groupby([pd.Grouper(level="State"), 
            pd.Grouper(level="City"), 
            pd.Grouper(level="Date", freq='2D')]
          ).sum()

Der Zeitreihen-Leitfaden in der Pandas-Dokumentation beschreibt resample() wie:

… eine zeitbasierte groupby, gefolgt von einer Reduktionsmethode für jede ihrer Gruppen.

Daher verwenden groupby() sollte technisch der gleiche Vorgang sein wie bei der Verwendung .resample() auf einem DataFrame mit einem einzelnen Index.

Der gleiche Absatz weist auf die Kochbuchabschnitt zum Resampling für fortgeschrittene Beispiele, bei denen der Eintrag ‘Gruppierung mit einem MultiIndex’ für diese Frage sehr relevant ist. Hoffentlich hilft das.

  • Im Gegensatz zu vielen verworrenen Antworten auf dieses Problem ist dies eine leicht verständliche Lösung, die zu leicht lesbarem Code führt.

    – Der McG

    23. Mai ’19 um 15:59

  • Die beste Antwort.

    – dsugasa

    11. September ’19 um 15:45 Uhr

Eine Alternative mit Stack/Unstack

df.unstack(level=[0,1]).resample('2D', how='sum').stack(level=[2,1]).swaplevel(2,0)

                               value_a  value_b
State   City       Date
Georgia Atlanta    2012-01-01        1       21
Alabama Mobile     2012-01-01       17       37
        Montgomery 2012-01-01       25       45
Georgia Savanna    2012-01-01        9       29
        Atlanta    2012-01-03        5       25
Alabama Mobile     2012-01-03       21       41
        Montgomery 2012-01-03       29       49
Georgia Savanna    2012-01-03       13       33

Anmerkungen:

  1. Keine Ahnung vom Leistungsvergleich
  2. Möglicher Panda-Bug – stack(level=[2,1]) hat funktioniert, aber stack(level=[1,2]) fehlgeschlagen

  • Das war wirklich hilfreich!

    – jarandaf

    1. Apr. ’16 um 10:20

  • Ich hatte Probleme mit der Berechnung pct_change gleich danach. Ähnliches Problem wie hier. Am Ende habe ich folgendes gemacht: reset_index, sort_values, groupby, pct_change (wie im Link)

    – Shadi

    3. August ’17 um 9:58

1641746847 426 Resampling innerhalb eines Pandas
Kamil Sindi

Das funktioniert:

df.groupby(level=[0,1]).apply(lambda x: x.set_index('Date').resample('2D', how='sum'))

                               value_a  value_b
State   City       Date
Alabama Mobile     2012-01-01       17       37
                   2012-01-03       21       41
        Montgomery 2012-01-01       25       45
                   2012-01-03       29       49
Georgia Atlanta    2012-01-01        1       21
                   2012-01-03        5       25
        Savanna    2012-01-01        9       29
                   2012-01-03       13       33

Wenn die Spalte Datum Zeichenfolgen enthält, konvertieren Sie sie vorher in Datum/Uhrzeit:

df['Date'] = pd.to_datetime(df['Date'])

1641746847 905 Resampling innerhalb eines Pandas
Josh D

Ich hatte das gleiche Problem, brach mir eine Weile den Kopf, aber dann las ich die Dokumentation der .resample Funktion in der 0.19.2 Dokumente, und ich sehe, es gibt ein neues kwarg namens “level”, die Sie verwenden können, um eine Ebene in einem MultiIndex anzugeben.

Edit: Weitere Details im “Was gibt’s Neues” Sektion.

  • Beantwortet nicht wirklich die Frage, wann Sie ein Resampling durchführen müssen, während mehrere Indizes beibehalten werden. In den Dokumenten muss level kwarg ein datetime-ähnlicher Parameter sein und die Frage bezog sich auf sekundäre Gruppierungsspalten, die nicht auf Datetime basieren

    – nachonachoman

    1. Juni ’17 um 17:50

1641746847 200 Resampling innerhalb eines Pandas
Geoff

Ich weiß, dass diese Frage ein paar Jahre alt ist, aber ich hatte das gleiche Problem und bin zu einer einfacheren Lösung gekommen, die 1 Zeile erfordert:

>>> import pandas as pd
>>> ts = pd.read_pickle('time_series.pickle')
>>> ts
xxxxxx1  yyyyyyyyyyyyyyyyyyyyyy1  2012-07-01     1
                                  2012-07-02    13
                                  2012-07-03     1
                                  2012-07-04     1
                                  2012-07-05    10
                                  2012-07-06     4
                                  2012-07-07    47
                                  2012-07-08     0
                                  2012-07-09     3
                                  2012-07-10    22
                                  2012-07-11     3
                                  2012-07-12     0
                                  2012-07-13    22
                                  2012-07-14     1
                                  2012-07-15     2
                                  2012-07-16     2
                                  2012-07-17     8
                                  2012-07-18     0
                                  2012-07-19     1
                                  2012-07-20    10
                                  2012-07-21     0
                                  2012-07-22     3
                                  2012-07-23     0
                                  2012-07-24    35
                                  2012-07-25     6
                                  2012-07-26     1
                                  2012-07-27     0
                                  2012-07-28     6
                                  2012-07-29    23
                                  2012-07-30     0
                                                ..
xxxxxxN  yyyyyyyyyyyyyyyyyyyyyyN  2014-06-02     0
                                  2014-06-03     1
                                  2014-06-04     0
                                  2014-06-05     0
                                  2014-06-06     0
                                  2014-06-07     0
                                  2014-06-08     2
                                  2014-06-09     0
                                  2014-06-10     0
                                  2014-06-11     0
                                  2014-06-12     0
                                  2014-06-13     0
                                  2014-06-14     0
                                  2014-06-15     0
                                  2014-06-16     0
                                  2014-06-17     0
                                  2014-06-18     0
                                  2014-06-19     0
                                  2014-06-20     0
                                  2014-06-21     0
                                  2014-06-22     0
                                  2014-06-23     0
                                  2014-06-24     0
                                  2014-06-25     4
                                  2014-06-26     0
                                  2014-06-27     1
                                  2014-06-28     0
                                  2014-06-29     0
                                  2014-06-30     1
                                  2014-07-01     0
dtype: int64
>>> ts.unstack().T.resample('W', how='sum').T.stack()
xxxxxx1  yyyyyyyyyyyyyyyyyyyyyy1  2012-06-25/2012-07-01      1
                                  2012-07-02/2012-07-08     76
                                  2012-07-09/2012-07-15     53
                                  2012-07-16/2012-07-22     24
                                  2012-07-23/2012-07-29     71
                                  2012-07-30/2012-08-05     38
                                  2012-08-06/2012-08-12    258
                                  2012-08-13/2012-08-19    144
                                  2012-08-20/2012-08-26    184
                                  2012-08-27/2012-09-02    323
                                  2012-09-03/2012-09-09    198
                                  2012-09-10/2012-09-16    348
                                  2012-09-17/2012-09-23    404
                                  2012-09-24/2012-09-30    380
                                  2012-10-01/2012-10-07    367
                                  2012-10-08/2012-10-14    163
                                  2012-10-15/2012-10-21    338
                                  2012-10-22/2012-10-28    252
                                  2012-10-29/2012-11-04    197
                                  2012-11-05/2012-11-11    336
                                  2012-11-12/2012-11-18    234
                                  2012-11-19/2012-11-25    143
                                  2012-11-26/2012-12-02    204
                                  2012-12-03/2012-12-09    296
                                  2012-12-10/2012-12-16    146
                                  2012-12-17/2012-12-23     85
                                  2012-12-24/2012-12-30    198
                                  2012-12-31/2013-01-06    214
                                  2013-01-07/2013-01-13    229
                                  2013-01-14/2013-01-20    192
                                                          ...
xxxxxxN  yyyyyyyyyyyyyyyyyyyyyyN  2013-12-09/2013-12-15      3
                                  2013-12-16/2013-12-22      0
                                  2013-12-23/2013-12-29      0
                                  2013-12-30/2014-01-05      1
                                  2014-01-06/2014-01-12      3
                                  2014-01-13/2014-01-19      6
                                  2014-01-20/2014-01-26     11
                                  2014-01-27/2014-02-02      0
                                  2014-02-03/2014-02-09      1
                                  2014-02-10/2014-02-16      4
                                  2014-02-17/2014-02-23      3
                                  2014-02-24/2014-03-02      1
                                  2014-03-03/2014-03-09      4
                                  2014-03-10/2014-03-16      0
                                  2014-03-17/2014-03-23      0
                                  2014-03-24/2014-03-30      9
                                  2014-03-31/2014-04-06      1
                                  2014-04-07/2014-04-13      1
                                  2014-04-14/2014-04-20      1
                                  2014-04-21/2014-04-27      2
                                  2014-04-28/2014-05-04      8
                                  2014-05-05/2014-05-11      7
                                  2014-05-12/2014-05-18      5
                                  2014-05-19/2014-05-25      2
                                  2014-05-26/2014-06-01      8
                                  2014-06-02/2014-06-08      3
                                  2014-06-09/2014-06-15      0
                                  2014-06-16/2014-06-22      0
                                  2014-06-23/2014-06-29      5
                                  2014-06-30/2014-07-06      1
dtype: int64

ts.unstack().T.resample('W', how='sum').T.stack() ist alles was es braucht! Sehr einfach und scheint ziemlich performant zu sein. Die Gurke, die ich einlese, ist 331M, also ist dies eine ziemlich kräftige Datenstruktur; Das Resampling dauert auf meinem MacBook Pro nur ein paar Sekunden.

  • Beantwortet nicht wirklich die Frage, wann Sie ein Resampling durchführen müssen, während mehrere Indizes beibehalten werden. In den Dokumenten muss level kwarg ein datetime-ähnlicher Parameter sein und die Frage bezog sich auf sekundäre Gruppierungsspalten, die nicht auf Datetime basieren

    – nachonachoman

    1. Juni ’17 um 17:50

Resampling innerhalb eines Pandas
LondonRob

Ich habe die Effizienz davon nicht überprüft, aber meine instinktive Art, Datetime-Operationen für einen Multi-Index durchzuführen, war eine Art manuellen “Split-Apply-Combine”-Prozess unter Verwendung eines Wörterbuchverständnisses.

Angenommen, Ihr DataFrame ist nicht indiziert. (Du kannst tun .reset_index() zuerst) funktioniert das wie folgt:

  1. Nach den Spalten ohne Datum gruppieren
  2. Setze “Datum” als Index und sample jedes Stück neu
  3. Zusammenbau mit pd.concat

Der endgültige Code sieht wie folgt aus:

pd.concat({g: x.set_index("Date").resample("2D").mean()
                   for g, x in house.groupby(["State", "City"])})

.

226350cookie-checkResampling innerhalb eines Pandas MultiIndex

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

Privacy policy