2013-03-14 12 views
9

Gibt es eine "Kochbuch" -Methode zum Resampling eines DataFrame mit (halb-) unregelmäßigen Perioden?Resampling mit benutzerdefinierten Zeiträumen

Ich habe einen Datensatz in einem täglichen Intervall und möchte, dass es resample, was manchmal (in der wissenschaftlichen Literatur) dekad ist. Ich denke nicht, dass es einen richtigen englischen Begriff dafür gibt, aber es ist im Grunde einen Monat in drei ~ zehn Tage Teile hacken, wo der dritte ein Rest von etwas zwischen 8 und 11 Tagen ist.

Ich habe selbst zwei Lösungen entwickelt, eine spezielle für diesen Fall und eine allgemeinere für unregelmäßige Perioden. Aber beide sind nicht wirklich gut, also ist es unglaublich, wie andere mit solchen Situationen umgehen.

Fangen wir mit der Erstellung einige Beispieldaten starten:

import pandas as pd 

begin = pd.datetime(2013,1,1) 
end = pd.datetime(2013,2,20) 

dtrange = pd.date_range(begin, end) 

p1 = np.random.rand(len(dtrange)) + 5 
p2 = np.random.rand(len(dtrange)) + 10 

df = pd.DataFrame({'p1': p1, 'p2': p2}, index=dtrange) 

Das erste, was ich mit kam durch einzelne Monate Gruppierung (YYYYMM) und dann manuell schneiden. Wie:

def to_dec1(data, func): 

    # create the indexes, start of the ~10day period 
    idx1 = pd.datetime(data.index[0].year, data.index[0].month, 1) 
    idx2 = idx1 + datetime.timedelta(days=10) 
    idx3 = idx2 + datetime.timedelta(days=10) 

    # slice the period and perform function 
    oneday = datetime.timedelta(days=1) 
    fir = func(data.ix[:idx2 - oneday].values, axis=0) 
    sec = func(data.ix[idx2:idx3 - oneday].values, axis=0) 
    thi = func(data.ix[idx3:].values, axis=0) 

    return pd.DataFrame([fir,sec,thi], index=[idx1,idx2,idx3], columns=data.columns) 

dfmean = df.groupby(lambda x: x.strftime('%Y%m'), group_keys=False).apply(to_dec1, np.mean) 

was zur Folge hat:

print dfmean 

        p1   p2 
2013-01-01 5.436778 10.409845 
2013-01-11 5.534509 10.482231 
2013-01-21 5.449058 10.454777 
2013-02-01 5.685700 10.422697 
2013-02-11 5.578137 10.532180 
2013-02-21  NaN  NaN 

Beachten Sie, dass Sie immer einen vollen Monat der ‚dekads‘ im Gegenzug bekommen, es ist nicht ein Problem und leicht zu entfernen, wenn nötig.

Die andere Lösung bietet eine Reihe von Daten, bei denen Sie den DataFrame zerhacken und eine Funktion für jedes Segment ausführen. Es ist flexibler in Bezug auf die Perioden, die Sie möchten.

def to_dec2(data, dts, func): 

    chucks = [] 
    for n,start in enumerate(dts[:-1]): 

     end = dts[n+1] - datetime.timedelta(days=1) 
     chucks.append(func(data.ix[start:end].values, axis=0)) 

    return pd.DataFrame(chucks, index=dts[:-1], columns=data.columns) 

dfmean2 = to_dec2(df, dfmean.index, np.mean) 

Beachten Sie, dass ich den Index des vorherigen Ergebnisses als den Bereich der Daten verwenden, um etwas Zeit zu sparen, die es selbst "baut".

Was wäre der beste Weg, um diese Fälle zu behandeln? Gibt es vielleicht eine etwas mehr eingebaute Methode in Pandas?

+0

für den allgemeineren Fall könnten Sie auf einem Multi-Index von [Datum, NUM_OF_DAYS] GROUPBY, (Ihre Routine leicht, diese Gruppen füllen könnte, wo immer Ihr sie wollen), dann wie normale GROUPBY. Es gibt wahrscheinlich eine effizientere Möglichkeit, dies mit TimeGrouper auf jeden Fall zu tun (aber ich muss darüber nachdenken) – Jeff

Antwort

7

Wenn Sie numpy 1.7 verwenden, können Sie datetime64 & timedelta64 Arrays verwenden, um die Berechnung zu tun:

die Beispieldaten erstellen:

import pandas as pd 
import numpy as np 

begin = pd.datetime(2013,1,1) 
end = pd.datetime(2013,2,20) 

dtrange = pd.date_range(begin, end) 

p1 = np.random.rand(len(dtrange)) + 5 
p2 = np.random.rand(len(dtrange)) + 10 

df = pd.DataFrame({'p1': p1, 'p2': p2}, index=dtrange) 

das Datum des Dekad berechnen:

d = df.index.day - np.clip((df.index.day-1) // 10, 0, 2)*10 - 1 
date = df.index.values - np.array(d, dtype="timedelta64[D]") 
df.groupby(date).mean() 

Die Ausgabe ist:

    p1   p2 
2013-01-01 5.413795 10.445640 
2013-01-11 5.516063 10.491339 
2013-01-21 5.539676 10.528745 
2013-02-01 5.783467 10.478001 
2013-02-11 5.358787 10.579149 
+0

Danke, funktioniert wie ein Charme. –

2

Mit Hyry Daten und Lösung für die Berechnung der d Variable, können wir tun auch die folgenden in Pandas 0,11-dev oder höher (unabhängig von numpy Version):

In [18]: from datetime import timedelta 

In [23]: pd.Series([ timedelta(int(i)) for i in d ]) 
Out[23]: 
0    00:00:00 
1  1 days, 00:00:00 
2  2 days, 00:00:00 
3  3 days, 00:00:00 
4  4 days, 00:00:00 
5  5 days, 00:00:00 
6  6 days, 00:00:00 
7  7 days, 00:00:00 
8  8 days, 00:00:00 
9  9 days, 00:00:00 
10   00:00:00 

47 6 days, 00:00:00 
48 7 days, 00:00:00 
49 8 days, 00:00:00 
50 9 days, 00:00:00 
Length: 51, dtype: timedelta64[ns] 

Das Datum Similary aufgebaut ist, oben

date = pd.Series(df.index) - pd.Series([ timedelta(int(i)) for i in d ]) 
df.groupby(date.values).mean() 
+0

Es ist nicht in 10.1, ich laufe nicht dev Versionen.Gut zu wissen für die Zukunft, danke! –

Verwandte Themen