
アルゴリズムを変えても精度が伸びない…
結論:モデル精度の大半は特徴量設計とリーク対策が結果の大半を決めます。
アルゴリズムを頻繁に変えるより、まずは土台を整えるのが近道です。
この記事で身に付く力
- 現場で使える特徴量設計の“型”(時間窓・集約・比/差分)
- リークを防ぐパイプライン構築(ColumnTransformer×Pipeline)
- 評価と自動化(CV±std、Permutation Importance、スクリプト化)
関連記事:
>>【保存版】scikit-learn基礎:回帰・分類・前処理・パイプライン・交差検証を“実務の型”で習得
>>【保存版】モデル評価:指標の選び方・交差検証・閾値最適化・ビジネス接続を“実務の型”で解説
>>【保存版】ハイパーパラメータ入門:Grid/Random/Optunaの実務チューニング完全ガイド
>>【保存版】pandas基礎:データフレームの作成・整形・結合・集計を“実務の型”で身につける
>>【実務で差がつく】pandas実践:欠損処理・結合・ウィンドウ関数・時系列・品質保証まで“読みやすく速い”型を習得
>>【保存版】NumPy基礎:配列・ブロードキャスト・ベクトル化・乱数・線形代数を“実務の型”で最短習得
>>実務で使える統計の型12 | Pythonで最短習得
>>【保存版】可視化入門:Matplotlib/Plotlyの使い分けと“伝わるグラフ設計”10ステップ
>>はじめてのSQL:SELECT/WHERE/GROUP BYを最短で理解【コピペOK】
>>【保存版】SQLite×Pythonで作る“ローカルDWH”——ETL・集計・レポート自動化の最短手順
>>【保存版】Jupyter Notebookの基本:環境構築・使い方・再現性・“読みやすいノート”設計まで完全ガイド
>>【保存版】Git/GitHub入門:バージョン管理・ブランチ戦略・レビュー・自動化を“実務の型”で最短習得
>>【コピペOK】pytestで“壊れないPython”を作る12ステップ
>>【保存版】データ職のポートフォリオ完全ガイド|再現性・評価・LTまで
よくあるつまずき(3つ)と先に押さえる解決方針
闇雲にアルゴリズムを変えても、土台が整っていないと精度は伸びません。まずはここを直します。
- リーク(情報漏れ):未来情報や目的変数の影響が混入→CVは良いのに本番で崩れる。
- スケール不一致:桁がバラバラ→勾配・距離ベースの手法が不安定。
- 高カーディナリティ:カテゴリが多すぎ→One-Hotが膨張。
解決の型:ColumnTransformer+Pipelineで“学習内の処理”に閉じ込み、交差検証で評価しながら小さく積む。
実務で効いた話(ふみと)
役員会向けの意思決定支援で刺さったのは、業務ロジック×時間軸を写した特徴量(例:直近4週移動平均/前年同週比/在庫ギャップ)。そして訓練データ内統計のみで変換するリーク対策。以降はこの方針でテンプレ化していきます。
実装テンプレ:特徴量“実務の型”10ブロック
以下のコードはそのままコピペでOK。学習内に前処理を閉じ込めるのが最大のポイントです。
1) データ要件とターゲット定義(最重要)
何を・いつまでに・誰の意思決定に使うのかを先に固定します。
予測日:YYYY-MM-DD
学習窓:予測日の過去N日(例:90日)
評価窓:直近L日(例:30日)
ターゲット:評価窓内の離反=1
目的と時間窓を先に決めると、“未来を見てしまう”事故を防げます。
2) 前処理の骨組み(ColumnTransformer×Pipeline)
目的:欠損補完・スケーリング・エンコードを訓練データでfit→検証/本番に適用できる形にする。
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score, StratifiedKFold
num_cols = ["qty","price","days_since_last","amount"]
cat_cols = ["store","category","area"]
# 数値: 欠損→中央値、→標準化
num_pipe = Pipeline([
("impute", SimpleImputer(strategy="median")),
("scale", StandardScaler()),
])
# カテゴリ: 欠損→最頻値、→One-Hot(未知カテゴリは無視、まれな値は束ねる)
cat_pipe = Pipeline([
("impute", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(handle_unknown="ignore", min_frequency=5))
])
# 列ごとに処理を振り分ける
preprocess = ColumnTransformer([
("num", num_pipe, num_cols),
("cat", cat_pipe, cat_cols)
])
# 前処理→モデルを直列化
clf = Pipeline([
("prep", preprocess),
("model", LogisticRegression(max_iter=1000, n_jobs=-1))
])
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
# 不均衡分類ではPR-AUC推奨
scores = cross_val_score(clf, X, y, scoring="average_precision", cv=cv, n_jobs=-1)
print(scores.mean(), scores.std())
ここでやっていること:
min_frequencyでレアカテゴリを自動で束ね、One-Hot爆発を緩和。- Impute/Scale/EncodeはすべてPipeline内。
fitは訓練折のみで行われ、検証・本番には学習済みパラメータを適用→リーク防止。
3) 時間特徴量(時系列の基本)
目的:季節性や周期性、直近の勢いを表現する。
df["date"] = pd.to_datetime(df["date"])
df["ym"] = df["date"].dt.to_period("M").astype(str)
df["dow"] = df["date"].dt.dayofweek
df = df.sort\_values("date")
df\["amt"] = df\["qty"]\*df\["price"]
# ラグ/移動平均(未来参照はNG)
df\["amt\_lag1"] = df.groupby("store")\["amt"].shift(1)
df\["amt\_ma4"] = df.groupby("store")\["amt"].rolling(4).mean().reset\_index(level=0, drop=True)
# 季節性
df\["month"] = df\["date"].dt.month
注意:shift(-1)のように未来を見る操作は厳禁。学習期間と評価期間をまたぐ平均もNG。
4) 集約特徴量(個体×時間窓で完結)
目的:
- 過去一定期間の“量・頻度・平均”を個体(顧客/店舗など)単位で表す。
- 同一個体内×指定期間で完結させ、他個体から情報が混ざらないようにする。
# 直近90日の顧客別集約例
win = df.groupby(["customer"]).rolling("90D", on="date")["amt"].agg(["sum","mean","count"]).reset_index()
win.columns = ["customer","date","amt_sum90","amt_mean90","txn90"]
df = df.merge(win, on=["customer","date"], how="left")
時間窓を限定し、同一個体内の統計を使う(クロス個体の情報混入に注意)。
5) 高カーディナリティ対策(Rare/Hash/Target Encoding)
目的:カテゴリが多い列の表現を安定させ、過学習とサイズ爆発を防ぐ。
- Rare Bucketing:出現が少ない値を
_OTHERに束ねる(min_frequencyで半自動) - Hashing:次元を固定して衝突を許容する(木系で有効なことが多い)
- Target Encoding:Fold内平均でリークを避ける
import pandas as pd
from sklearn.model_selection import KFold
def kfold\_target\_encoding(X\_col, y, n\_splits=5, seed=42):
X\_col = pd.Series(X\_col)
kf = KFold(n\_splits=n\_splits, shuffle=True, random\_state=seed)
enc = pd.Series(index=X\_col.index, dtype=float)
for tr, va in kf.split(X\_col):
m = y.iloc\[tr].groupby(X\_col.iloc\[tr]).mean()
enc.iloc\[va] = X\_col.iloc\[va].map(m).fillna(y.iloc\[tr].mean())
return enc
X\["store\_te"] = kfold\_target\_encoding(X\["store"], y)
ポイント:全データ平均でのエンコードはリーク。必ずFold内で算出→検証へ適用します。
6) 欠損と外れ値(フラグを別列で持つ)
目的:欠損そのものが情報のときに“消えないように”扱う。
from sklearn.impute import SimpleImputer
# 欠損フラグを別に持つ
X\["qty\_isna"] = X\["qty"].isna().astype(int)
# 数値はmedian、カテゴリは最頻
imputer\_num = SimpleImputer(strategy="median")
imputer\_cat = SimpleImputer(strategy="most\_frequent")
7) 変換:スケーリング/ボックス変換/ビニング
目的:手法に合う分布・スケールに整形する。
StandardScaler:平均0・分散1(ロジ回/線形/距離系)MinMaxScaler:0–1スケーリング(木系は不要なことが多い)RobustScaler:外れ値に強いPowerTransformer(Yeo-Johnson):分布の歪み是正KBinsDiscretizer:連続値→離散化(境界はドメイン判断
すべてPipeline内で。外で一括実行はリークの温床です。
8) 相互作用・比・差分(業務ロジックを写す)
目的:現場の指標に近い形に落とす。
X["unit_price"] = X["amount"]/X["qty"]
X["stock_gap"] = X["forecast_stock"] - X["actual_stock"]
X["price_ratio"] = X["price"] / X.groupby("category")["price"].transform("median")
解釈:差分・比は直感的で、カテゴリ基準比は季節やトレンドの影響を相対化できます。
9) 特徴量選択(軽量セット)
目的:説明性と計算効率を両立する。
- 高相関は片方を落とす(解釈重視なら有効)
- L1正則化(Lasso/Logistic)でスパース化
- Permutation ImportanceはCVの外側で計算(内側だと楽観バイアス)
from sklearn.inspection import permutation_importance
clf.fit(X_tr, y_tr)
r = permutation_importance(clf, X_va, y_va, n_repeats=5, random_state=42)
10) 評価・改善・自動化(締め)
- 評価:分類→PR-AUC/ROC-AUC、回帰→MAE/RMSE。CV±stdとTop-kでビジネス指標に接続。
- 改善:特徴量の追加/削除→再CV。過学習は正則化・単純化で抑制。
- 自動化:
Pipeline+GridSearchCV/RandomizedSearchCVで再現可能に。
付録:よく使う拡張・チェック・テスト
A. ColumnTransformer×Datetime機能拡張例
目的:日付から月・曜日などの派生列を前処理パイプラインの中で生成する。
from sklearn.preprocessing import FunctionTransformer
# 入力: DataFrame(date列を含む)→ 出力: 追加する派生列だけ返す
def add_date_parts(d):
d = d.copy()
dt = pd.to_datetime(d["date"])
d["month"], d["dow"] = dt.dt.month, dt.dt.dayofweek
return d[["month","dow"]]
preprocess = ColumnTransformer([
("num", num_pipe, num_cols),
("cat", cat_pipe, cat_cols),
("date", FunctionTransformer(add_date_parts), ["date"]) # date→2列
])
B. リークのチェックリスト(保存版)
- 未来日付/未来在庫を使っていない
- Target EncodingはFold内平均で実施
- 標準化/欠損補完は学習内でfit
- 集約は同一個体/時間窓内で完結
- 評価は時系列CV or KFoldで設計(シャッフル有無を吟味)
C. テスト最小セット(pytest)
# tests/test_features.py
import pandas as pd
from src.features import make_features
def test\_no\_future\_leak():
df = pd.DataFrame({"date": pd.date\_range("2025-01-01", periods=10, freq="D"),
"amt": range(10)})
X = make\_features(df)
\# lagは必ずNaNを含む(未来参照なしの証拠)
assert X.filter(like="lag").isna().sum().sum() > 0
読者タイプ別:最短で“刺さる”一手
- 社会人(転職準備):時間窓×差分/比+Target Encoding(CV付き)。
CVの平均±stdとTop-kで意思決定に接続。 - 副業(すぐ成果):在庫ギャップ/需要移動平均/前年同週比などKPI直結の特徴量を優先。
- 在宅(学習継続):まずはPipeline化して“ボタン一発”。欠損フラグ+RobustScalerで安定運用。
行動課題:ミニプロジェクト(提出推奨)
課題:「小売の需要予測(回帰)」を想定し、以下の特徴量を作成→CV(KFold)でMAE評価→Permutation Importanceで上位5を報告。
- ラグ:
amt_lag1, lag7 - 移動平均:
amt_ma4, ma12 - 季節:
month, dow - カテゴリ基準比:
price_ratio - 在庫ギャップ:
stock_gap(あれば) - 欠損フラグ:
*_isna
- [ ] 未来参照なし(
shiftは正方向のみ) - [ ] 前処理はPipelineに含めた
- [ ] CV±stdを提示(回帰は
neg_mean_absolute_error) - [ ] Top-k特徴量の重要度を提示
- [ ] Notebook→スクリプト化(
run_all.py)
伴走サポート(任意)
ロジックを数字に翻訳できると、精度と納得感が一気に上がります。リーク対策と評価設計まで含め、短期で“回る”仕組みを作るなら、レビュー付きスクールの活用が近道です。
TechAcademy データサイエンスコース(受講料:174,600円~ ※更に割引あり)

