4

次のような秒単位の解像度を持つ、不規則にインデックス化された時系列のデータがあります。

import pandas as pd
idx = ['2012-01-01 12:43:35', '2012-03-12 15:46:43', 
       '2012-09-26 18:35:11', '2012-11-11 2:34:59']
status = [1, 0, 1, 0]
df = pd.DataFrame(status, index=idx, columns = ['status'])
df = df.reindex(pd.to_datetime(df.index))

In [62]: df
Out[62]: 
                     status
2012-01-01 12:43:35       1
2012-03-12 15:46:43       0
2012-09-26 18:35:11       1
2012-11-11 02:34:59       0

ステータスが 1 である年の端数に興味があります。現在私が行っている方法はdf、年に 1 秒ごとにインデックスを再作成し、次のような順方向の塗りつぶしを使用することです。

full_idx = pd.date_range(start = '1/1/2012', end = '12/31/2012', freq='s')
df1 = df.reindex(full_idx, method='ffill')

これは、次のようなステータスDataFrameの時間の割合を確認するために、平均を計算できるその年のすべての秒を含むa を返します。1

In [66]: df1
Out[66]: 
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 31536001 entries, 2012-01-01 00:00:00 to 2012-12-31 00:00:00
Freq: S
Data columns:
status    31490186  non-null values
dtypes: float64(1)


In [67]: df1.status.mean()
Out[67]: 0.31953371123308066

問題は、大量のデータに対してこれを行う必要があり、1 年に 1 秒ごとにインデックスを再作成することは、これまでで最もコストのかかる操作であることです。

これを行うためのより良い方法は何ですか?

4

2 に答える 2

3

不規則な時系列のエントリ間の時間差を計算する pandas メソッドはないようですが、時系列インデックスをオブジェクトの配列に変換する便利な方法があり、減算によってオブジェクトdatetime.datetimeに変換できます。datetime.timedelta

In [6]: start_end = pd.DataFrame({'status': [0, 0]},
                                 index=[pd.datetools.parse('1/1/2012'),
                                        pd.datetools.parse('12/31/2012')])

In [7]: df = df.append(start_end).sort()

In [8]: df
Out[8]: 
                     status
2012-01-01 00:00:00       0
2012-01-01 12:43:35       1
2012-03-12 15:46:43       0
2012-09-26 18:35:11       1
2012-11-11 02:34:59       0
2012-12-31 00:00:00       0

In [9]: pydatetime = pd.Series(df.index.to_pydatetime(), index=df.index)

In [11]: df['duration'] = pydatetime.diff().shift(-1).\
              map(datetime.timedelta.total_seconds, na_action='ignore')

In [16]: df
Out[16]: 
                     status  duration
2012-01-01 00:00:00       0     45815
2012-01-01 12:43:35       1   6145388
2012-03-12 15:46:43       0  17117308
2012-09-26 18:35:11       1   3916788
2012-11-11 02:34:59       0   4310701
2012-12-31 00:00:00       0       NaN

In [17]: (df.status * df.duration).sum() / df.duration.sum()
Out[17]: 0.31906950786402843

ノート:

  • status最初のタイムスタンプの前にゼロを設定したため、回答が異なっているように見えますがdf1、転送する開始値がなく、pandas mean() によって NA 値が除外されているため、これらのエントリは NA です。
  • timedelta.total_seconds()は Python 2.7 の新機能です。
  • この方法と再インデックス付けのタイミングの比較:

    In [8]: timeit delta_method(df)
    1000 loops, best of 3: 1.3 ms per loop
    
    In [9]: timeit redindexing(df)
    1 loops, best of 3: 2.78 s per loop
    
于 2013-01-05T07:10:49.190 に答える