【徹底解説】pandas resampleで時系列データを自在に集計・変換
はじめに:時系列データ分析とPandasの力
データ分析において、時系列データは非常に一般的で重要な存在です。株価の変動、センサーデータの収集、気象情報の記録、ウェブサイトのアクセスログなど、私たちの周りには時間を追って記録されたデータが溢れています。これらの時系列データから有用な知見を得るためには、データの周期性やトレンドを捉えたり、異なる時間粒度でデータを比較したりする操作が不可欠となります。
Pythonのデータ分析ライブラリであるPandasは、時系列データの取り扱いに非常に長けています。特に、時系列データ専用のインデックス型であるDatetimeIndex
やPeriodIndex
を持つDataFrameやSeriesは、時間に基づいた様々な強力な操作を可能にします。
その中でも、時系列データの時間的な粒度(頻度)を変更するための中心的なメソッドがresample
です。resample
を使うことで、秒単位のデータを分単位や時間単位、日単位に集計したり(ダウンサンプリング)、逆に日単位のデータを時間単位や分単位に拡張したり(アップサンプリング)、特定の時間区間ごとにデータを処理したりすることができます。
この記事では、Pandasのresample
メソッドを徹底的に解説します。基本的な使い方から、豊富な引数の意味、アップサンプリング時の注意点、さまざまな応用例、そして類似メソッドとの違いまで、resample
をマスターするために必要な知識を網羅します。
この記事を読むことで、あなたは以下のことができるようになります。
resample
の基本的な概念と使い方を理解する。- ダウンサンプリングとアップサンプリングの違いを理解し、適切に使い分ける。
- 頻度エイリアス(Rule)を使いこなし、様々な時間粒度で集計・変換を行う。
closed
、label
、origin
などの引数を活用し、集計区間やラベルのタイムスタンプを自在に制御する。- アップサンプリングにおける欠損値処理(補間)の方法を学ぶ。
agg
メソッドを使った柔軟な集計方法を習得する。resample
、asfreq
、reindex
の違いを理解し、適切なメソッドを選択する。- 実際のデータ分析で
resample
を効果的に活用するための応用例を知る。
さあ、Pandas resample
の世界へ飛び込み、時系列データ分析のスキルを一段階レベルアップさせましょう。
1. 時系列データの基本:Pandasでの表現
resample
メソッドを使うためには、対象となるDataFrameやSeriesが時系列インデックスを持っている必要があります。通常、これはDatetimeIndex
またはPeriodIndex
です。最も一般的なのはDatetimeIndex
ですので、ここでは主にDatetimeIndex
を扱います。
時系列データを含むDataFrameを作成してみましょう。最も簡単な方法は、pd.date_range
関数を使って時系列インデックスを生成し、それをDataFrameのインデックスとして指定することです。
“`python
import pandas as pd
import numpy as np
サンプルデータの生成
2023年1月1日から1月3日までの各分ごとのタイムスタンプ
start_date = ‘2023-01-01 00:00:00’
end_date = ‘2023-01-03 23:59:00’
freq = ‘min’ # 分ごとの頻度
date_rng = pd.date_range(start=start_date, end=end_date, freq=freq)
データの作成(例:ランダムな数値と、特定のパターンを持つ数値)
データの数は len(date_rng) と同じになります
data = {
‘value1’: np.random.rand(len(date_rng)) * 100,
‘value2’: np.sin(np.arange(len(date_rng)) / 100) * 50 + 50
}
df = pd.DataFrame(data, index=date_rng)
print(“元のデータ(先頭5行):”)
print(df.head())
print(“\n元のデータ(末尾5行):”)
print(df.tail())
print(“\nインデックスの型:”)
print(df.index)
print(“\nデータの形状:”)
print(df.shape)
“`
このコードで、3日間(4320分)の分ごとのデータを持つDataFrameが作成されました。インデックスはDatetimeIndex
であり、resample
を使う準備が整っています。
2. resample
メソッドの基本概念と使い方
2.1 resample
とは? リサンプリングの概念
resample
(リサンプリング)とは、文字通り「サンプリングをやり直す」操作です。時系列データにおいて、これはデータの時間的な頻度(粒度)を変更することを意味します。
リサンプリングには大きく分けて2つの方向性があります。
- ダウンサンプリング (Downsampling): 頻度を下げる操作です。例えば、分単位のデータを時間単位や日単位に集計する場合などがこれにあたります。より粗い時間間隔に集約するため、通常は集計操作(合計、平均、最大、最小など)を伴います。
- アップサンプリング (Upsampling): 頻度を上げる操作です。例えば、日単位のデータを時間単位や分単位に拡張する場合などがこれにあたります。元のデータが存在しない新しいタイムスタンプが出現するため、通常は欠損値が発生し、その補間や穴埋めが必要になります。
resample
メソッドは、これらのダウンサンプリングとアップサンプリングの両方に対応しており、非常に柔軟な時系列データの集計・変換を可能にします。
2.2 resample
の基本的な使い方
resample
メソッドは、DataFrameまたはSeriesの時系列インデックス(DatetimeIndex
またはPeriodIndex
)に対して呼び出されます。
基本的な書式は以下のようになります。
“`python
df.resample(rule)
または
series.resample(rule)
“`
ここで、rule
はリサンプリングの頻度を指定する引数です。rule
には、Pandasが定義している頻度エイリアス(Frequency Alias)またはオフセットエイリアス(Offset Alias)と呼ばれる文字列を指定します。
resample
メソッドを呼び出すと、DatetimeIndexResampler
という特殊なオブジェクト(GroupByオブジェクトに似ています)が返されます。このオブジェクトに対して、集計関数(mean()
, sum()
, count()
, first()
, last()
, ohlc()
など)や補間関数(ffill()
, bfill()
)を適用することで、実際のリサンプリングと処理が行われます。
例:分単位データを時間単位の平均値にダウンサンプリングする
“`python
作成したサンプルデータ df を使用
時間単位 (‘H’) でリサンプリングし、各時間区間の平均値を計算
df_hourly_mean = df.resample(‘H’).mean()
print(“時間単位で平均値を集計したデータ(先頭5行):”)
print(df_hourly_mean.head())
print(“\nデータの形状:”)
print(df_hourly_mean.shape) # 72時間 = 3日 * 24時間
“`
元のデータは分単位(4320行)でしたが、'H'
(時間単位)でリサンプリングしてmean()
を適用した結果、時間単位(72行)のデータに集約されました。
2.3 頻度エイリアス(Rule)の重要性
resample
のrule
引数に指定する頻度エイリアスは非常に重要です。これは、新しい時間的な粒度と、その粒度で区切られた「ビン(bin)」または「区間」のサイズを定義します。
よく使われる頻度エイリアスの一部を以下に示します。
エイリアス | 説明 | 例 |
---|---|---|
S |
秒 | resample('S') |
min or T |
分 | resample('min') |
H |
時間 | resample('H') |
D |
日 | resample('D') |
W |
週(通常日曜日始まり) | resample('W') |
W-MON |
週(月曜日始まり) | resample('W-MON') |
M |
月末 | resample('M') |
MS |
月初 | resample('MS') |
BM |
営業月末 | resample('BM') |
BMS |
営業月初 | resample('BMS') |
Q |
四半期末 | resample('Q') |
QS |
四半期初 | resample('QS') |
BQ |
営業四半期末 | resample('BQ') |
BQS |
営業四半期初 | resample('BQS') |
Y or A |
年末 | resample('Y') |
YS or AS |
年初 | resample('YS') |
BY or BA |
営業年末 | resample('BY') |
BYS or BAS |
営業年初 | resample('BYS') |
これらは基本的なエイリアスですが、さらに細かく期間を指定することも可能です。例えば、'10T'
は10分ごと、'3H'
は3時間ごと、'2W'
は2週ごと、'5D'
は5日ごとといった指定ができます。
resample('10T')
resample('3H')
resample('5D')
rule
には、このように数字 + 頻度エイリアスの形式で、集計・変換の期間を指定します。
3. ダウンサンプリング:データを集約する
ダウンサンプリングは、より細かい時間粒度のデータを、より粗い時間粒度で集計する操作です。例えば、秒単位のセンサーデータを日単位の平均値に、日次の株価データを月次の終値に集約する場合などです。
ダウンサンプリングでは、指定したrule
に基づいて時間が区切られ、それぞれの時間区間(ビン)に含まれる元のデータに対して集計関数が適用されます。
3.1 よく使う集計関数
resample
オブジェクトに対して適用できる主な集計関数は以下の通りです。
count()
: 各ビンに含まれるデータ点の数sum()
: 各ビンの合計値mean()
: 各ビンの平均値median()
: 各ビンのメジアン(中央値)first()
: 各ビンの最初のデータ点last()
: 各ビンの最後のデータ点max()
: 各ビンの最大値min()
: 各ビンの最小値ohlc()
: 各ビンのOpen(開始値)、High(最高値)、Low(最低値)、Close(終値)
例:日次データの集計
分単位のサンプルデータ df
を、日次で集計してみましょう。
“`python
日次 (‘D’) でリサンプリングし、様々な集計を適用
df_daily = df.resample(‘D’)
df_daily_mean = df_daily.mean() # 日ごとの平均
df_daily_sum = df_daily.sum() # 日ごとの合計
df_daily_max = df_daily.max() # 日ごとの最大値
df_daily_min = df_daily.min() # 日ごとの最小値
df_daily_first = df_daily.first() # 各日最初のデータ
df_daily_last = df_daily.last() # 各日最後のデータ
df_daily_count = df_daily.count() # 各日のデータ数
print(“日ごとの平均値:”)
print(df_daily_mean)
print(“\n日ごとの合計値:”)
print(df_daily_sum)
print(“\n日ごとのデータ数:”)
print(df_daily_count) # 3日分のデータなので、各日 24 * 60 = 1440 件となるはず
“`
出力を見ると、各日のデータがそれぞれの集計関数で集約されていることがわかります。count()
の結果からは、各日正確に1440件(1分×60分×24時間)のデータが存在していることが確認できます。
3.2 ohlc()
関数
株価データなどでは、特定の期間(日、週など)の「始値 (Open)」「高値 (High)」「安値 (Low)」「終値 (Close)」を取得することがよくあります。resample
オブジェクトのohlc()
関数は、これを一括で行ってくれます。
ohlc()
は、元のDataFrame/Seriesが複数の列を持っていても、数値型の列に対してそれぞれohlcを計算し、MultiIndexを持つDataFrameを返します。
例:日次のOHLCを取得
“`python
日次 (‘D’) でリサンプリングし、OHLCを計算
df_daily_ohlc = df.resample(‘D’).ohlc()
print(“\n日ごとのOHLC:”)
print(df_daily_ohlc)
“`
結果として、元の列(value1
, value2
)ごとに、’open’, ‘high’, ‘low’, ‘close’の4つの集計値を持つMultiIndexのDataFrameが得られます。
3.3 複数の集計関数を一度に適用 (agg()
)
resample
オブジェクトに対して、複数の集計関数を一度に適用したい場合は、agg()
メソッドを使用します。これはPandasのGroupByオブジェクトに対するagg()
と同様の使い方ができます。
agg()
には、集計関数の名前(文字列)または関数オブジェクトのリスト、あるいは列ごとに異なる集計を指定するための辞書を渡すことができます。
例:日次で平均値と最大値を同時に計算
“`python
日次 (‘D’) でリサンプリングし、平均値と最大値をaggで計算
df_daily_agg = df.resample(‘D’).agg([‘mean’, ‘max’])
print(“\n日ごとの平均値と最大値(aggを使用):”)
print(df_daily_agg)
“`
例:列ごとに異なる集計関数を適用
“`python
日次 (‘D’) でリサンプリングし、列ごとに異なる集計をaggで計算
df_daily_agg_col = df.resample(‘D’).agg({
‘value1’: [‘mean’, ‘sum’],
‘value2’: [‘max’, ‘min’, ‘last’]
})
print(“\n列ごとに異なる集計(aggを使用):”)
print(df_daily_agg_col)
“`
agg()
を使うことで、リサンプリング後の集計を非常に柔軟に行うことができます。
3.4 ダウンサンプリングにおけるタイムスタンプの調整 (closed
, label
, origin
)
ダウンサンプリングでは、指定した頻度rule
で時間を区切りますが、その区間(ビン)の境界や、集計結果のインデックスとして使用するタイムスタンプをどのように決定するかを制御するための引数があります。特に重要なのがclosed
、label
、そしてv1.1で導入されたorigin
(または旧loffset
)です。
3.4.1 closed
引数
closed
引数は、各集計区間(ビン)のどちらの端を閉じた区間とするかを指定します。デフォルトは'left'
です。
closed='left'
: 区間の左端(開始時刻)を含み、右端(終了時刻)を含まない[start, end)
closed='right'
: 区間の左端(開始時刻)を含まず、右端(終了時刻)を含む(start, end]
これは特に区間の境界にデータが存在する場合に影響します。
例:時間単位集計における closed
の違い
サンプルデータは分単位です。時間単位('H'
)で集計する場合、デフォルトでは closed='left'
です。
“`python
2023-01-01 00:00 から 2023-01-01 00:59 までのデータが
2023-01-01 00:00 のインデックスに集計される (左端を含む)
デフォルト: closed=’left’
df_closed_left = df[‘2023-01-01 00:00:00′:’2023-01-01 01:00:00’].resample(‘H’).sum()
print(“closed=’left’ (デフォルト):”)
print(df_closed_left)
2023-01-01 00:00:00 のインデックスに 00:00から00:59までの合計が集計される
2023-01-01 01:00:00 のデータは次の区間 [01:00, 02:00) に含まれる
closed=’right’
df_closed_right = df[‘2023-01-01 00:00:00′:’2023-01-01 01:00:00’].resample(‘H’, closed=’right’).sum()
print(“\nclosed=’right’:”)
print(df_closed_right)
2023-01-01 01:00:00 のインデックスに (00:00, 01:00] の合計が集計される
つまり 00:01から01:00までのデータが含まれる
“`
結果を見ると、closed='left'
では区間の開始時刻(00:00:00
, 01:00:00
…)がインデックスになり、その時刻を含む区間が集計対象となります。closed='right'
では区間の終了時刻(01:00:00
, 02:00:00
…)がインデックスになり、その時刻を含む区間が集計対象となります。
3.4.2 label
引数
label
引数は、集計結果のインデックスとして区間の左端のタイムスタンプを使うか、右端のタイムスタンプを使うかを指定します。デフォルトは'left'
です。
label='left'
: 各区間の開始時刻をインデックスとして使用label='right'
: 各区間の終了時刻をインデックスとして使用
これもダウンサンプリングで特に重要です。closed
とlabel
はしばしば一緒に使われます。例えば、日次集計の結果を「その日の終わり」である23:59:59のタイムスタンプでラベル付けしたい場合などです。
例:日次集計における label
の違い
サンプルデータ df
を日次で集計し、label
の違いを見てみましょう。
“`python
日次 (‘D’) で集計
closed=’left’, label=’left’ (デフォルトの組み合わせ)
df_daily_default = df.resample(‘D’).mean()
print(“closed=’left’, label=’left’ (デフォルト):”)
print(df_daily_default.head())
インデックスは各日の00:00:00になる
closed=’right’, label=’right’
この組み合わせは、区間の終了時刻を含み、その時刻でラベル付けするためよく使われます。
df_daily_right = df.resample(‘D’, closed=’right’, label=’right’).mean()
print(“\nclosed=’right’, label=’right’:”)
print(df_daily_right.head())
インデックスは各日の23:59:59 (または次の日の00:00:00から1ナノ秒引いた値など、
厳密には区間の終了時刻に最も近いタイムスタンプ) になる
“`
label='right'
を使うと、例えば日次集計の場合、インデックスが各日の終わり(23:59:59のようなタイムスタンプ)になります。これは、集計対象期間の終了時点を示したい場合に便利です。
3.4.3 origin
引数 (v1.1以降推奨)
origin
引数は、集計区間を生成するための基準となる時刻を指定します。デフォルトでは、データの最初のタイムスタンプか、またはエポックタイム(1970-01-01 00:00:00 UTC)が使用されますが、これを明示的に制御できます。特に、特定の時刻を区切りの境界としたい場合に便利です。
例えば、毎日午前9時に日次集計を区切りたい場合などに使用できます。
origin
には以下の値を指定できます。
'start_day'
: データの最初の日の00:00:00'start_time'
: データの最初のタイムスタンプそのもの'end_day'
: データの最後の日の00:00:00'end_time'
: データの最後のタイムスタンプそのもの- 特定のタイムスタンプ (
pd.Timestamp(...)
)
origin
を指定すると、rule
で指定した頻度で、origin
を基準として等間隔に集計区間が生成されます。
例:毎日正午(12:00)を区切りとして日次集計する
通常の日次集計('D'
)は午前0時が区切りです。これを正午区切りにしてみましょう。
“`python
デフォルトの日次集計 (午前0時区切り)
df_daily_default_origin = df.resample(‘D’).sum()
print(“日次集計 (デフォルト origin):”)
print(df_daily_default_origin)
2023-01-01 00:00:00 インデックス -> 01/01 00:00 から 01/01 23:59 の合計
2023-01-02 00:00:00 インデックス -> 01/02 00:00 から 01/02 23:59 の合計
originを2023-01-01 12:00:00に設定して日次集計
区間は … [2022-12-31 12:00, 2023-01-01 12:00), [2023-01-01 12:00, 2023-01-02 12:00), … となる
label=’right’ にすると、区間の終了時刻 (例: 2023-01-02 12:00:00) がインデックスになる
df_daily_origin_12pm = df.resample(‘D’, origin=pd.Timestamp(‘2023-01-01 12:00:00′), label=’right’).sum()
print(“\n日次集計 (origin=2023-01-01 12:00:00, label=’right’):”)
print(df_daily_origin_12pm)
2023-01-02 12:00:00 インデックス -> 01/01 12:00 から 01/02 11:59 の合計
2023-01-03 12:00:00 インデックス -> 01/02 12:00 から 01/03 11:59 の合計
2023-01-04 12:00:00 インデックス -> 01/03 12:00 から 01/03 23:59 の合計 (最後のビン)
“`
このようにorigin
を使うことで、時間区切りの基準を柔軟に設定できます。これは、業務上の集計期間(例:営業日の締め時間)に合わせてリサンプリングしたい場合などに非常に役立ちます。
古いバージョンのPandasではloffset
引数が使われていましたが、これは非推奨となりorigin
に置き換えられました。origin
の方がより直感的で強力な機能を提供します。
4. アップサンプリング:データを拡張する
アップサンプリングは、より粗い時間粒度のデータを、より細かい時間粒度で拡張する操作です。例えば、日次のデータを時間単位や分単位に変換する場合などがこれにあたります。
アップサンプリングでは、指定したrule
に基づいて新しいタイムスタンプが生成されますが、元のデータにはこれらの新しいタイムスタンプに対応する値が存在しません。そのため、新しいタイムスタンプを持つ行の値はデフォルトで欠損値(NaN
)になります。
例:日次データを時間単位にアップサンプリング
ダウンサンプリングした日次データ df_daily_mean
を使って、時間単位にアップサンプリングしてみましょう。
“`python
日次データ df_daily_mean (インデックスは各日の 00:00:00)
print(“元のデータ(日次平均、先頭5行):”)
print(df_daily_mean.head())
時間単位 (‘H’) でアップサンプリング
df_hourly_upsample = df_daily_mean.resample(‘H’)
print(“\n時間単位でアップサンプリング(そのまま):”)
print(df_hourly_upsample.head(10)) # NaNが多く含まれる
“`
結果を見ると、元のデータが存在するタイムスタンプ(各日の00:00:00)以外の多くのタイムスタンプで値がNaN
になっています。
4.1 アップサンプリングにおける集計関数
ダウンサンプリングではmean()
, sum()
などの集計関数を使いましたが、アップサンプリングでこれらの関数を使うことは通常ありません。なぜなら、新しい区間には元のデータが1つしか含まれない(または全く含まれない)ため、集計の意味がないからです。
アップサンプリングで必要になるのは、発生した欠損値をどのように処理するかです。
4.2 欠損値の補間(内挿)
アップサンプリングで発生した欠損値を埋める一般的な方法に「補間(Interpolation)」があります。これは、既知の値に基づいて未知の値を推測する手法です。
resample
オブジェクトに対して、欠損値を埋めるための関数を適用することができます。
4.2.1 ffill()
(Forward Fill)
ffill()
は、欠損値を直前の非欠損値で埋めます。Forward FillやPadとも呼ばれます。
“`python
時間単位でアップサンプリングし、ffillで欠損値を埋める
df_hourly_ffill = df_daily_mean.resample(‘H’).ffill()
print(“\n時間単位でアップサンプリングしffillで補間(先頭10行):”)
print(df_hourly_ffill.head(10))
“`
結果を見ると、各日の00:00:00の値が、次の日の00:00:00まで引き継がれていることがわかります。
4.2.2 bfill()
(Backward Fill)
bfill()
は、欠損値を直後の非欠損値で埋めます。Backward FillやBackfillとも呼ばれます。
“`python
時間単位でアップサンプリングし、bfillで欠損値を埋める
df_hourly_bfill = df_daily_mean.resample(‘H’).bfill()
print(“\n時間単位でアップサンプリングしbfillで補間(先頭10行):”)
print(df_hourly_bfill.head(10))
“`
結果を見ると、各日の00:00:00の前の時刻の欠損値が、その日の00:00:00の値で埋められていることがわかります。
4.2.3 interpolate()
interpolate()
は、既知の値の間を線形(または他の方法)で補間します。時系列データでは、線形補間がよく使われます。
interpolate()
メソッドは、resample
オブジェクトに直接適用するのではなく、resample
後に得られたDataFrame/Seriesに対して適用するのが一般的です。
“`python
時間単位でアップサンプリング(NaNが発生)
df_hourly_upsample_nan = df_daily_mean.resample(‘H’).asfreq() # asfreq()を使うと NaN が明示的に入る
interpolate() で線形補間
df_hourly_interpolate = df_hourly_upsample_nan.interpolate(method=’time’) # 時系列データには method=’time’ が推奨
print(“\n時間単位でアップサンプリングしinterpolateで補間(先頭10行):”)
print(df_hourly_interpolate.head(10))
print(“\n…(途中省略)…”)
print(df_hourly_interpolate.loc[‘2023-01-01 23:55:00′:’2023-01-02 00:05:00’])
“`
interpolate()
を使うと、値が直線的に変化するように欠損値が埋められます。method='time'
を指定すると、タイムスタンプの経過時間を考慮した線形補間が行われます。
4.2.4 定数で埋める (fillna()
)
特定の定数(例えば0)で欠損値を埋めたい場合は、resample
後に結果のDataFrame/Seriesに対してfillna()
メソッドを使います。
“`python
時間単位でアップサンプリング(NaNが発生)
df_hourly_upsample_nan = df_daily_mean.resample(‘H’).asfreq()
fillna(0) で0埋め
df_hourly_fillna_zero = df_hourly_upsample_nan.fillna(0)
print(“\n時間単位でアップサンプリングしfillna(0)で埋める(先頭10行):”)
print(df_hourly_fillna_zero.head(10))
“`
どのような補間方法を選択するかは、データの性質や分析の目的に依存します。データのトレンドを維持したい場合はinterpolate
、直前の状態を引き継ぎたい場合はffill
、ある時点から急変するとみなす場合はbfill
などが考えられます。
5. resample
の詳細な引数
これまでに基本的なrule
、closed
、label
、origin
について説明しました。resample
メソッドには、さらに細かい制御を可能にする引数がいくつかあります。
5.1 rule
(詳細な頻度エイリアス)
既に基本的な頻度エイリアスは紹介しましたが、さらに多くのエイリアスや、複合的な指定方法があります。
- 期間を指定:
'5min'
,'3H'
,'2D'
,'W-TUE'
,'BM'
W-TUE
: 火曜日を週の開始とする週次BM
: 月末(営業日)BMS
: 月初(営業日)- 同様に四半期 (
Q
,BQ
,QS
,BQS
)、年 (Y
,BY
,YS
,BYS
) にも営業日版や開始日版があります。
- 年度の開始月を指定: 会計年度などで年間の集計期間を標準(1月始まり)から変更したい場合に使用します。
'Y-MAR'
: 3月末締めの年度'YS-MAR'
: 3月始まりの年度初め'BA-JUN'
: 6月末営業日締めの年度'BAS-SEP'
: 9月始まり営業日年度初め
例:火曜日始まりの週次集計、3月末締めの年度集計
“`python
火曜日始まりの週次集計 (‘W-TUE’)
サンプルデータは3日分なので、最初の週は火曜日から金曜日までの4日分、
次の週は月曜日までで終わることになる(データ期間による)
df_weekly_tue = df.resample(‘W-TUE’).sum()
print(“\n火曜日始まりの週次集計:”)
print(df_weekly_tue)
2023-01-03 が火曜日なので、最初の区間は 2023-01-03 に終わり、
2023-01-01, 2023-01-02 (土日) は前の週に含まれる (デフォルト closed=’left’, label=’left’)
インデックスは週の開始日 (月曜日) になる W のルール。
2023-01-01 が日曜日なので、デフォルト W では 2023-01-01 が最初のインデックスになり 01/01-01/07 が区間となる
W-TUE では週のインデックスは W-TUE エイリアスの週の開始日 (通常月曜日) になる。
2023-01-01(日) 01/02(月) 01/03(火) …
W-TUE の週の区切りは火曜日だが、ラベルは月曜日になる。
2023-01-02 00:00:00 -> [2023-01-02 00:00:00, 2023-01-03 00:00:00)
2023-01-09 00:00:00 -> [2023-01-03 00:00:00, 2023-01-10 00:00:00)
データは 2023-01-01 から 2023-01-03 までなので
最初の区間 [2022-12-27, 2023-01-03) に 01/01, 01/02 のデータが含まれる
次の区間 [2023-01-03, 2023-01-10) に 01/03 のデータが含まれる
ラベルは週の開始日 (月曜日) になる
2023-01-02 -> 01/01, 01/02 の合計
2023-01-09 -> 01/03 の合計
結果は 2023-01-02 と 2023-01-09 をインデックスとするデータになる
3月末締めの年度集計 (‘Y-MAR’)
サンプルデータは 2023-01-01 からなので、最初の集計期間は
前年度末 (2022-03-31) から 2023-03-31 までとなる。
2023-01-01 から 2023-01-03 のデータはこの期間に含まれる。
df_annual_ymar = df.resample(‘Y-MAR’).sum()
print(“\n3月末締めの年度集計:”)
print(df_annual_ymar)
インデックスは年度の終了日 (2023-03-31) になる (デフォルト label=’right’)
“`
これらのエイリアスを使いこなすことで、ビジネス要件に合った様々な期間での集計が可能です。
5.2 axis
引数
axis
引数は、リサンプリングを行う対象の軸を指定します。デフォルトは0
で、DataFrameのインデックス(行)に対してリサンプリングを行います。これは通常時系列インデックスです。
ほとんどの場合、axis=0
のまま使用します。もし列がDatetimeIndex
を持っていて、列に対してリサンプリングしたいという特殊なケースではaxis=1
を指定します。
5.3 kind
引数
kind
引数は、リサンプリング後のインデックスの型を指定します。
kind='timestamp'
(デフォルト):DatetimeIndex
として結果を返します。kind='period'
:PeriodIndex
として結果を返します。
PeriodIndex
は、特定の期間(例:「2023年1月」「2023年第1四半期」)を表現するのに適しています。
例:結果をPeriodIndexで取得する
“`python
日次 (‘D’) でリサンプリングし、結果をPeriodIndexで取得
df_daily_period = df.resample(‘D’, kind=’period’).sum()
print(“\n日次集計(PeriodIndex):”)
print(df_daily_period)
print(“\nインデックスの型:”)
print(df_daily_period.index)
“`
インデックスがDatetimeIndex
からPeriodIndex
に変わっていることがわかります。PeriodIndex
は期間ベースの分析や、カレンダー期間でのGroupBy操作などと相性が良い場合があります。
5.4 offset
引数
offset
引数は、rule
で定義されたビン(区間)の境界をずらすために使用します。offset
には、pandas.Timedelta
オブジェクトまたはそのエイリアス(例: '5min'
)を指定します。
これはorigin
とは異なり、origin
が集計区間の「開始点」を定めるのに対し、offset
は各ビンの境界線を文字通り時間軸上でスライドさせます。
例:時間単位集計の区間を15分遅らせる
通常、時間単位集計('H'
)の区間は ... [00:00, 01:00), [01:00, 02:00), ...
となります。これを15分遅らせて ... [00:15, 01:15), [01:15, 02:15), ...
としたい場合にoffset='15min'
を使用します。
“`python
時間単位 (‘H’) でリサンプリングし、offset=’15min’ を適用
デフォルトの closed=’left’, label=’left’ で集計
df_hourly_offset = df.resample(‘H’, offset=’15min’).sum()
print(“\n時間単位集計 (offset=’15min’):”)
print(df_hourly_offset.head())
区間の始まりは 00:15, 01:15, … となるが、
label=’left’ なのでインデックスは 00:15, 01:15, … となる
“`
offset
は、特定の時刻ちょうどを区間の区切りとしたいが、origin
の基準点指定では難しい場合などに役立つことがあります。ただし、origin
で大抵のケースは対応可能です。
5.5 on
引数
on
引数は、DataFrameにDatetimeIndex
がない場合に、どの列を時系列データとして使用するかを指定します。その列は適切な日付/時刻型(datetime64[ns]
など)である必要があります。
例:タイムスタンプが列にある場合
“`python
インデックスがデフォルトのInt64Indexで、タイムスタンプが列にあるDataFrameを作成
df_col_ts = pd.DataFrame({
‘timestamp’: pd.date_range(start_date, end_date, freq=’min’),
‘value1’: np.random.rand(len(date_rng)) * 100,
‘value2’: np.sin(np.arange(len(date_rng)) / 100) * 50 + 50
})
print(“タイムスタンプが列にあるデータ(先頭5行):”)
print(df_col_ts.head())
print(“\nインデックスの型:”)
print(df_col_ts.index) # デフォルトのInt64Index
‘timestamp’ 列を基準に日次集計
df_col_ts_daily = df_col_ts.resample(‘D’, on=’timestamp’).sum()
print(“\n’timestamp’ 列を基準に日次集計:”)
print(df_col_ts_daily.head())
print(“\nインデックスの型:”)
print(df_col_ts_daily.index) # 結果はDatetimeIndexになる
“`
on
引数を使うと、インデックスを変更することなく、特定のタイムスタンプ列に基づいてリサンプリングを行うことができます。リサンプリング結果は自動的にDatetimeIndex
を持つDataFrameになります。
5.6 level
引数
level
引数は、対象のDataFrameやSeriesがMultiIndexを持っており、そのどのレベルが時系列インデックスであるかを指定する場合に使用します。
例:MultiIndexでレベル0がDatetimeIndexの場合
“`python
MultiIndexを持つデータを作成 (レベル0: 日付, レベル1: カテゴリ)
dates = pd.date_range(‘2023-01-01′, periods=6, freq=’H’)
categories = [‘A’, ‘B’]
multi_index = pd.MultiIndex.from_product([dates, categories], names=[‘timestamp’, ‘category’])
df_multi = pd.DataFrame(np.random.rand(12, 2), index=multi_index, columns=[‘value1’, ‘value2’])
print(“MultiIndexを持つデータ(先頭5行):”)
print(df_multi.head())
レベル0 (‘timestamp’) を基準に日次集計
df_multi_daily = df_multi.resample(‘D’, level=’timestamp’).sum()
print(“\nレベル0 (‘timestamp’) を基準に日次集計:”)
print(df_multi_daily.head())
“`
level
を指定することで、MultiIndexの一部として含まれる時系列インデックスに対してリサンプリングを行うことができます。
6. 応用例
resample
は非常に多用途です。いくつかの応用例を見てみましょう。
6.1 特定の時間帯のデータ集計
例えば、毎日午前9時から午後5時までのデータのみを抽出し、日次で集計したいとします。resample
に直接時間帯を指定する引数はありませんが、リサンプリングの前にデータをフィルタリングすることで実現できます。
“`python
データのコピーを作成(破壊的な変更を避けるため)
df_copy = df.copy()
毎日 09:00 から 17:00 までのデータのみを抽出
between_time はインデックスに対して動作します
df_daytime = df_copy.between_time(’09:00′, ’17:00′)
print(“09:00から17:00までのデータ(先頭5行):”)
print(df_daytime.head())
print(“\n09:00から17:00までのデータ(末尾5行):”)
print(df_daytime.tail())
抽出したデータを日次で集計
df_daytime_daily_sum = df_daytime.resample(‘D’).sum()
print(“\n毎日09:00から17:00までのデータの日次合計:”)
print(df_daytime_daily_sum)
“`
このように、resample
は他のPandasの時系列機能と組み合わせて使うことで、より複雑なデータ処理を実現できます。
6.2 会計年度やカスタム期間での集計
先ほどrule
の例で少し触れましたが、'Y-MAR'
のようなオフセットエイリアスを使うことで、標準的なカレンダー期間ではない期間で集計できます。
例えば、日本の多くの企業が採用している4月-3月の会計年度で月次集計したい場合。これは標準の月次集計('M'
or 'BM'
)では対応できません。しかし、会計年度ベースで集計したいというのは年次集計のケースが多いでしょう。
年間集計の場合は'Y-MAR'
を使いますが、特定のカスタムな月単位(例:毎月15日締め)で集計したい場合は、resample
単独では難しく、より複雑なカスタム処理(groupby
と組み合わせるなど)が必要になることがあります。
しかし、特定の月の末日締めであれば、'M'
や'BM'
を使えば対応できます。特定の月の特定の日の締め切り(例:毎月25日締め)は、origin
とrule
、label
を組み合わせて実現できる場合があります。
例:毎月25日を区切りとした月次集計 (26日~翌月25日の集計)
“`python
データ期間を広げる(複数月にまたがるように)
start_date_long = ‘2022-12-15 00:00:00’
end_date_long = ‘2023-02-10 23:59:00′
date_rng_long = pd.date_range(start=start_date_long, end=end_date_long, freq=’min’)
df_long = pd.DataFrame(np.random.rand(len(date_rng_long)), index=date_rng_long, columns=[‘value’])
毎月25日を区切りとする月次集計
区間は …[前月26日 00:00:00, 当月26日 00:00:00) … となるようにoriginを設定
例: … [2022-12-26 00:00:00, 2023-01-26 00:00:00), [2023-01-26 00:00:00, 2023-02-26 00:00:00), …
origin は最初の区切りとなる時刻を指定する。例えば 2023-01-26 00:00:00 を指定すると、
それ以前の最初の区切りは 2022-12-26 00:00:00 となる。
label=’right’ にすると、区間の終了時刻 (例: 2023-01-26 00:00:00) がインデックスになる。
closed=’right’ にすると、区間の終了時刻 (例: 2023-01-26 00:00:00) を含むようになる。
origin = 2023-01-26 00:00:00 を基準点とする。
月次(‘MS’)リサンプリングは月初 00:00:00 を区切りとするルール。
origin を指定することで、そのルールが origin を基準に適用される。
月初の区切りを 26日 00:00 にしたいので、 origin = 26日 00:00 とする。
label=’left’ (デフォルト) ならインデックスは区間の開始時刻 (26日 00:00)
label=’right’ ならインデックスは区間の終了時刻 (翌月 26日 00:00)
26日 00:00:00 を区切りとするため、 rule=’MS’, origin=’2023-01-26 00:00:00′ を指定
df_custom_monthly = df_long.resample(‘MS’, origin=pd.Timestamp(‘2023-01-26 00:00:00’)).sum()
print(“\n毎月26日始まりの月次集計 (MS, origin=2023-01-26 00:00:00):”)
print(df_custom_monthly)
インデックスは 2022-12-26, 2023-01-26 となる (label=’left’ のため)
2022-12-26 のインデックスの行は [2022-12-26 00:00:00, 2023-01-26 00:00:00) の合計
2023-01-26 のインデックスの行は [2023-01-26 00:00:00, 2023-02-26 00:00:00) の合計
データ期間は 2022-12-15 から 2023-02-10 なので
最初の区間 [2022-12-26, 2023-01-26) にはデータなし (12/15-12/25 のデータは前の区間に含まれるが、データ開始が遅いため最初の区間が短いか無い)
データ開始が 2022-12-15 なので、origin=2023-01-26 00:00:00 とすると、
最初のリサンプリングビンは 2023-01-26 00:00:00 から rule=’MS’ を逆算して求められる。
2023-01-26 – 1ヶ月 = 2022-12-26
2022-12-26 – 1ヶ月 = 2022-11-26
… となる。
データ期間は 2022-12-15 から 2023-02-10 なので、関連するビンは:
[2022-11-26 00:00:00, 2022-12-26 00:00:00) -> データ期間外 (2022-12-15以降)
[2022-12-26 00:00:00, 2023-01-26 00:00:00) -> データ期間 2022-12-26 から 2023-01-10 までのデータが含まれる
[2023-01-26 00:00:00, 2023-02-26 00:00:00) -> データ期間 2023-01-26 から 2023-02-10 までのデータが含まれる
ラベルは 2022-12-26 と 2023-01-26 となる (label=’left’ のため)
2022-12-26 インデックスの行に 2022-12-26 から 2023-01-10 のデータ合計
2023-01-26 インデックスの行に 2023-01-26 から 2023-02-10 のデータ合計
もし毎月25日を含んで締めたいなら closed=’right’, label=’right’
df_custom_monthly_closed_right = df_long.resample(‘MS’, origin=pd.Timestamp(‘2023-01-26 00:00:00′), closed=’right’, label=’right’).sum()
print(“\n毎月26日始まりの月次集計 (MS, origin=2023-01-26 00:00:00, closed=’right’, label=’right’):”)
print(df_custom_monthly_closed_right)
インデックスは 2023-01-26, 2023-02-26 となる (label=’right’ のため)
2023-01-26 のインデックスの行は (2022-12-26 00:00:00, 2023-01-26 00:00:00] の合計
2023-02-26 のインデックスの行は (2023-01-26 00:00:00, 2023-02-26 00:00:00] の合計
データ期間 2022-12-15 から 2023-02-10 を考慮すると:
2023-01-26 インデックスの行は 2022-12-15 から 2023-01-10 までのデータ合計 (最初のビンがデータ開始で打ち切られる)
2023-02-26 インデックスの行は 2023-01-26 から 2023-02-10 までのデータ合計
``
origin
このように、引数と
rule、
label、
closed`の組み合わせを理解することで、標準的なカレンダー期間ではない、任意の日付・時刻を区切りとした集計が可能になります。ただし、その挙動は直感的でない場合もあるため、結果を確認しながら進めることが重要です。
7. resample
vs asfreq
vs reindex
Pandasには、時系列データの頻度を変更したり、インデックスを操作したりするメソッドがいくつかあります。resample
の他にasfreq
やreindex
も頻繁に使用されますが、それぞれ機能と目的が異なります。この違いを理解することが、適切なメソッドを選択するために重要です。
7.1 resample
- 目的: 時間的な粒度を変更し、集計(ダウンサンプリング)または欠損値処理(アップサンプリング)を行う。
- 挙動: 指定した
rule
で時間区間(ビン)を作成し、そのビン内のデータに対して集計関数を適用するか、新しいタイムスタンプに対して補間を行う。ダウンサンプリングではデータの行数が減り、アップサンプリングでは増える。 - 集計/変換: 必ず集計関数(
sum
,mean
など)や補間関数(ffill
,bfill
など)をメソッドチェーンの最後につなげる必要がある。 - 主な用途: データの集約、欠損値の補間。
7.2 asfreq
- 目的: 時系列データの頻度を変更する。
- 挙動: 指定した
freq
(頻度エイリアス)で新しいインデックスを作成し、その新しいインデックスの各タイムスタンプに対して、元のデータに存在する最も近いタイムスタンプの値を対応付ける(デフォルト)。新しいタイムスタンプに対応する元のデータがない場合は、デフォルトでは欠損値(NaN
)になる。集計は行わない。元のデータ点の値がそのまま新しい頻度のインデックスにコピーされるイメージ。 - 集計/変換: 行わない。値はコピーされるか
NaN
になる。欠損値の埋め方はmethod
引数('ffill'
,'bfill'
)やfill_value
引数で制御できるが、これはresample
の補間とは異なり、欠損値が発生した後の処理ではなく、新しい頻度に変換する際に値をどのように探すか/埋めるかを指定する。 - 主な用途: データに欠損しているタイムスタンプを挿入する(アップサンプリング的な使い方)、または既存のタイムスタンプから特定の頻度だけを抽出する(ダウンサンプリング的な使い方だが集計ではない)。
例:asfreq
の使用
“`python
元の分単位データ df を日次の 00:00:00 だけに絞る (ダウンサンプリング的な使い方だが集計なし)
df_asfreq_daily = df.asfreq(‘D’)
print(“\nasfreq(‘D’) で日次の 00:00:00 だけを抽出:”)
print(df_asfreq_daily.head()) # 各日の 00:00:00 の値が表示される
日次データ df_daily_mean を時間単位にアップサンプリングし、欠損値を前方向補間する
これは resample(‘H’).ffill() と同じ結果にはならない!
asfreq は新しいインデックスに対して元のインデックスの値を対応付ける
この場合、元のデータは日次(00:00:00)なので、新しい時間単位インデックス (00:00:00, 01:00:00, …) に対して
元のデータが存在するのは 00:00:00 のタイムスタンプだけ。
asfreq().ffill() は asfreq() で発生した NaN を fillna(‘ffill’) するのと同じ。
df_asfreq_hourly_ffill = df_daily_mean.asfreq(‘H’, method=’ffill’)
print(“\ndf_daily_mean.asfreq(‘H’, method=’ffill’) で時間単位に変換:”)
print(df_asfreq_hourly_ffill.head(10))
resample(‘H’).ffill() と同じ結果になる (ここでは)。
asfreq の method は NaN を埋めるだけでなく、元のデータポイントをどのように探すかのヒントにもなるが、
時系列インデックスの場合は単純な ffill/bfill になることが多い。
fillna(‘ffill’) との唯一の違いは、asfreq の method は変換と同時に補間を行う点。
一方 resample(‘H’).ffill() はリサンプリングという区間集計処理を行った結果に補間を適用する。
アップサンプリングで値の補間をしたい場合は、resample(‘freq’).() の形式がより一般的で推奨される。
“`
7.3 reindex
- 目的: DataFrameやSeriesを、全く新しいインデックスに合わせる。
- 挙動: 指定した
index
引数の値を持つ新しいインデックスを作成し、元のインデックスにその値が存在すれば対応する値をコピー、存在しなければ欠損値(NaN
)にする。時系列に限らず、任意のインデックスに対して使用可能。 - 集計/変換: 行わない。値はコピーされるか
NaN
になる。method
引数('ffill'
,'bfill'
,'nearest'
)やfill_value
引数で欠損値の埋め方を制御できる。 - 主な用途: データフレームのインデックスを揃える、任意のタイミングで欠損値を埋めながら新しいインデックスを作成する。
asfreq
はreindex
の特殊なケース(新しいインデックスが規則的な時系列インデックスの場合)と考えることもできる。
例:reindex
の使用
“`python
元の分単位データ df を、特定の不規則なタイムスタンプリストに合わせる
new_index = pd.to_datetime([‘2023-01-01 00:05:00’, ‘2023-01-01 00:15:30’, ‘2023-01-01 00:30:00’, ‘2023-01-02 12:00:00’])
df_reindexed = df.reindex(new_index)
print(“\n不規則なインデックスで reindex:”)
print(df_reindexed)
2023-01-01 00:05:00 と 2023-01-01 00:30:00 は元のインデックスに存在するので値が入る
2023-01-01 00:15:30 は元のインデックスに存在しないので NaN になる
2023-01-02 12:00:00 は元のインデックスに存在しないので NaN になる
reindex と同時に欠損値を前方向補間
df_reindexed_ffill = df.reindex(new_index, method=’ffill’)
print(“\nreindex と同時に ffill で補間:”)
print(df_reindexed_ffill)
2023-01-01 00:15:30 の NaN は直前 (00:05:00) の値で埋められる
2023-01-02 12:00:00 の NaN は直前 (00:30:00) の値で埋められる
“`
まとめると:
* 集計したい または アップサンプリングで複数の元の値を元に補間したい → resample
* 特定の頻度で値を抽出したい または アップサンプリングで単純な前/後方向補間をしたい → asfreq
* 任意のインデックスに合わせたい → reindex
アップサンプリング時の補間に関しては、resample().<interpolation_method>()
の方が、より柔軟な補間方法(線形補間など)を利用できる点で強力です。
8. トラブルシューティングと注意点
resample
を使用する際に遭遇しやすい問題や注意点をいくつか挙げます。
8.1 インデックスがDatetimeIndexでない
最も基本的なエラーの原因です。resample
は時系列インデックス(DatetimeIndex
またはPeriodIndex
)に対して呼び出す必要があります。DataFrameやSeriesのインデックスがそうでない場合は、エラーが発生します。
もし時系列データが列に含まれている場合は、on
引数を使用するか、先にその列をインデックスに設定する必要があります。
“`python
例: インデックスが数値の場合
df_no_ts_idx = pd.DataFrame({‘timestamp’: pd.to_datetime([‘2023-01-01’, ‘2023-01-02’]), ‘value’: [10, 20]})
df_no_ts_idx.resample(‘D’).sum() # -> エラー発生
on 引数を使用するか
df_no_ts_idx.resample(‘D’, on=’timestamp’).sum()
またはインデックスに設定してから
df_with_ts_idx = df_no_ts_idx.set_index(‘timestamp’)
df_with_ts_idx.resample(‘D’).sum()
“`
8.2 タイムゾーンに関する問題
タイムゾーン情報を持つDatetimeIndex
を扱う場合、resample
はタイムゾーンを保持します。異なるタイムゾーンのデータを混ぜてresample
しようとすると問題が発生する可能性があります。必要に応じてtz_convert()
やtz_localize()
でタイムゾーンを統一してからresample
するのが安全です。
“`python
UTCタイムゾーンを持つデータ
df_utc = df.tz_localize(‘UTC’)
print(“\nUTCタイムゾーンのデータ:”)
print(df_utc.head())
集計結果もUTCタイムゾーンを持つ
df_utc_daily = df_utc.resample(‘D’).sum()
print(“\nUTCタイムゾーンの日次集計:”)
print(df_utc_daily.head())
東京時間に変換してから集計
df_tokyo_daily = df_utc.tz_convert(‘Asia/Tokyo’).resample(‘D’).sum()
print(“\n東京時間に変換して日次集計:”)
print(df_tokyo_daily.head())
“`
タイムゾーン変換を行うと、タイムスタンプがずれるため、集計結果も変わる可能性があります。特に日を跨ぐような集計では注意が必要です。
8.3 欠損値の取り扱い(アップサンプリング後)
アップサンプリングで発生したNaN
をどのように処理するかは、分析の目的に応じて慎重に選択する必要があります。単純なffill
やbfill
は、データのトレンドを無視してしまう可能性があります。interpolate
は線形変化を仮定しますが、非線形なトレンドを持つデータには適さないかもしれません。欠損値の補間はデータの性質を歪める可能性があるため、その影響を理解した上で行うことが重要です。
8.4 集計期間にデータが全く存在しない場合
resample
で指定した集計期間(ビン)に、元のデータが1つも含まれない場合があります。ダウンサンプリングの場合、このようなビンに対する集計結果は、数値型の列であれば通常NaN
(例えばsum()
なら0になることもある)、オブジェクト型などの列であれば空のリストやNaN
になります。count()
は0になります。
“`python
サンプルデータ df は 2023-01-01 から 2023-01-03
2023-01-04 で日次集計を試みる
date_rng_gap = pd.date_range(‘2023-01-01’, ‘2023-01-05′, freq=’D’)
df_with_gap_resample = df.resample(‘D’).sum().reindex(date_rng_gap)
print(“\nデータがない期間を含む日次集計 (reindexで期間を拡張):”)
print(df_with_gap_resample)
2023-01-04 の行は NaN になる
``
resample
この例はの結果を
reindexで拡張していますが、元のデータに大きなギャップがある場合も同様に、そのギャップに対応するリサンプリング区間はデータを含まないため
NaN`になります。
8.5 大規模データとパフォーマンス
非常に大規模な時系列データに対してresample
を行う場合、メモリ使用量や処理時間に注意が必要です。特に高頻度データ(秒単位やミリ秒単位)を長期間にわたって扱う場合、ダウンサンプリングでも元のデータ量が膨大であれば処理に時間がかかります。アップサンプリングの場合は、新しいタイムスタンプの数が元のデータ点よりはるかに多くなるため、結果のDataFrameが非常に大きくなり、メモリ不足を引き起こす可能性があります。
大規模データでは、以下の点を考慮すると良いでしょう。
* データ型の最適化: 時刻データ型や数値データ型が効率的にメモリを使用するように確認する。
* チャンク処理: データを期間ごとに分割して処理する。
* Daskなどの並列/分散処理ライブラリの活用: Pandasに似たAPIで大規模データを扱えるライブラリを検討する。
* 必要な列だけを処理: リサンプリング対象の列を絞る。
8.6 古いPandasバージョンとの互換性
resample
メソッドは進化しており、特にorigin
引数は比較的新しいバージョン(v1.1以降)で導入され、古いloffset
引数を置き換えました。また、タイムゾーンやPeriodIndexの扱いもバージョンによって微妙な違いがある場合があります。古いバージョンのPandasを使用している場合は、ドキュメントを確認するか、最新版へのアップデートを検討してください。
9. まとめ
この記事では、Pandasの強力な時系列データ処理メソッドであるresample
について、その概念、基本的な使い方、詳細な引数、ダウンサンプリングとアップサンプリング、応用例、そして類似メソッドとの違いを徹底的に解説しました。
resample
は、rule
引数で新しい時間的な粒度を指定し、ダウンサンプリングの場合は集計関数(sum
, mean
, ohlc
など)を、アップサンプリングの場合は補間関数(ffill
, bfill
)やinterpolate
などを組み合わせて使用することで、時系列データを自在に集計・変換できるメソッドです。
特にclosed
, label
, origin
といった引数を使いこなすことで、集計区間の境界やラベルのタイムスタンプを柔軟に制御できます。これは、ビジネス上の特定の期間(会計年度、営業日など)での集計を行う際に非常に強力です。
また、resample
とasfreq
、reindex
の違いを理解することは、目的に応じた適切なメソッドを選択するために不可欠です。集計を伴う粒度変更はresample
、頻度変更や単純な補間はasfreq
、任意のインデックスへの再構築はreindex
と使い分けるのが一般的です。
時系列データ分析において、resample
はデータの周期性やトレンドを把握するための第一歩となることが多く、また異なるデータソースを時間的に整合させるためにも不可欠なツールです。この記事で学んだ知識を活用し、あなたの時系列データ分析スキルをさらに向上させてください。
Pandasの公式ドキュメントも非常に充実していますので、さらに詳細な情報や最新の機能についてはそちらも参照することをおすすめします。
Happy Data Analyzing!