埋め込み(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
)について- 列インデックス(
embedding_indices[col]
)を取得し、 - その列の ユニーク値(
np.unique(X_seq[:, :, idx])
) を集め、 - 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
)に対し、- 各列について、シーケンス長
S
ぶんの値を カテゴリ写像で整数ID化、 - 形状(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層にそのまま投入できる状態になります。
コメント