株式会社キカガク AI人材長期育成コース(受講料:237,600円~)

この記事から次に読むべきもの
-
-
【保存版】モデル評価:指標の選び方・交差検証・閾値最適化・ビジネス接続を“実務の型”で解説
精度が上がらない原因の多くは「評価設計の誤り」にあります。 評価は「何点取れたか」を競うものではなく、意思決定に耐えうるか を検証する営みです。本記事は、回帰/分類/ランキングの 指標選定 → 交差検 ...
-
-
【保存版】ハイパーパラメータ入門:Grid/Random/Optunaの実務チューニング完全ガイド
チューニングのゴールは「スコアの数字遊び」ではありません。意思決定に耐える安定した最適化を短時間で作ること。 本記事は未経験〜初学者が週10時間×2週間で、GridSearchCV / Randomi ...
-
-
【保存版】scikit-learn基礎:回帰・分類・前処理・パイプライン・交差検証を“実務の型”で習得
機械学習で迷子になる最大の理由は、前処理→学習→評価→改善の順番が曖昧なまま個々のアルゴリズムに飛びつくこと。 本記事は、未経験〜初学者が週10時間×2〜3週で到達できるscikit-learnの最短 ...
-
-
【実務で差がつく】pandas実践:欠損処理・結合・ウィンドウ関数・時系列・品質保証まで“読みやすく速い”型を習得
基礎文法の次は、実務で毎回出る処理を“型”として覚える段階です。 本記事は、pandas 2.x を前提に、欠損・外れ値・結合・ウィンドウ関数・時系列・カテゴリ処理・集計の自動化・大規模データの分割処 ...
-
-
はじめてのSQL:SELECT/WHERE/GROUP BYを最短で理解【コピペOK】
データ分析・自動レポート・簡易アプリの土台はSQLです。Pythonだけで押し切るより、前処理の7割をDB側で完結させる方が速く・安定します。本記事は、未経験〜初 学者が週10時間×2〜3週で、SEL ...
最近のコメント