学習する(7:Embedding)

学習

埋め込み(Embedding)入力を作る前処理

学習用のシーケンス特徴から 埋め込み(Embedding)入力を作る前処理が必要ですので、以下の通り作成しました。

print("✅ Embedding")
def build_category_maps(X_seq):
    maps = {}
    for col in embedding_cols:
        idx = embedding_indices[col]
        unique_vals = np.unique(X_seq[:, :, idx])
        maps[col] = {v: i for i, v in enumerate(unique_vals)}
    return maps

category_maps = build_category_maps(X_train)
category_maps_str_keys = {
    col: {str(k): v for k, v in mapping.items()}
    for col, mapping in category_maps.items()
}

with open("category_maps.json", "w", encoding="utf-8") as f:
    json.dump(category_maps_str_keys, f, ensure_ascii=False, indent=2)
print("✅ category_maps 保存済み")

def suggest_embedding_dims(input_dims, max_dim=32):
    return {col: min(max_dim, int(np.sqrt(n)) + 1) for col, n in input_dims.items()}

embedding_input_dims = {col: len(category_maps[col]) for col in embedding_cols}
embedding_output_dims = suggest_embedding_dims(embedding_input_dims)

embedding_info = {
    "embedding_cols": embedding_cols,
    "embedding_indices": embedding_indices,
    "embedding_input_dims": embedding_input_dims,
    "embedding_output_dims": embedding_output_dims
}
with open("embedding_info.json", "w", encoding="utf-8") as f:
    json.dump(embedding_info, f, ensure_ascii=False, indent=2)
print("✅ embedding_info 保存済み")

def make_embedding_dict(X_seq, category_maps):
    out = {col: [] for col in embedding_cols}
    for seq in X_seq:
        for col in embedding_cols:
            idx = embedding_indices[col]
            mapping = category_maps[col]
            out[col].append([mapping.get(int(seq[t, idx]), 0) for t in range(sequence_length)])
    return {col: np.array(out[col], dtype=np.int64) for col in out}

X_cat_train = make_embedding_dict(X_train, category_maps)
X_cat_val = make_embedding_dict(X_val, category_maps)
X_cat_test = make_embedding_dict(X_test, category_maps)

このコードは、列ごとのカテゴリ集合を学習データから抽出し、カテゴリ→連番ID の写像を作成・保存、さらに 埋め込み次元の目安 を自動算出し、最終的に モデルへ渡す整数配列(N×S) を生成します。

  • カテゴリ写像の作成(build_category_maps
    学習シーケンス X_train を対象に、各埋め込み列(embedding_cols)について
    1. 列インデックス(embedding_indices[col])を取得し、
    2. その列の ユニーク値(np.unique(X_seq[:, :, idx]) を集め、
    3. 0,1,2,… の 連番IDに再マップ{v: i for i, v in enumerate(unique_vals)})。
      こうして得た 列ごとの辞書(カテゴリ→ID)category_maps に格納。
      なお np.unique は値をソートする点に注意(IDはユニーク値の昇順で付与されます)。
  • JSON 保存のためのキー変換
    JSON は辞書キーに文字列が必要なため、{str(k): v} に変換して category_maps.json へ保存。
    これにより 推論時にも同じマッピングを復元 できます。
  • 埋め込み入出力次元の決定
    • 入力次元embedding_input_dims)は、各列のカテゴリ総数(len(category_maps[col]))。
    • 出力次元embedding_output_dims)はヒューリスティックで決定:
      min(max_dim, int(sqrt(n)) + 1)(デフォルト max_dim=32)。
      カテゴリ数 n に応じて 過不足のない埋め込み幅 を自動提案します。
      これらと列名・列インデックスをまとめて embedding_info.json に保存し、再現性と可搬性 を確保。
  • 埋め込み用テンソルの生成(make_embedding_dict
    各データ分割(X_train, X_val, X_test)に対し、
    1. 各列について、シーケンス長 S ぶんの値を カテゴリ写像で整数ID化
    2. 形状(N, S)int64 配列として格納(列ごとに辞書で保持)。
      未知カテゴリは mapping.get(value, 0)既定の0へフォールバック します(※「0」が実カテゴリに割り当てられる設計のため、未知専用IDを分離したい場合は要調整。たとえば学習時にIDを全体+1し、0を常に UNK として予約する方法など)。
  • 設計上のポイント
    • 学習セットのみからカテゴリ集合を作ることで、未来情報の混入(リーク)を回避
    • 以前のラベルエンコード(LabelEncoder)が「元のカテゴリ→ID」であるのに対し、本処理は 学習用テンソルに現れた整数値をさらに列ごと連番に再圧縮 しています(埋め込みテーブルを無駄なく小さく保つ目的)。
    • 列順は embedding_indices で固定しており、main_feature_order.json と整合する前提です。

結果として、各カテゴリ列に対応する (N, S)形状の整数ID配列X_cat_train/val/test[col])と、入出力次元メタが揃い、PyTorch/TensorFlow などの Embedding層にそのまま投入できる状態になります。

コメント

タイトルとURLをコピーしました