【日付と時間】Pandasの日付時刻処理:Timestamp・to_datetime・dtアクセサ
時系列分析の第一歩は、文字列の日付をPandasの日付時刻型に変換することです。DatetimeIndexを使えば週・月・四半期ごとの集計が可能になり、dtアクセサは文字列の分割と同じように日付を分解でき、Timedeltaは日付の計算をシンプルにしてくれます。本セクションでは、日付時刻の型システム、パース、抽出、計算について解説します。
⚠️ 注意: 以下のコードはローカルのPython環境で実行してください。
1. 学習内容
- ❶ Timestamp / DatetimeIndex
- ❷ pd.to_datetime によるパース
- ❸ .dt アクセサ
- ❹ Timedelta による日付計算
- ❺ date_range と頻度
2. チャーリーの観測所が直面する日付のジレンマ
(1) 課題:日付が文字列のため月次集計ができない
チャーリーの観測所データは日付を文字列として保存しているため、月次の統計を取ることができません:
PYTHON
import pandas as pd
df = pd.DataFrame({
'date_str': ['2024-01-15', '2024-01-20', '2024-02-10', '2024-02-28', '2024-03-15'],
'temperature': [5.2, 3.8, 8.1, 9.5, 12.3]
})
# df.groupby(df['date_str'].str[:7]) — 脆弱なハック!
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
(2) 解決策:to_datetime + dt
▶ サンプル:to_datetime によるパースと抽出
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
:to_datetime によるパースと抽出(難易度 ⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'date_str': ['2024-01-15', '2024-01-20', '2024-02-10', '2024-02-28', '2024-03-15'],
'temperature': [5.2, 3.8, 8.1, 9.5, 12.3]
})
# 文字列をdatetimeに変換
df['date'] = pd.to_datetime(df['date_str'])
# グループ化のために月を抽出
df['month'] = df['date'].dt.month
# 月ごとにグループ化
monthly = df.groupby('month')['temperature'].mean()
print(monthly)
# month
# 1 4.50
# 2 8.80
# 3 12.30
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
3. Pandasの日付時刻の型システム
(1) 4つの日付時刻型
| 型 | 用途 | 例 |
|---|---|---|
| Timestamp | 単一の時点 | pd.Timestamp('2024-01-15') |
| DatetimeIndex | タイムスタンプの連なり | pd.date_range('2024-01', periods=3, freq='M') |
| Timedelta | 2時点間の時間間隔 | pd.Timedelta(days=7) |
| Period | 期間(時間幅) | pd.Period('2024-01', freq='M') |
▶ サンプル:日付時刻型の作成
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
:日付時刻型の作成(難易度 ⭐)
PYTHON
import pandas as pd
# Timestamp — 単一の時点
ts = pd.Timestamp('2024-01-15 10:30:00')
print(ts.year, ts.month, ts.day, ts.hour)
# 2024 1 15 10
# DatetimeIndex — タイムスタンプの連なり
idx = pd.date_range('2024-01-01', periods=5, freq='D')
print(idx)
# DatetimeIndex(['2024-01-01', '2024-01-02', ...], dtype='datetime64[ns]')
# Timedelta — 時間間隔
delta = pd.Timedelta(days=7, hours=3)
print(delta) # 7 days 03:00:00
print(ts + delta) # 2024-01-22 13:30:00
# Period — 期間(月/四半期/年)
p = pd.Period('2024-Q1', freq='Q')
print(p.start_time, p.end_time)
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
4. pd.to_datetime
(1) 複数形式のパース
▶ サンプル:to_datetime による複数形式のパース
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
:to_datetime による複数形式のパース(難易度 ⭐⭐)
PYTHON
import pandas as pd
# ISO形式(自動検出)
dates1 = pd.to_datetime(['2024-01-15', '2024-02-20', '2024-03-10'])
print(dates1)
# 混在形式
dates2 = pd.to_datetime(['01/15/2024', 'Feb 20, 2024', '20240310'])
print(dates2)
# 形式を明示的に指定(大規模データでは高速)
dates3 = pd.to_datetime(['15-01-2024', '20-02-2024'], format='%d-%m-%Y')
print(dates3)
# エラーの処理
bad_dates = pd.to_datetime(
['2024-01-15', 'not-a-date', '2024-03-10'],
errors='coerce' # 無効値 → NaT(errors='raise' ではない)
)
print(bad_dates)
# DatetimeIndex(['2024-01-15', 'NaT', '2024-03-10'])
# Unixタイムスタンプ
unix_ts = pd.to_datetime([1705276800, 1707974400], unit='s')
print(unix_ts)
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
(2) よく使う format コード
| コード | 意味 | 例 |
|---|---|---|
| %Y | 4桁の年 | 2024 |
| %m | 2桁の月 | 01 |
| %d | 2桁の日 | 15 |
| %H | 24時間表記の時 | 14 |
| %M | 分 | 30 |
| %S | 秒 | 00 |
| %b | 月の省略名 | Jan |
| %B | 月の正式名 | January |
| %a | 曜日の省略名 | Mon |
5. .dt アクセサ
(1) 日付時刻プロパティの抽出
▶ サンプル:dt アクセサのプロパティ
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
:dt アクセサのプロパティ(難易度 ⭐⭐)
PYTHON
import pandas as pd
df = pd.DataFrame({
'timestamp': pd.date_range('2024-01-15 08:30:00', periods=5, freq='12h')
})
# 日付の構成要素を抽出
df['year'] = df['timestamp'].dt.year
df['month'] = df['timestamp'].dt.month
df['day'] = df['timestamp'].dt.day
df['hour'] = df['timestamp'].dt.hour
df['day_of_week'] = df['timestamp'].dt.dayofweek # 0=月曜、6=日曜
df['day_name'] = df['timestamp'].dt.day_name() # Monday、Tuesday...
df['is_weekend'] = df['timestamp'].dt.dayofweek >= 5
df['quarter'] = df['timestamp'].dt.quarter
print(df[['timestamp', 'month', 'day_name', 'is_weekend', 'quarter']])
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
(2) dt のメソッド
▶ サンプル:dt メソッドによる操作
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
:dt メソッドによる操作(難易度 ⭐)
PYTHON
import pandas as pd
dates = pd.Series(pd.date_range('2024-01-15', periods=5, freq='2D'))
# Period(期間)に変換
print(dates.dt.to_period('M')) # 月次の期間
# 深夜0時に正規化(時刻の構成要素を除去)
print(dates.dt.normalize())
# 最も近い時間に丸める
timestamps = pd.Series(pd.date_range('2024-01-15 08:35:00', periods=3, freq='45min'))
print(timestamps.dt.round('h')) # 最も近い時間に丸める
# Floor(切り捨て)/Ceil(切り上げ)
print(timestamps.dt.floor('h')) # 切り捨て
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
6. Timedelta による日付計算
(1) 日付の加算と減算
▶ サンプル:Timedelta による日付計算
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
:Timedelta による日付計算(難易度 ⭐⭐)
PYTHON
import pandas as pd
# タイムスタンプを作成
start = pd.Timestamp('2024-01-15')
deadline = start + pd.Timedelta(days=30)
print(f"締切:{deadline}")
# 日付同士の差分
delivery = pd.Timestamp('2024-02-10')
delay = delivery - deadline
print(f"遅延:{delay.days} 日") # -4 日(早い)
# 文字列からTimedeltaを作成
td = pd.to_timedelta('5 days 3 hours')
print(td)
# Seriesに対する操作
df = pd.DataFrame({
'order_date': pd.date_range('2024-01-01', periods=5),
'delivery_days': [3, 5, 2, 7, 4]
})
df['delivery_date'] = df['order_date'] + pd.to_timedelta(df['delivery_days'], unit='D')
df['is_late'] = df['delivery_days'] > 5
print(df)
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
7. date_range と頻度
(1) 日付シーケンスの生成
▶ サンプル:date_range による日付生成
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
:date_range による日付生成(難易度 ⭐⭐)
PYTHON
import pandas as pd
# 固定の期間数
print(pd.date_range('2024-01-01', periods=5, freq='D'))
# 2024-01-01 から 2024-01-05 まで
# 開始日 + 終了日
print(pd.date_range('2024-01-01', '2024-01-10', freq='2D'))
# 2024-01-01、2024-01-03、2024-01-05、2024-01-07、2024-01-09
# 営業日のみ
bdays = pd.bdate_range('2024-01-01', periods=5) # 週末をスキップ
print(bdays)
# 月次の頻度
months = pd.date_range('2024-01', periods=4, freq='MS') # 月初(Month Start)
print(months)
# 時間ごと
hours = pd.date_range('2024-01-15 09:00', periods=4, freq='h')
print(hours)
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
(2) 頻度エイリアス早見表
| エイリアス | 意味 | 例 |
|---|---|---|
| D | 暦日 | 毎日 |
| B | 営業日 | 週末をスキップ |
| W | 週次 | 毎週日曜 |
| MS | 月初 | 各月の1日 |
| M | 月末 | 各月の最終日 |
| QS | 四半期初 | 各四半期の初日 |
| Q | 四半期末 | 各四半期の最終日 |
| H | 時間ごと | 毎時 |
| T/min | 分ごと | 毎分 |
8. 総合例:コーヒーショップの時系列分析
(5) ▶ 日付時刻の型システム
graph LR
A[Pandasの日付時刻型] --> B[Timestamp 時点]
A --> C[DatetimeIndex 時系列]
A --> D[Timedelta 時間間隔]
A --> E[Period 期間]
B --> F[単一の瞬間]
C --> G[頻度ごとの集計]
D --> H[日付の計算]
E --> I[月次/四半期の集計]
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
▶ サンプル:時系列分析の全体ワークフロー
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
:時系列分析の全体ワークフロー(難易度 ⭐⭐⭐)
PYTHON
import pandas as pd
import numpy as np
# ============================================
# 総合例:コーヒーショップの日付時刻操作を
# 用いた時系列分析
# ============================================
# 1. 90日分の日次売上データを作成
np.random.seed(42)
df = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=90, freq='D'),
'sales': np.random.poisson(50, 90) * 10,
'customers': np.random.poisson(30, 90)
})
df = df.set_index('date')
# 2. 時間の特徴量を抽出
df['month'] = df.index.month
df['day_of_week'] = df.index.dayofweek
df['day_name'] = df.index.day_name()
df['is_weekend'] = df.index.dayofweek >= 5
df['week_number'] = df.index.isocalendar().week.astype(int)
# 3. 月次のサマリー
monthly = df.groupby('month').agg(
total_sales=('sales', 'sum'),
avg_customers=('customers', 'mean'),
days=('sales', 'count')
).round(0)
print("=== 月次サマリー ===")
print(monthly)
# 4. 平日 vs 週末
wknd = df.groupby('is_weekend')['sales'].mean().round(0)
print(f"\n=== 平日 vs 週末 ===\n{wknd}")
# 5. 最も売上の多い曜日
best_day = df.groupby('day_name')['sales'].mean().sort_values(ascending=False)
print(f"\n=== 最も売上の多い曜日 ===\n{best_day.head(3)}")
# 6. 前月比の成長率
monthly_sales = df.resample('M')['sales'].sum()
mom_growth = monthly_sales.pct_change().round(3) * 100
print(f"\n=== 前月比成長率 % ===\n{mom_growth}")
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)して一緒に進めてください。実際の値はpandasのバージョンによって若干異なる場合があります。
❓ よくある質問
Q to_datetime の形式(format)を指定するにはどうすればよいですか?
A ISO形式(2024-01-15)は自動検出されるため、formatパラメータは不要です。非標準の形式にはformatパラメータを使います:
pd.to_datetime(s, format='%d/%m/%Y')。Pythonのstrftime形式コードは、%Yが年、%mが月、%dが日、%Hが時、%Mが分、%Sが秒です。形式を指定すると、自動検出より5〜10倍高速です。Q .dt は .str と似ていますか?
A はい—.strは文字列アクセサ、.dtは日付時刻アクセサです。どちらも .accessor.method() の構文を使い、NaN/NaTの値を自動的にスキップし、メソッドチェーンをサポートします。.strは文字列の列で動作し、.dtは日付時刻の列で動作します。
Q Timedelta はどのような操作をサポートしますか?
A Timestamp ± Timedelta = Timestamp(日付の加算/減算)。Timestamp - Timestamp = Timedelta(日付の差分)。Timedelta ± Timedelta = Timedelta(時間間隔の加算/減算)。Timedelta × int = Timedelta(時間間隔の乗算)。Timedelta + Timedelta = Timestamp はサポートされていません(意味がないため)。
Q 頻度 D と B の違いは何ですか?
A D = 暦日(週末を含む)、B = 営業日(週末をスキップ)。
date_range(freq='D') は毎日を生成し、bdate_range() または freq='B' は営業日のみを生成します。月次の頻度では、MS = 月初、M = 月末です。間違った頻度を選ぶと、リサンプルの結果が大きく異なる可能性があります。Q タイムゾーンを扱うにはどうすればよいですか?
A tz_localizeでタイムゾーンを設定し、tz_convertでタイムゾーン間を変換します:
df.index.tz_localize('UTC').tz_convert('Asia/Shanghai')。Pandasはpytz/dateutilのタイムゾーンライブラリを使用します。一般的なワークフローは、UTCタイムスタンプの読み込み → ローカルタイムゾーンへの変換 → ローカル日付での集計です。Q NaT とは何ですか?
A NaT(Not a Time)は日付時刻型の欠損値で、NaNに相当します。pd.to_datetime(errors='coerce') は無効な日付をNaTに変換します。NaTを含む操作はすべてNaTを返します(NaNと同様)。検出には pd.isna() / pd.notna() を使います。
Q Period と Timestamp の違いは何ですか?
A Timestampは時点(2024-01-15 10:30:00)ですが、Periodは期間(2024年1月)です。Periodにはstart_timeとend_timeの属性があります。月次・四半期のレポートにはPeriodを、イベントのタイムスタンプにはTimestampを使います。resampleはPeriodオブジェクトを生成し、rollingにはTimestampが必要です。
📖 まとめ
- Pandasには4つの日付時刻型があります:Timestamp(時点)/DatetimeIndex(時系列)/Timedelta(時間間隔)/Period(期間)
- pd.to_datetimeは文字列の日付をパースします。formatパラメータで形式を指定し、errors='coerce'で無効値を適切に処理します
- .dtアクセサは日付時刻のプロパティ(year/month/day/hour/dayofweek/quarterなど)を抽出します
- Timedeltaは日付の加算・減算をサポートします。pd.to_timedeltaは文字列や数値から時間間隔を作成します
- date_rangeは頻度エイリアス D/B/W/MS/M/QS/Q/H で日付シーケンスを生成します
- DatetimeIndexをインデックスにすると、時系列分析(resample/shift/rolling)が可能になります
- 営業日にはbdate_rangeまたはfreq='B'を、タイムゾーンにはtz_localize/tz_convertを使います
📝 練習問題
- 基礎(難易度 ⭐):日付文字列を含むSeriesを作成し、to_datetimeでパースして月(month)と曜日(dayofweek)を抽出し、月ごとのレコード数を集計してください。
- 応用(難易度 ⭐⭐):30日分の日次売上DataFrame(DatetimeIndex付き)を作成し、dtでis_weekendを抽出して平日と週末の平均売上を比較し、Timedeltaを計算して最高売上の日が何日前だったかを求めてください。
- チャレンジ(難易度 ⭐⭐⭐):90日分のコーヒーショップの売上データをシミュレートし、次の処理を完成させてください:to_datetimeによるパース → set_index → dtで月/四半期/曜日の抽出 → groupbyによる月次サマリー → 前月比成長率の計算 → 最も売上の多い曜日の特定。



