12

(半)不規則な期間でDataFrameをリサンプリングする「クックブック」の方法はありますか?

私は毎日の間隔でデータセットを持っており、それを時々(科学文献では)dekadと呼ばれるものにリサンプリングしたいと思っています。適切な英語の用語があるとは思いませんが、基本的には1か月を3〜10日の部分に分割し、3番目は8〜11日の残りの部分です。

私は自分で2つの解決策を考え出しました。1つはこの場合の特定の解決策であり、もう1つは不規則な期間のより一般的な解決策です。しかし、どちらも本当に良いものではないので、他の人がこれらのタイプの状況をどのように処理するかについては不思議です。

いくつかのサンプルデータの作成から始めましょう。

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)

その結果:

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

常に1か月分の「dekads」を受け取ることに注意してください。これは問題ではなく、必要に応じて簡単に削除できます。

もう1つのソリューションは、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)

前の結果のインデックスを日付の範囲として使用して、自分で「構築」する時間を節約できることに注意してください。

これらのケースを処理する最良の方法は何でしょうか?パンダにはもう少し組み込みの方法がありますか?

4

2 に答える 2

11

numpy 1.7を使用する場合は、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)

デカッドの日付を計算します。

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
于 2013-03-14T12:14:43.323 に答える
2

HYRYのデータとd変数の計算までのソリューションを使用して、pandas 0.11-dev以降で次のことも実行できます(numpyバージョンに関係なく)。

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]

日付は上記と同様に構成されます

date = pd.Series(df.index) - pd.Series([ timedelta(int(i)) for i in d ])
df.groupby(date.values).mean()
于 2013-03-14T12:31:00.490 に答える