特徴量生成
田中VPoE:「特徴量選択は『不要なものを捨てる』技術だったが、今回は『新しいものを生み出す』技術だ。元のデータにない情報をドメイン知識を活かして作り出す。これがデータサイエンティストの腕の見せどころだ。」
あなた:「例えばどんなものを作るんですか?」
田中VPoE:「NetShop なら、『購入金額の変化率』とか『最終購入からの経過日数を区間に分ける』とか。ビジネスの文脈を理解している人間だからこそ作れる特徴量がある。」
特徴量生成(Feature Engineering)とは
既存のデータから新しい特徴量を作り出す技術です。モデルの精度向上に最も大きなインパクトを与えることが多い工程です。
数値変換による特徴量生成
多項式特徴量
from sklearn.preprocessing import PolynomialFeatures
import pandas as pd
import numpy as np
# 元の特徴量
df = pd.DataFrame({
'purchase_count': [5, 10, 3, 20, 8],
'avg_amount': [3000, 5000, 2000, 8000, 4000],
})
# 2次の交互作用項を生成
poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
X_poly = poly.fit_transform(df)
print(f"元の特徴量数: {df.shape[1]}")
print(f"生成後の特徴量数: {X_poly.shape[1]}")
print(f"特徴量名: {poly.get_feature_names_out()}")
# → purchase_count, avg_amount, purchase_count * avg_amount
対数変換
右に裾が長い分布(購入金額など)を正規分布に近づけます。
# 対数変換
df['log_amount'] = np.log1p(df['avg_amount']) # log1p = log(1 + x)
# 平方根変換
df['sqrt_count'] = np.sqrt(df['purchase_count'])
変化率・差分
# 月次の購入金額データがある場合
df['amount_change_rate'] = (
(df['this_month_amount'] - df['last_month_amount'])
/ df['last_month_amount'].replace(0, 1) # ゼロ除算防止
)
# 前月比
df['amount_ratio'] = df['this_month_amount'] / df['last_month_amount'].replace(0, 1)
ビニング(離散化)
連続値をカテゴリに変換する手法です。
# 等幅ビニング
df['inactive_bin'] = pd.cut(
df['days_inactive'],
bins=[0, 7, 30, 90, float('inf')],
labels=['活発', '通常', '低活動', '休眠']
)
# 等頻度ビニング(各ビンのデータ数が均等)
df['amount_quantile'] = pd.qcut(
df['avg_amount'],
q=4,
labels=['低額', '中低額', '中高額', '高額']
)
なぜビニングが有効か
- 外れ値の影響を軽減
- 非線形な関係を捉えやすくなる
- ビジネス的に解釈しやすい区分を作れる
ドメイン知識に基づく特徴量
NetShop のビジネスを理解しているからこそ作れる特徴量です。
# NetShop 向け特徴量生成の例
# 1. RFM特徴量(Recency, Frequency, Monetary)
df['recency'] = (pd.Timestamp.now() - df['last_purchase_date']).dt.days
df['frequency'] = df['purchase_count_90days']
df['monetary'] = df['total_amount_90days']
# 2. エンゲージメント指標
df['purchase_per_visit'] = df['purchase_count'] / df['visit_count'].replace(0, 1)
df['avg_session_duration'] = df['total_session_time'] / df['visit_count'].replace(0, 1)
# 3. トレンド特徴量
df['purchase_trend'] = df['purchases_recent_30d'] - df['purchases_prev_30d']
df['activity_declining'] = (df['purchase_trend'] < 0).astype(int)
# 4. 時間系特徴量
df['days_since_registration'] = (pd.Timestamp.now() - df['registration_date']).dt.days
df['is_weekend_buyer'] = (df['most_frequent_purchase_day'].isin([5, 6])).astype(int)
# 5. 集約特徴量
df['support_per_purchase'] = df['support_tickets'] / df['purchase_count'].replace(0, 1)
df['return_rate'] = df['return_count'] / df['purchase_count'].replace(0, 1)
特徴量生成のコツ
| カテゴリ | 手法 | 例 |
|---|---|---|
| 比率・割合 | A / B | 返品率、コンバージョン率 |
| 差分・変化 | A - B | 前月比の変化量 |
| 集約 | groupby + agg | カテゴリ別の平均購入額 |
| 時間 | 日付の差分 | 最終購入からの経過日数 |
| フラグ | 条件判定 | 90日以上非活動 |
| 組合せ | A * B | 購入回数 x 平均単価 |
特徴量生成の注意点
データリーケージに注意
# NG: 未来の情報を使っている
df['will_return_item'] = ... # 離反後の返品情報
# OK: 予測時点で利用可能な情報のみ
df['past_return_rate'] = df['returns_90days'] / df['purchases_90days']
特徴量の数を増やしすぎない
# 大量に生成した後は、特徴量選択で絞り込む
from sklearn.feature_selection import SelectKBest, f_classif
selector = SelectKBest(f_classif, k=20)
X_selected = selector.fit_transform(X_engineered, y)
# 選択された特徴量を確認
selected_mask = selector.get_support()
selected_features = [f for f, s in zip(feature_names, selected_mask) if s]
print(f"生成した特徴量: {len(feature_names)}")
print(f"選択された特徴量: {len(selected_features)}")
まとめ
- 特徴量生成はモデル精度に最も大きなインパクトを与える
- 多項式特徴量、対数変換、ビニングなどの数学的変換がある
- ドメイン知識を活かした特徴量が最も価値が高い
- RFM 分析やエンゲージメント指標は EC サイトで有効
- データリーケージと特徴量数の管理に注意
チェックリスト
- 多項式特徴量の生成方法を理解した
- ビニングの目的と実装方法を把握した
- ドメイン知識に基づく特徴量を3つ以上考えられる
- 特徴量生成時のデータリーケージに注意できる
次のステップへ
次は演習です。NetShop のデータに対して、特徴量選択・エンコーディング・スケーリング・特徴量生成を一通り実践しましょう。
推定読了時間: 30分