LESSON

特徴量生成

田中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分