2013-03-14 1 views
9

(半)不規則な期間でDataFrameを再サンプリングする「料理本」の方法はありますか?カスタム期間でリサンプリングする

私は毎日のデータセットを持っており、ときには(科学文献の)デカードという名前のデータセットに再サンプリングしたいと考えています。私はそれのための適切な英語の言葉があると思うが、基本的に3〜10日の部品で1ヶ月を切り刻む3番目の部分は8と11日の間の残りの部分です。

私は自分自身で2つの解決方法を考え出しました。具体的にはこのケースに対応し、より一般的なものは不規則な期間に発生しました。しかし、どちらも本当に良いわけではないので、他の人がこのような状況をどのように扱うかは、私が巧妙である。

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) 

私が思いついた最初のものは、個々ヶ月(YYYYMM)でグループ化して、それを手動でスライスされています

は、いくつかのサンプルデータを作成して開始します。以下のような:

になり
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) 

:あなたは常にリターンの「dekads」の完全な月を得る

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 

注、その問題ありませんし、必要に応じて取り外しが簡単。

他の解決策は、DataFrameを切り取り、各セグメントで機能を実行する日付の範囲を指定することによって機能します。あなたが望む期間の面でより柔軟性があります。

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) 

それを自分自身「を構築する」いくつかの時間を節約するために、日付の範囲として、以前の結果のインデックスを使用してイム注意。

これらのケースを処理するにはどうすればよいでしょうか?おそらくもう少しPandasの組み込みメソッドはありますか?

+0

より一般的なケースでは、[date、num_of_days]のマルチインデックスでグループ化することができます(あなたのルーチンは、あなたが望む場所にこれらのグループを簡単に入れることができます)。どのイベントでもTimeGrouperを使ってこれを行うより効率的な方法があります(でもそれについて考える必要があります)。 – Jeff

答えて

7

あなたは1.7 numpyのを使用する場合は、計算を行うためにdatetime64 & timedelta64配列を使用することができます。

サンプルデータを作成します。

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) 

はdekadの日付を計算します。

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() 

出力は次のとおりです。

    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 
変数の計算にHYRYのデータおよびソリューションアップを使用して
+0

ありがとうございます、魅力的です。 –

2

、私たちも行うことができます(関係なく、numpyのバージョンの)後に0.11-devのか、パンダに次の

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] 

日はにsimilary構築されます

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

10.1ではなく、devバージョンを実行しています。将来を知ってよかった、ありがとう! –

関連する問題