{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.11.11"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":10445,"databundleVersionId":200747,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nfrom sklearn.preprocessing import LabelEncoder\nfrom xgboost import XGBRegressor\nimport matplotlib.pyplot as plt\n\nrseed = 71","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-30T11:41:32.360059Z","iopub.execute_input":"2025-06-30T11:41:32.360510Z","iopub.status.idle":"2025-06-30T11:41:32.368442Z","shell.execute_reply.started":"2025-06-30T11:41:32.360482Z","shell.execute_reply":"2025-06-30T11:41:32.366819Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ----------------------------------------------\n# データ読み込み\n# ----------------------------------------------\nDATA_DIR = \"/kaggle/input/elo-merchant-category-recommendation\"\ntrain = pd.read_csv(f\"{DATA_DIR}/train.csv\")\ntest  = pd.read_csv(f\"{DATA_DIR}/test.csv\")\n\n# 元テーブルからID列と目的変数をコピー\ntrain_card_id = train['card_id'].copy()\ntest_card_id  = test['card_id'].copy()\ntrain_y       = train['target'].copy()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-30T11:41:32.370572Z","iopub.execute_input":"2025-06-30T11:41:32.371053Z","iopub.status.idle":"2025-06-30T11:41:32.740398Z","shell.execute_reply.started":"2025-06-30T11:41:32.371008Z","shell.execute_reply":"2025-06-30T11:41:32.739471Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ----------------------------------------------\n# メインテーブルの特徴量作成\n# ・年月文字列は欠損補完・Label Encoding\n# ・他はそのまま\n# ----------------------------------------------\n\n# 元テーブルから特徴量をコピー（目的変数は削除）\ntrain_x = train.copy().drop(columns=[\"target\"])\ntest_x  = test.copy()\n\n# 年月文字列に欠損があるので補完\ntrain_x[\"first_active_month\"] = train_x[\"first_active_month\"].fillna(\"Unknown\")\ntest_x[\"first_active_month\"]  = test_x[\"first_active_month\"].fillna(\"Unknown\")\n\n# 年月文字列をLabel Encoding\nle = LabelEncoder()\nall_months = pd.concat([train_x[\"first_active_month\"], test_x[\"first_active_month\"]])\nle.fit(all_months)\ntrain_x[\"fam_label\"] = le.transform(train_x[\"first_active_month\"])\ntest_x[\"fam_label\"]  = le.transform(test_x[\"first_active_month\"])\n\n# 変換前の年月文字列を削除\ntrain_x = train_x.drop(columns=[\"first_active_month\"])\ntest_x  = test_x.drop(columns=[\"first_active_month\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-30T11:41:32.741410Z","iopub.execute_input":"2025-06-30T11:41:32.741674Z","iopub.status.idle":"2025-06-30T11:41:32.879193Z","shell.execute_reply.started":"2025-06-30T11:41:32.741653Z","shell.execute_reply":"2025-06-30T11:41:32.877704Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":" # ----------------------------------------------\n # 追加テーブルの特徴量作成\n # ----------------------------------------------\n\n # 追加テーブルの読み込み\n new_trans = pd.read_csv(f\"{DATA_DIR}/new_merchant_transactions.csv\")\n print(new_trans.describe())\n\n# merchants.csv の読み込み\n mer_trans = pd.read_csv(f\"{DATA_DIR}/merchants.csv\")\n\n# new_merchant_transactions に merchants 情報を結合\n new_trans_with_merchants = pd.merge(new_trans, mer_trans, on='merchant_id', how='left')\n\n # 集約特徴の作成パターンを辞書化\n agg_funcs_new_with_merchants = {\n     \"purchase_amount\": [\"min\", \"max\", \"mean\"], # 正規化済みの購入金額（負値 = 顧客の支出）\n     \"installments\":    [\"min\", \"max\", \"mean\"], # 分割払いの分割回数\n     \"month_lag\":       [\"min\", \"max\", \"mean\"], # 基準日からの経過月数\n     \"purchase_date\":   [\"count\"],      # 購入日時（countで空でない行を数える ⇔ 購入回数）\n\n     \"category_4\":        [\"nunique\"], # 例: カテゴリ4のユニーク数\n     \"avg_sales_lag3\":   [\"min\", \"max\",\"mean\"],    # merchants.csvにある数値カラムの例\n     \"merchant_group_id\": [\"nunique\"],\n     \"active_months_lag3\":  [\"min\", \"max\",\"mean\"],\n }\n # 例）\"month_lag\": [\"min\", \"mean\", \"max\"],\n # 　　⇔　変数 \"month_lag\" について，同一IDの中で\n # 　　　　最小値，平均値，最大値を取って集約特徴に追加する\n\n # 全ての行を card_id の値でグループ化\n # ⇒　上の集約パターンに従って実際に特徴を集約\n agg_new_with_merchants = new_trans_with_merchants.groupby(\"card_id\").agg(agg_funcs_new_with_merchants)\n\n # 備考）上の集約特徴のテーブルは，列が MultiIndex の状態になっている\n # 　　　⇒　列名のリストを表示して確認してみよう\n print(agg_new_with_merchants.columns.to_list())\n # 1列を指定するために「変数名と集約関数」をペアで指定する必要があることがわかる\n\n # 新特徴の名前（列名）を機械的に生成してリスト化\n # 　　命名規則：元変数名_集約方法（「purchase_amount_mean」など）\n flat_cols_new_with_merchants = []\n for col_name, func_name in agg_new_with_merchants.columns.to_flat_index():\n    new_name = f\"new_merchants_{col_name}_{func_name}\" # 識別しやすいようにプレフィックスを付ける\n    flat_cols_new_with_merchants.append(new_name)\n\n # MultiIndex状態の列を通常の状態に変換（列方向に平坦化）\n agg_new_with_merchants.columns = flat_cols_new_with_merchants\n print(agg_new_with_merchants.columns.to_list())\n\n # groupby によるグループ化を解除（card_idを通常の列に戻す）\n agg_new_with_merchants = agg_new_with_merchants.reset_index()\n\n\n\n\n # historical_transactions.csv の読み込み\n hist_trans = pd.read_csv(f\"{DATA_DIR}/historical_transactions.csv\")\n\n # 集約特徴の作成パターンを辞書化 (例: purchase_amountの平均、installmentsの合計など)\n agg_funcs_hist = {\n    \"purchase_amount\": [\"min\", \"max\",\"mean\", \"sum\"],\n    \"installments\":    [\"min\", \"max\",\"sum\"],\n    \"month_lag\":       [\"min\", \"max\", \"mean\"],\n    \"purchase_date\":   [\"count\"],\n }\n\n # card_id でグループ化し、集約\n agg_hist = hist_trans.groupby(\"card_id\").agg(agg_funcs_hist)\n\n # 列名の平坦化\n flat_cols_hist = []\n for col_name, func_name in agg_hist.columns.to_flat_index():\n    new_name = f\"hist_{col_name}_{func_name}\" # 識別しやすいようにプレフィックスを付ける\n    flat_cols_hist.append(new_name)\n agg_hist.columns = flat_cols_hist\n agg_hist = agg_hist.reset_index()\n\n\n\n # メインテーブルの特徴と結合\n train_x = train_x.merge(agg_new_with_merchants, on=\"card_id\", how=\"left\")\n test_x  = test_x.merge(agg_new_with_merchants, on=\"card_id\", how=\"left\")\n\n # historical_transactions の集約特徴量を結合\n train_x = train_x.merge(agg_hist, on=\"card_id\", how=\"left\") # agg_hist を結合\n test_x  = test_x.merge(agg_hist, on=\"card_id\", how=\"left\")  # agg_hist を結合\n\n\n # Fill missing values created by the left join\n train_x = train_x.fillna(-1)\n test_x  = test_x.fillna(-1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-30T11:41:32.882188Z","iopub.execute_input":"2025-06-30T11:41:32.882566Z","iopub.status.idle":"2025-06-30T11:43:24.575656Z","shell.execute_reply.started":"2025-06-30T11:41:32.882539Z","shell.execute_reply":"2025-06-30T11:43:24.574518Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ID列を削除\ntrain_x = train_x.drop(columns=[\"card_id\"])\ntest_x  = test_x.drop(columns=[\"card_id\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-30T11:43:24.576843Z","iopub.execute_input":"2025-06-30T11:43:24.577188Z","iopub.status.idle":"2025-06-30T11:43:24.604719Z","shell.execute_reply.started":"2025-06-30T11:43:24.577158Z","shell.execute_reply":"2025-06-30T11:43:24.603650Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ----------------------------------------------\n# 使用する特徴量の可視化\n# ----------------------------------------------\n\n# 各特徴の統計量\nprint(pd.concat([train_x, train_y], axis=1).describe())\n\n# 各特徴のヒストグラム\ntrain_x.hist(bins=100, color=\"blue\", grid=True, label='pandas')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-30T11:43:24.606038Z","iopub.execute_input":"2025-06-30T11:43:24.606459Z","iopub.status.idle":"2025-06-30T11:43:32.750160Z","shell.execute_reply.started":"2025-06-30T11:43:24.606426Z","shell.execute_reply":"2025-06-30T11:43:32.749080Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ------------------------------\n# XGBoostの学習・推論・submit\n# ------------------------------\nmodel = XGBRegressor(random_state=rseed)\nmodel.fit(train_x, train_y)\npreds = model.predict(test_x)\n\nsubmission = pd.DataFrame({\n    \"card_id\": test_card_id,\n    \"target\":  preds\n})\n\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true,"execution":{"iopub.status.busy":"2025-06-30T11:43:32.751235Z","iopub.execute_input":"2025-06-30T11:43:32.751511Z","iopub.status.idle":"2025-06-30T11:43:34.965452Z","shell.execute_reply.started":"2025-06-30T11:43:32.751491Z","shell.execute_reply":"2025-06-30T11:43:34.964203Z"}},"outputs":[],"execution_count":null}]}