特徴量構築の核心:集約と変換のパターン
機械学習パイプラインにおいて、モデルの収束速度および最終精度の大部分は入力表現の質に依存する。生データからは直接捉えきれない隠れた構造を抽出するため、既存変数間に数学的・論理的関係を定義する特徴量構築(Feature Construction)が行われる。本稿では、複数レコード間の関係性を凝縮する集約(Aggregation)手法と、単一/複数列に対する関数マッピングによる変換(Transformation)手法の実装フローを示す。
カテゴリ指定による集約統計量の算出
同一グループ(ユーザーID、製品カテゴリ、日付バケット等)に属する観測値に対して、対象カラムの要約統計量を計算する手法は、予測モデルの入力次元を安全かつ効果的に拡張する標準的なアプローチである。pandasのグループ化機能を用い、代表的な集約関数を適用する。
import pandas as pd
import numpy as np
from scipy import stats
# サンプルテーブルの構築
np.random.seed(42)
dataset = pd.DataFrame({
'org_code': ['GRP_A', 'GRP_A', 'GRP_A', 'GRP_B', 'GRP_B', 'GRP_C', 'GRP_C', 'GRP_C', 'GRP_D', 'GRP_D'],
'event_type': ['login', 'click', 'purchase', 'click', 'login', 'purchase', 'login', 'click', 'purchase', 'login'],
'session_dur': [12, 18, 25, 9, 14, 6, 8, 11, 15, 19],
'page_view': [2, 3, 5, 3, 4, 4, 6, 7, 4, 5]
})
# グループ単位での代表統計量抽出
med_by_grp = dataset.groupby('org_code')['session_dur'].median()
mean_by_grp = dataset.groupby('org_code')['session_dur'].mean()
分布特性を表す統計指標の生成
中心傾向に加え、ばらつき度合や出現頻度を特徴量化することで、クラス間判別能力が向上するケースが多い。各組織コード内での分散、標準偏差、最頻値、行数カウントを計算する実装例。
# 標準偏差と分散
std_dev = dataset.groupby('org_code')['session_dur'].std()
variance = dataset.groupby('org_code')['session_dur'].var()
# 最頻値の取得(多次元配列対応の安全な取り出し)
mode_val = dataset.groupby('org_code')['session_dur'].agg(lambda x: stats.mode(x)[0].tolist()[0])
# グループ内イベント発生回数
freq_cnt = dataset.groupby('org_code')['event_type'].count()
print("集約中央値:", med_by_grp.to_dict())
print("度数カウント:", freq_cnt.to_dict())
集約値と元データの線形結合
木構造アンサンブル(RandomForest, XGBoost, LightGBM)においては、個人値とグループ基準値の差分や比率を用いることで、「所属クラスに対してどちら程度上振れ/下振れしているか」という相対評価指標を形成できる。mergeで集約結果を元データフレームに結合後、ベクトル計算を適用する。
# グループ平均値を左外部結合で付与
ref_col = 'org_avg_session'
dataset = dataset.merge(
dataset.groupby('org_code')['session_dur'].mean().reset_index().rename(columns={'session_dur': ref_col}),
on='org_code', how='left'
)
# 線形変換による新規特徴量作成
dataset['diff_from_grp_mean'] = dataset['session_dur'] - dataset[ref_col]
dataset['ratio_to_grp_mean'] = dataset['session_dur'] / dataset[ref_col]
dataset['prod_with_grp_mean'] = dataset['session_dur'] * dataset[ref_col]
print(dataset[['org_code', 'session_dur', ref_col, 'diff_from_grp_mean']].head())
数値・論理空間への変換処理
単一カラムまたはカラムペアに対し関数写像を適用することで、モデルの学習曲面を平坦化したり、非線形性を明示化したりできる。
単項演算と対数圧縮
定数シフト、スケーリング、対数変換の基本処理。特に右裾の長い分布(例:広告支出、取引金額)を持つ数値特徴量に対し、対数変換は外れ値の影響を緩和し、線形仮定を満たしやすくする。
# 定数加減算と乗除算
dataset['shifted_dur'] = dataset['session_dur'] * 0.1 + 5.0
# 自然対数変換(ゼロまたは負値防止のための微小定数付与)
eps = 1e-6
dataset['log_dur'] = np.log(dataset['session_dur'] + eps)
多変数間演算と相互作用項
複数の特徴量を乗算したり、多項式基底に変換したりすることで、線形分離不可能な境界を近似可能にする。ただし、線形回帰やSVM等では次元爆発や多重共線性のリスクがあるため、モデル特性に応じて適用範囲を限定する。
# 交互作用特徴量(Interaction Features)
dataset['dur_x_views'] = dataset['session_dur'] * dataset['page_view']
dataset['dur_sq'] = dataset['session_dur'] ** 2
# Scikit-learnを用いた多項式特徴量の自動展開
from sklearn.preprocessing import PolynomialFeatures
poly_mapper = PolynomialFeatures(degree=2, include_bias=False)
inter_matrix = poly_mapper.fit_transform(dataset[['session_dur', 'page_view']])
inter_df = pd.DataFrame(inter_matrix, columns=poly_mapper.get_feature_names_out(['duration', 'views']))
比較型・順序型・ビット演算特徴量
レコード横断的な極値抽出、ランキングエンコーディング、ビット条件付き演算も、実務環境で頻繁に使用される表現変換手法である。
# カラム間の最大値・最小値抽出
dataset['max_dur_views'] = dataset[['session_dur', 'page_view']].max(axis=1)
dataset['min_dur_views'] = dataset[['session_dur', 'page_view']].min(axis=1)
# ランキングエンコーディング(降順密集法)
dataset['views_rank_dense'] = dataset['page_view'].rank(method='dense', ascending=False)
# ビット単位排他的論理和(XOR)例
# 事前に閾値で二値化済みと仮定
dataset['is_high_dur'] = (dataset['session_dur'] > dataset['session_dur'].median()).astype(int)
dataset['is_high_views'] = (dataset['page_view'] > dataset['page_view'].median()).astype(int)
dataset['xor_condition'] = dataset.apply(lambda r: int(r['is_high_dur'] ^ r['is_high_views']), axis=1)