Pandasによる日付と時間の操作テクニック
Pandasは、Pythonにおけるデータ分析ライブラリであり、特に時系列データを扱う上で強力な機能を提供します。日付と時間の操作は、データ分析において不可欠な要素であり、Pandasはそのための豊富なツールキットを備えています。ここでは、Pandasで日付と時間を操作するための主要なテクニックを、より深く掘り下げて解説します。
日付と時間データの型
Pandasでは、日付と時間を扱うための主要なデータ型として `datetime64[ns]` があります。このデータ型は、マイクロ秒(ナノ秒)単位の精度で日付と時間を格納できます。
datetime64[ns]の作成
* **文字列からの変換**:
最も一般的な方法は、日付や時間の文字列を `pd.to_datetime()` 関数を用いて変換することです。
“`python
import pandas as pd
date_str = ‘2023-10-27 10:30:00′
dt_object = pd.to_datetime(date_str)
print(dt_object)
print(type(dt_object))
“`
この関数は、様々なフォーマットの文字列を自動的に解釈しようとしますが、必要に応じて `format` 引数で明示的にフォーマットを指定することも可能です。
“`python
date_str_custom = ’27/10/2023 10:30 AM’
dt_object_custom = pd.to_datetime(date_str_custom, format=’%d/%m/%Y %I:%M %p’)
print(dt_object_custom)
“`
* **年、月、日などの配列からの作成**:
年、月、日などの要素を個別の配列として持ち、それらから日付オブジェクトを作成することもできます。
“`python
year = [2023, 2024]
month = [10, 1]
day = [27, 15]
dt_array = pd.to_datetime({‘year’: year, ‘month’: month, ‘day’: day})
print(dt_array)
“`
* **Unixタイムスタンプからの変換**:
Unixタイムスタンプ(エポックからの経過秒数)も `pd.to_datetime()` で変換できます。
“`python
timestamp = 1698375000 # 2023-10-27 10:30:00 UTC
dt_from_ts = pd.to_datetime(timestamp, unit=’s’)
print(dt_from_ts)
“`
`unit` 引数で秒 (`’s’`)、ミリ秒 (`’ms’`)、マイクロ秒 (`’us’`) などを指定できます。
datetime64[ns]の属性へのアクセス
`datetime64[ns]` 型のSeriesやIndexオブジェクトは、`.dt` アクセサを通じて、年、月、日、曜日などの様々な属性に簡単にアクセスできます。
“`python
s = pd.Series(pd.to_datetime([‘2023-10-27 10:30:00’, ‘2023-10-28 11:00:00’]))
print(s.dt.year) # 年
print(s.dt.month) # 月
print(s.dt.day) # 日
print(s.dt.hour) # 時
print(s.dt.minute) # 分
print(s.dt.second) # 秒
print(s.dt.dayofweek) # 曜日 (月曜日が0、日曜日が6)
print(s.dt.day_name())# 曜日の名前
print(s.dt.quarter) # 四半期
print(s.dt.isocalendar().week) # ISO週番号
“`
時間間隔 (Timedelta)
日付や時間の差分は、`timedelta64[ns]` 型として表現されます。これは、時間の長さを表すために使用されます。
timedeltaの作成
* **日付同士の差**:
“`python
date1 = pd.to_datetime(‘2023-10-27’)
date2 = pd.to_datetime(‘2023-10-30’)
time_diff = date2 – date1
print(time_diff)
print(type(time_diff))
“`
* **文字列からの変換**:
`pd.to_timedelta()` 関数を使用して、時間の長さを表す文字列からtimedeltaオブジェクトを作成できます。
“`python
delta_str = ‘2 days 5 hours 30 minutes’
delta_object = pd.to_timedelta(delta_str)
print(delta_object)
“`
この関数も、様々なフォーマットを解釈します。
* **数値からの変換**:
数値を指定し、単位を指定してtimedeltaを作成します。
“`python
delta_numeric = pd.to_timedelta(5, unit=’D’) # 5日
print(delta_numeric)
delta_numeric_h = pd.to_timedelta(60, unit=’H’) # 60時間
print(delta_numeric_h)
“`
timedeltaの操作
timedeltaオブジェクトは、加算、減算、比較などの演算が可能です。また、その総時間を日、秒などで取得できます。
“`python
s_dt = pd.Series(pd.to_datetime([‘2023-10-27’, ‘2023-10-30’]))
s_td = pd.Series(pd.to_timedelta([‘1 day’, ‘2 days 12 hours’]))
print(s_dt + s_td) # 日付にtimedeltaを加算
print(s_dt – s_dt.shift(1)) # 隣接する日付との差
print(s_td.dt.days) # timedeltaの「日」の部分
print(s_td.dt.total_seconds()) # timedeltaの総秒数
“`
時系列インデックス
Pandasの強力な機能の一つは、時系列データを効率的に扱うための `DatetimeIndex` です。これは、DataFrameやSeriesのインデックスとして使用されることで、時間に基づいたスライシングやリサンプリングを容易にします。
DatetimeIndexの作成
* **日付範囲の生成**:
`pd.date_range()` 関数は、指定された開始日、終了日、または期間と頻度に基づいて、一連の日付を生成するのに非常に便利です。
“`python
date_idx = pd.date_range(start=’2023-10-01′, end=’2023-10-10′, freq=’D’) # 日単位
print(date_idx)
date_idx_freq = pd.date_range(start=’2023-10-01′, periods=5, freq=’H’) # 5期間、時間単位
print(date_idx_freq)
“`
`freq` 引数には、’D’ (日), ‘H’ (時), ‘T’ or ‘min’ (分), ‘S’ (秒), ‘B’ (営業日), ‘W’ (週), ‘M’ (月終端), ‘MS’ (月始端), ‘Q’ (四半期終端), ‘QS’ (四半期始端), ‘A’ (年終端), ‘AS’ (年始端) など、様々なエイリアスが用意されています。
DatetimeIndexを使ったデータ操作
DataFrameやSeriesのインデックスにDatetimeIndexを設定すると、以下のような操作が簡単に行えます。
* **時間に基づくスライシング**:
日付や時間文字列を使って、データの一部を抽出できます。
“`python
ts = pd.Series(range(10), index=pd.date_range(‘2023-10-01’, periods=10))
print(ts[‘2023-10-03’]) # 特定の日付
print(ts[‘2023-10-02′:’2023-10-05’]) # 日付範囲
print(ts[‘2023-10’]) # 月単位で抽出
print(ts[‘2023’]) # 年単位で抽出
“`
* **部分文字列インデックス**:
年、月、日などの部分文字列でインデックスを指定することも可能です。
“`python
print(ts[ts.index.year == 2023])
print(ts[ts.index.month == 10])
print(ts[ts.index.dayofweek == 4]) # 金曜日 (0=月曜)
“`
リサンプリング (Resampling)
リサンプリングは、時系列データの頻度を変更する操作です。例えば、日次のデータを月次のデータに集約したり、時間ごとのデータを15分ごとのデータに細分化したりする場合に使用します。
ダウンサンプリング (Downsampling)
より低い頻度に集約する操作です。集約には、`mean()`, `sum()`, `count()`, `max()`, `min()` などの集約関数を使用します。
“`python
# 日次のデータを月次の平均値にリサンプリング
monthly_mean = ts.resample(‘M’).mean()
print(monthly_mean)
# 日次のデータを週次の合計値にリサンプリング
weekly_sum = ts.resample(‘W’).sum()
print(weekly_sum)
“`
アップサンプリング (Upsampling)
より高い頻度に細分化する操作です。アップサンプリング後、欠損値を補間する必要がある場合が多いです。補間には `ffill()` (前方補間) や `bfill()` (後方補間)、`interpolate()` などが使われます。
“`python
# 時間ごとのデータを15分ごとのデータにアップサンプリングし、前方補間
upsampled = ts.resample(’15min’).ffill()
print(upsampled.head())
“`
リサンプリングの応用
* **ロールバック (Rolling Window)**:
指定した期間の移動平均などを計算する際に使われます。
“`python
rolling_mean = ts.rolling(window=3).mean() # 3期間の移動平均
print(rolling_mean)
“`
* **指数移動平均 (Exponential Moving Average – EMA)**:
直近のデータに重きを置いた移動平均です。
“`python
ema = ts.ewm(span=3).mean() # spanは等価な移動平均の期間
print(ema)
“`
タイムゾーンの扱い
Pandasはタイムゾーンを意識した日付/時間操作もサポートしています。
タイムゾーンの付与 (Localization)
タイムゾーン情報を持たない datetime オブジェクトにタイムゾーンを付与します。
“`python
s_naive = pd.Series(pd.to_datetime([‘2023-10-27 10:30:00’, ‘2023-10-28 11:00:00’]))
s_localized = s_naive.dt.tz_localize(‘UTC’) # UTCタイムゾーンを付与
print(s_localized)
“`
利用可能なタイムゾーンは `pytz` ライブラリなどによって提供されます。
タイムゾーンの変換 (Conversion)
付与されたタイムゾーンを持つ datetime オブジェクトを別のタイムゾーンに変換します。
“`python
s_tokyo = s_localized.dt.tz_convert(‘Asia/Tokyo’) # 東京時間に変換
print(s_tokyo)
“`
タイムゾーンフリー (Natively timezone-naive)
タイムゾーン情報を持たない状態は「naive」、持つ状態は「aware」と呼ばれます。タイムゾーンの変換を行うには、まず naive なオブジェクトに `tz_localize` でタイムゾーンを付与し、aware なオブジェクトにした後で `tz_convert` を使います。
日付と時間のフォーマット変換
日付/時間オブジェクトを文字列に変換したり、その逆を行ったりする際に、フォーマットを指定することが重要です。
datetime オブジェクトから文字列へ
`strftime()` メソッドを使用します。
“`python
dt_obj = pd.to_datetime(‘2023-10-27 10:30:00’)
formatted_str = dt_obj.strftime(‘%Y/%m/%d %H:%M’)
print(formatted_str)
“`
文字列から datetime オブジェクトへ
前述の `pd.to_datetime()` 関数で `format` 引数を使用します。
“`python
str_to_convert = ’27-10-2023′
dt_from_str = pd.to_datetime(str_to_convert, format=’%d-%m-%Y’)
print(dt_from_str)
“`
日付/時間関連の特殊な日付
Pandasには、年末年始、祝日、営業日などの特殊な日付を扱うための機能も含まれています。
営業日 (Business Days)**:**
`pd.offsets.BDay()` を使用して、営業日のみを考慮した日付計算が可能です。
“`python
today = pd.to_datetime(‘2023-10-27’) # 金曜日
next_business_day = today + pd.offsets.BDay(1)
print(next_business_day) # 次の営業日(月曜日)
next_3_business_days = today + pd.offsets.BDay(3)
print(next_3_business_days)
“`
`pd.bdate_range()` を使用して、営業日の日付範囲を生成することもできます。
祝日 (Holidays)**:**
外部ライブラリ (例: `holidays`) と連携することで、特定の国の祝日を考慮した日付計算も実現できます。Pandas自体は、直接的な祝日リストの管理機能は提供していませんが、`BusinessDay` オフセットにカスタム祝日リストを渡すことで対応できます。
### まとめ
Pandasは、日付と時間の操作において非常に柔軟で強力な機能を提供します。`datetime64[ns]` 型、`timedelta64[ns]` 型、`DatetimeIndex` を中心に、データの読み込み、変換、スライシング、リサンプリング、タイムゾーン処理まで、多岐にわたるテクニックを駆使することで、効果的な時系列データ分析が可能となります。これらの機能を理解し、適切に活用することが、データサイエンスの分野で成功するための鍵となります。
