データ型を変換する処理
モデルに渡す前にデータをクレンジング・変換する工程。 ここでの誤りが下流に伝播するので慎重に。
本ページでは 型変換 を、 定義・前提条件・使い方・落とし穴の順に整理して解説します。 厳密な定義より、 まず何を、 いつ、 どう使うかを理解することを優先してください。
データ型を変換する処理
英語名 Type Conversion。
この用語を理解・使用するときは、 次のような前提を意識してください:
SSDSE-B-2026 のような公的統計データを Python で扱う際の基本パターン:
1 2 3 4 5 6 7 8 9 10 11 12 | import pandas as pd import numpy as np # データ読み込み df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1) print(df.shape) print(df.dtypes) print(df.describe()) # 「型変換」の文脈で扱う場合の例: # 分野: データ前処理 # 関連手法は同カテゴリの他用語を参照してください。 |
具体的なコードは データエンジニアリング を参照してください。
分析結果を報告するときに含めるべき情報:
CSV を読み込んだら「数値の列が文字列になっていた」「日付が単なるテキストだった」という経験は誰しもあるはず。 この「型を正しい型に直す」のが型変換。 これを怠ると、 sort が辞書順になったり、 集計で意味のない結果が出たり、 機械学習モデルがエラーを吐いたりします。 つまり、 分析の全工程に影響する、 一見地味で実は最重要な前処理。
型 $T_1$ の値 $x$ から型 $T_2$ の値 $y$ への写像 $f: T_1 \to T_2$ を「型変換(キャスト)」と呼ぶ:
$$y = f(x), \quad x \in T_1, \quad y \in T_2$$情報が保存される(可逆)変換と、 情報が落ちる(不可逆)変換がある。 例: int → float は可逆、 float → int は小数部が落ちる。
| dtype | 意味 | 代表例 | 注意 |
|---|---|---|---|
| int64 | 整数 | 人口、 個数 | NaN を含めない |
| float64 | 浮動小数 | 支出金額、 率 | NaN OK、 比較は誤差注意 |
| object | 文字列(または混在) | 都道府県名 | 混在に注意 |
| datetime64[ns] | 日時 | 調査日、 取引日 | タイムゾーンに注意 |
| category | カテゴリ | 性別、 階層 | メモリ節約、 順序付け可 |
| bool | 真偽値 | 該当/非該当 | NaN は object 化 |
同じ「47 都道府県」のデータを違う型で保存した場合のメモリ比較:
| 列内容 | object型 | category型 | 節約率 |
|---|---|---|---|
| 47 都道府県名 (47行) | ~3.5 KB | ~0.6 KB | 83% |
| 47 都道府県名 × 10年 (470行) | ~35 KB | ~2 KB | 94% |
| int64 → int32 | 8 bytes/値 | 4 bytes/値 | 50% |
| float64 → float32 | 8 bytes/値 | 4 bytes/値 | 50% |
TypeError が出ない状態に整える。data/raw/SSDSE-B-2026.csv (UTF-8、 2 行ヘッダ)。 初期型は多くが object(文字列)。 これに .astype() と df.astype({...}) を組み合わせる。1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='utf-8', skiprows=1) # 文字列を整数に df['総人口'] = df['総人口'].astype(int) # 整数を文字列に df['年'] = df['年'].astype(str) # 複数列を一度に df = df.astype({'消費支出': float, '可処分所得': float, '都道府県': 'category'}) print(df.dtypes) |
astype() は「失敗したら例外を投げる」厳しい変換。 SSDSE-B-2026 の「総人口」のように文字列でも数字のみなら成功するが、 列に「-」「N/A」が紛れていれば ValueError になる。 そのときはパターン 2 の to_numeric(errors='coerce') に切り替える。pd.to_numeric(errors='coerce') でそれらを NaN に置換、 downcast でメモリも 4 倍節約。1 2 3 4 5 6 7 8 9 | # errors='coerce' で変換できない値を NaN に df['消費支出'] = pd.to_numeric(df['消費支出'], errors='coerce') # errors='raise' (デフォルト) でエラーを上げる # errors='ignore' で元の値を保持 # downcast でメモリ節約 df['人口'] = pd.to_numeric(df['人口'], downcast='integer') # int8〜int64 の最小 df['率'] = pd.to_numeric(df['率'], downcast='float') |
errors='coerce' は「変換できないものは NaN にする」現場で最も安全な選択肢。 SSDSE-B-2026 のように欠損記号が「-」「…」で混在する公的統計の取り扱いに必須。 downcast 後はメモリ消費が半減〜1/4 になり、 大規模パネル分析でも実用速度になる。datetime64[ns] 型に変換し、 日付差・週次集計・タイムゾーン換算を可能にする。tz_localize + tz_convert を組み合わせる。1 2 3 4 5 6 7 8 9 10 11 | # ISO 形式は自動認識 df['日付'] = pd.to_datetime(df['日付']) # format 指定(速度・確実性 UP) df['日付'] = pd.to_datetime(df['日付'], format='%Y/%m/%d') # 年月日が別列なら df['日付'] = pd.to_datetime(df[['year', 'month', 'day']]) # タイムゾーン付き df['UTC日時'] = pd.to_datetime(df['日時']).dt.tz_localize('Asia/Tokyo').dt.tz_convert('UTC') |
format= を指定すると変換速度が 10〜100 倍速くなる(自動推測を回避)。 SSDSE のような国内データは Asia/Tokyo で localize → UTC に揃えると、 海外データと突合するときに DST (夏時間)バグが起きない。pd.CategoricalDtype(categories=[...], ordered=True) を渡す。1 2 3 4 5 6 7 8 9 | # 単純なカテゴリ化 df['都道府県'] = df['都道府県'].astype('category') # 順序付きカテゴリ size_order = pd.CategoricalDtype(categories=['小', '中', '大'], ordered=True) df['規模'] = df['規模'].astype(size_order) # メモリ削減効果を確認 print(df.memory_usage(deep=True)) |
sort_values、 groupby、 不等式比較で「小 < 中 < 大」を自動認識するので、 学年・震度・優先度などの順序データに最適。1 2 3 4 5 6 7 8 9 10 11 12 | def optimize_dtypes(df): for col in df.select_dtypes(include=['int']).columns: df[col] = pd.to_numeric(df[col], downcast='integer') for col in df.select_dtypes(include=['float']).columns: df[col] = pd.to_numeric(df[col], downcast='float') for col in df.select_dtypes(include=['object']).columns: if df[col].nunique() / len(df) < 0.5: df[col] = df[col].astype('category') return df df = optimize_dtypes(df) print(df.info(memory_usage='deep')) |
df['col'].astype(int) は NaN があれば ValueError。 → 'Int64'(pandas 拡張型)か fillna() で対応。int 化できない。 str.replace(',', '').astype(int) で除去してから変換。to_datetime 失敗。 専用パーサが必要。0.1 + 0.2 != 0.3 の罠。 金額・率では Decimal や整数(円単位)の方が安全。observed=True で抑制。Int64 なら NaN を保ったまま整数を維持。pandas 1.0 以降、 NaN を保ったまま型を保てる拡張型が登場。 従来の罠を回避できる。
| 従来 | 拡張型 | 利点 |
|---|---|---|
| int64 | Int64 | NaN を含める |
| float64 | Float64 | pd.NA 統一 |
| object | string | 文字列専用、 高速 |
| bool | boolean | NaN を含める bool |
使い方: df['col'] = df['col'].astype('Int64') のように大文字始まりで指定。
| 操作 | Python | SQL | Excel | Power Query |
|---|---|---|---|---|
| 文字 → 数 | int(s) | CAST(x AS INT) | VALUE() | Int64.Type |
| 数 → 文字 | str(n) | CAST(x AS VARCHAR) | TEXT() | Text.Type |
| 文字 → 日時 | pd.to_datetime | CAST(x AS DATE) | DATEVALUE | Date.Type |
| 小数 → 整数 | int(x) | CAST(x AS INT) | INT() | Number.RoundDown |
describe())