- Amazon: Pythonによるデータ分析入門 第2版 / 実践機械学習 第2版
- 楽天: Pythonによるデータ分析入門 第2版 / 実践機械学習 第2版
なぜPandasの“ちょい技”が効くのか
機械学習の精度はアルゴリズムだけで決まるわけではありません。多くの時間を占める前処理と特徴量づくりで、スピードと再現性を高めることが成果に直結します。ここでは、Pandasを使った実務で効いたトリックを7つに絞って紹介します。どれも小さな工夫ですが、積み上げると大きな差になります。
1. 読み込みを設計する:usecols・dtype・parse_dates
読み込みの最適化はその後のすべてを速く、軽くします。不要な列を読み込まない、型を明示、日付は最初から日時型に。
import pandas as pd
cols = ["id", "date", "price", "category"]
dtypes = {"id": "int32", "price": "float32", "category": "category"}
df = pd.read_csv(
"data.csv",
usecols=cols,
dtype=dtypes,
parse_dates=["date"],
)
df = df.set_index("id")
使う列だけを読み、型を固定することで、メモリと速度を両立します。読み込み時にインデックスを決めると、後工程の結合・検索も安定します。
2. 型とメモリを整える:downcast・to_datetimeのエラー許容
推論環境に載せることも考え、型を小さく安全に。
# 数値のダウンキャスト
for c in ["price"]:
df[c] = pd.to_numeric(df[c], errors="coerce", downcast="float")
# 文字列→日付(壊れた値はNaTに)
df["date"] = pd.to_datetime(df["date"], errors="coerce")
エラーは強制的にNaN/NaTへ。後段の欠損処理と組み合わせて、堅牢さを担保します。
3. カテゴリはcategoryで管理し、コード化とダミー化を使い分け
低〜中カーディナリティな文字列はcategory
型が最適。メモリ削減と処理速度の両方に効きます。
# カテゴリ型化とコード化
cat_col = "category"
df[cat_col] = df[cat_col].astype("category")
df[cat_col + "_code"] = df[cat_col].cat.codes
# one-hot(落とし込み過ぎに注意)
df = pd.get_dummies(df, columns=[cat_col], drop_first=True)
ツリー系ではコード化、線形モデルではダミー化など、学習器に合わせて選ぶのがコツです。
4. メソッドチェーンで“再現可能な前処理パイプライン”
assign
・query
・eval
・pipe
を組み合わせると、ノートブックの散逸を防ぎ、処理を一望できます。
def add_features(df):
return (
df
.query("price > 0")
.assign(
log_price=lambda d: np.log1p(d["price"]),
day=lambda d: d["date"].dt.day,
)
.assign(
price_rolling7=lambda d: d["price"].rolling(7, min_periods=1).mean()
)
)
import numpy as np
df_feat = (df
.sort_values("date")
.pipe(add_features))
関数add_features
に閉じ込めると、学習・推論の両方で同じロジックを使い回せます。
5. シャッフル・分割を手早く:sampleとグループ分割
データフレームだけで手早く分割したいとき。
# シャッフル
df_shuffled = df.sample(frac=1, random_state=42)
# ホールドアウト分割(80/20)
train = df_shuffled.sample(frac=0.8, random_state=42)
valid = df_shuffled.drop(train.index)
# ラベルごとに比率を保つ分割(簡易ストラタム)
label = "target"
train_s = (df
.groupby(label, group_keys=False)
.apply(lambda x: x.sample(frac=0.8, random_state=42)))
valid_s = df.drop(train_s.index)
厳密な分割はsklearn.model_selection.train_test_split
のstratify
が便利ですが、Pandasだけでも実用的に運用できます。
6. groupby・transform・rollingで“軽い”特徴量を量産
行指向のapply
は遅くなりがち。まずはベクトル化・集約で作れる特徴量を最大化しましょう。
# 集約特徴(顧客平均など)
df["price_user_mean"] = df.groupby("user_id")["price"].transform("mean")
# 時系列の移動平均(ユーザー単位)
df = df.sort_values(["user_id", "date"]).copy()
df["price_roll3"] = (
df.groupby("user_id")["price"].rolling(3, min_periods=1).mean().reset_index(level=0, drop=True)
)
transform
は元の行数を保つため、学習データにそのまま合流できるのが強みです。
7. 欠損と外れ値の“早期発見・早期治療”ルーチン
学習前のクイック健診を習慣に。
# 概要チェック
df.info()
print(df.describe(include="all"))
# 欠損率・分布
na_rate = df.isna().mean().sort_values(ascending=False)
print(na_rate.head())
# シンプルな欠損処理
num_cols = df.select_dtypes(include=["number"]).columns
df[num_cols] = df[num_cols].fillna(df[num_cols].median())
# カテゴリの穴埋め
cat_cols = df.select_dtypes(include=["category", "object"]).columns
df[cat_cols] = df[cat_cols].fillna("(missing)")
まずは単純な方針で一貫性を持たせ、必要なら後で高度な手法(KNNや多重代入など)へ切り替えます。
現場で効く運用のヒント
- 最初に「読み込み契約(列・型・欠損)」を決めると、下流が安定します。
- 特徴量関数は
pipe
でカプセル化し、学習・推論で同一化。 - まずはベクトル化で速く作れる特徴量を最大化。遅い
apply
は最後の手段。 - 分割は常に
random_state
固定。結果の再現性が検証の土台です。
まとめ
Pandasの小さな工夫は、データ準備・特徴量エンジニアリング・検証の全部に効いてきます。ここで紹介した7つをベースに、自分の案件に合わせた“前処理スタイルガイド”を作っておくと、チームの速度と品質がぐっと上がります。まずは一つでも、今日のノートブックから取り入れてみてください。
- Amazon: Pythonによるデータ分析入門 第2版 / 実践機械学習 第2版
- 楽天: Pythonによるデータ分析入門 第2版 / 実践機械学習 第2版