型変換は最初に通る関門で、最もバグが潜む箇所。「日付パース」「数値化」「カテゴリ型」それぞれに固有の罠があります。
日付パースの罠 5 選
- フォーマット混在:`2025/01/01`, `2025-1-1`, `Jan 1, 2025`, `令和7年元日` ── 同じ日
- タイムゾーン:UTC か JST か、システム依存。ナイーブ datetime は禁忌
- 夏時間(DST):欧米データで「9 月の最終日曜深夜 1:30 が 2 回ある」事故
- Unix epoch:秒 / ミリ秒 / マイクロ秒で 1000 倍ズレる
- 和暦:令和 → 2019/05/01 開始、ライブラリによって扱いが違う
数値型の罠
- `int` vs `int64`:オーバーフロー(10 億超は注意)
- `float` の精度:`0.1 + 0.2 != 0.3`、金額は Decimal か整数で
- NaN / Inf の伝染:1 つ NaN が混じると平均・SUM が NaN になる
- 文字列 → 数値:`'1,234'` の `,` は事前除去、`'1.5万'` も対処要
カテゴリ型
- 順序付き vs 順序なし:「小 < 中 < 大」は順序付き、「赤 / 青 / 緑」は順序なし
- 未知カテゴリ:学習データにない値が推論時に来たらどうするか
- メモリ削減:pandas の `category` 型は文字列のメモリを大幅削減
ツール別比較
| ツール | 型変換 | 強み |
|---|---|---|
| pandas | `astype()`、`pd.to_datetime()` | 柔軟、エラー詳細 |
| Polars | `cast()` | 速い、エラーで停止 |
| `safe_cast()` | 失敗時 NULL(事故防止) |
Python 実装:日付パース 6 形式を統一
混在した日付フォーマットを 1 関数で吸収
Python
import pandas as pdfrom datetime import datetimeimport re
def parse_jp_date(s: str) -> pd.Timestamp | None: """日本語データに頻出する日付フォーマットを吸収""" if pd.isna(s) or s == "": return pd.NaT
# 和暦の正規化(令和 → 西暦) if "令和" in s: m = re.search(r"令和(\d+)年", s) if m: year = 2018 + int(m.group(1)) s = re.sub(r"令和\d+年", f"{year}年", s) if "平成" in s: m = re.search(r"平成(\d+)年", s) if m: year = 1988 + int(m.group(1)) s = re.sub(r"平成\d+年", f"{year}年", s)
# 全角数字 → 半角 s = s.translate(str.maketrans("0123456789", "0123456789"))
# pandas の柔軟パーサーに委ねる try: return pd.to_datetime(s, errors="coerce") except Exception: return pd.NaT
# テストtest_cases = [ "2025/01/01", "2025-1-1", "Jan 1, 2025", "令和7年元日", # → 2025-01-01 "令和7年1月1日", "2025年1月1日", "202501/01", # 全角数字]for s in test_cases: print(f"{s!s:25} → {parse_jp_date(s)}")タイムゾーンの罠
Python
import pandas as pd
# ナイーブ datetime(タイムゾーン不在)は禁忌naive = pd.Timestamp("2026-01-01 09:00:00")print(naive.tz) # → None(不安)
# 必ず明示的にjst = pd.Timestamp("2026-01-01 09:00:00", tz="Asia/Tokyo")utc = jst.tz_convert("UTC")print(jst, "==", utc) # 2026-01-01 09:00 JST == 2026-01-01 00:00 UTC
# DataFrame 全体にdf["created_at"] = pd.to_datetime(df["created_at"], utc=True) # 全列 UTC に統一df["created_at_jst"] = df["created_at"].dt.tz_convert("Asia/Tokyo")数値型の罠:金額の精度
Python
from decimal import Decimal
# float の精度問題print(0.1 + 0.2 == 0.3) # False !!!print(0.1 + 0.2) # 0.30000000000000004
# 金額は Decimal か整数(円単位)でamount = Decimal("1234.56")total = amount * 3print(total) # 3703.68(誤差なし)
# pandas で金額列を扱うときdf["amount"] = df["amount"].astype("string").map(Decimal)カテゴリ型のメモリ削減
Python
import pandas as pd
# 数百万行の文字列列をカテゴリ型にdf["status"] = df["status"].astype("category")print(df.memory_usage(deep=True))# 文字列列が 80 MB → カテゴリ化で 8 MB(10 倍削減)
# 順序付きdf["size"] = pd.Categorical( df["size"], categories=["S", "M", "L", "XL"], ordered=True,)df["size"] > "M" # → ブール列で「L 以上」が取れるふくふくの進め方
「型変換で本番事故を起こした」のご相談には、ログ分析 → 型仕様書 → 共通変換関数化を 1〜2 週間で。型エラーで失敗するのが正解で、サイレントに変換し続ける設計は事故の元です。
次回予告
EP.05 は文字列正規化。「ふくふく」「フクフク」「FUKUFUKU」を統一する Unicode 正規化と日本語固有処理。
この記事の感想を教えてください
あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。