{"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-30T14:46:37.010313Z","iopub.execute_input":"2025-06-30T14:46:37.010560Z","iopub.status.idle":"2025-06-30T14:46:37.015663Z","shell.execute_reply.started":"2025-06-30T14:46:37.010541Z","shell.execute_reply":"2025-06-30T14:46:37.014646Z"}},"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-30T14:46:37.016633Z","iopub.execute_input":"2025-06-30T14:46:37.016937Z","iopub.status.idle":"2025-06-30T14:46:37.350434Z","shell.execute_reply.started":"2025-06-30T14:46:37.016889Z","shell.execute_reply":"2025-06-30T14:46:37.349245Z"}},"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-30T14:46:37.351535Z","iopub.execute_input":"2025-06-30T14:46:37.351763Z","iopub.status.idle":"2025-06-30T14:46:37.479038Z","shell.execute_reply.started":"2025-06-30T14:46:37.351747Z","shell.execute_reply":"2025-06-30T14:46:37.478096Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ----------------------------------------------\n# 追加テーブルの特徴量作成\n# ----------------------------------------------\n\n# 追加テーブルの読み込み\nnew_trans = pd.read_csv(f\"{DATA_DIR}/new_merchant_transactions.csv\")\nprint(new_trans.describe())\n\n# 追加テーブルの読み込み\nnew_trans = pd.read_csv(f\"{DATA_DIR}/new_merchant_transactions.csv\")\nnew_trans[\"authorized_flag\"] = new_trans[\"authorized_flag\"].map({\"Y\": 1, \"N\": 0})\nnew_trans[\"category_1\"] = new_trans[\"category_1\"].map({\"Y\": 1, \"N\": 0})\nnew_trans[\"category_3\"] = new_trans[\"category_3\"].map({'A': 0, 'B': 1, 'C': 2})\nnew_trans[\"purchase_date\"] = pd.to_datetime(new_trans[\"purchase_date\"])\nnew_trans[\"month\"] = new_trans[\"purchase_date\"].dt.month\nnew_trans[\"weekend\"] = (new_trans[\"purchase_date\"].dt.weekday >= 5).astype(int)\nnew_trans[\"hour\"] = new_trans[\"purchase_date\"].dt.hour\nnew_trans[\"day\"] = new_trans[\"purchase_date\"].dt.day\nnew_trans[\"dayofweek\"] = new_trans[\"purchase_date\"].dt.dayofweek\n\n# より豊富な統計量で特徴量を作成\nagg_funcs = {\n    \"purchase_amount\": [\"min\", \"max\", \"mean\", \"std\", \"skew\", \"median\", \"sum\"],\n    \"installments\":    [\"min\", \"max\", \"mean\", \"std\", \"nunique\", \"median\"],\n    \"month_lag\":       [\"min\", \"max\", \"mean\", \"std\", \"skew\"],\n    \"authorized_flag\": [\"mean\", \"sum\"],\n    \"category_1\":      [\"mean\"],\n    \"category_2\":      [\"mean\", \"nunique\"],\n    \"category_3\":      [\"mean\", \"nunique\"],\n    \"month\":           [\"nunique\", \"median\"],\n    \"weekend\":         [\"mean\"],\n    \"hour\":            [\"mean\", \"std\", \"skew\"],\n    \"day\":             [\"mean\", \"std\"],\n    \"dayofweek\":       [\"mean\", \"nunique\"],\n    \"purchase_date\":   [\"count\"]\n}\n\n# 集約処理\nagg_new = new_trans.groupby(\"card_id\").agg(agg_funcs)\n\n# 列名を平坦化\nagg_new.columns = [f\"new_{col}_{stat}\" for col, stat in agg_new.columns.to_flat_index()]\nagg_new = agg_new.reset_index()\n\n# 結合\ntrain_x = train_x.merge(agg_new, on=\"card_id\", how=\"left\")\ntest_x  = test_x.merge(agg_new, on=\"card_id\", how=\"left\")\n\n# 欠損値処理\ntrain_x = train_x.fillna(-1)\ntest_x  = test_x.fillna(-1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-30T14:46:37.480002Z","iopub.execute_input":"2025-06-30T14:46:37.480247Z","iopub.status.idle":"2025-06-30T14:46:52.394750Z","shell.execute_reply.started":"2025-06-30T14:46:37.480229Z","shell.execute_reply":"2025-06-30T14:46:52.393842Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ----------------------------------------------\n# historical_transactions の特徴量作成\n# ----------------------------------------------\n\n# 読み込み\nhist_trans = pd.read_csv(f\"{DATA_DIR}/historical_transactions.csv\")\n\n# 前処理\nhist_trans[\"authorized_flag\"] = hist_trans[\"authorized_flag\"].map({\"Y\": 1, \"N\": 0})\nhist_trans[\"category_1\"] = hist_trans[\"category_1\"].map({\"Y\": 1, \"N\": 0})\nhist_trans[\"category_3\"] = hist_trans[\"category_3\"].map({'A': 0, 'B': 1, 'C': 2})\nhist_trans[\"purchase_date\"] = pd.to_datetime(hist_trans[\"purchase_date\"])\nhist_trans[\"month\"] = hist_trans[\"purchase_date\"].dt.month\nhist_trans[\"weekend\"] = (hist_trans[\"purchase_date\"].dt.weekday >= 5).astype(int)\nhist_trans[\"hour\"] = hist_trans[\"purchase_date\"].dt.hour\nhist_trans[\"day\"] = hist_trans[\"purchase_date\"].dt.day\nhist_trans[\"dayofweek\"] = hist_trans[\"purchase_date\"].dt.dayofweek\n\n# ★ 重要：不正取引を除外（モデルに悪影響の場合あり）\nhist_trans = hist_trans[hist_trans[\"authorized_flag\"] == 1]\n\n# 集約関数の設定\nagg_funcs = {\n    \"purchase_amount\": [\"min\", \"max\", \"mean\", \"std\", \"skew\", \"median\", \"sum\"],\n    \"installments\":    [\"min\", \"max\", \"mean\", \"std\", \"nunique\", \"median\"],\n    \"month_lag\":       [\"min\", \"max\", \"mean\", \"std\", \"skew\"],\n    \"authorized_flag\": [\"mean\", \"sum\"],\n    \"category_1\":      [\"mean\"],\n    \"category_2\":      [\"mean\", \"nunique\"],\n    \"category_3\":      [\"mean\", \"nunique\"],\n    \"month\":           [\"nunique\", \"median\"],\n    \"weekend\":         [\"mean\"],\n    \"hour\":            [\"mean\", \"std\", \"skew\"],\n    \"day\":             [\"mean\", \"std\"],\n    \"dayofweek\":       [\"mean\", \"nunique\"],\n    \"purchase_date\":   [\"count\"]\n}\n\n# 集約\nagg_hist = hist_trans.groupby(\"card_id\").agg(agg_funcs)\n\n# 列名を平坦化\nagg_hist.columns = [f\"hist_{col}_{stat}\" for col, stat in agg_hist.columns.to_flat_index()]\nagg_hist = agg_hist.reset_index()\n\n# メインテーブルへ結合\ntrain_x = train_x.merge(agg_hist, on=\"card_id\", how=\"left\")\ntest_x  = test_x.merge(agg_hist, on=\"card_id\", how=\"left\")\n\n# 欠損値補完\ntrain_x = train_x.fillna(-1)\ntest_x  = test_x.fillna(-1)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-30T14:46:52.395707Z","iopub.execute_input":"2025-06-30T14:46:52.395994Z","iopub.status.idle":"2025-06-30T14:48:50.534872Z","shell.execute_reply.started":"2025-06-30T14:46:52.395966Z","shell.execute_reply":"2025-06-30T14:48:50.534003Z"}},"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-30T14:48:50.536033Z","iopub.execute_input":"2025-06-30T14:48:50.536373Z","iopub.status.idle":"2025-06-30T14:48:50.603706Z","shell.execute_reply.started":"2025-06-30T14:48:50.536343Z","shell.execute_reply":"2025-06-30T14:48:50.602426Z"}},"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-30T14:48:50.604975Z","iopub.execute_input":"2025-06-30T14:48:50.605305Z","iopub.status.idle":"2025-06-30T14:49:09.407448Z","shell.execute_reply.started":"2025-06-30T14:48:50.605277Z","shell.execute_reply":"2025-06-30T14:49:09.406304Z"}},"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-30T14:49:09.408561Z","iopub.execute_input":"2025-06-30T14:49:09.408880Z","iopub.status.idle":"2025-06-30T14:49:14.958573Z","shell.execute_reply.started":"2025-06-30T14:49:09.408855Z","shell.execute_reply":"2025-06-30T14:49:14.957531Z"}},"outputs":[],"execution_count":null}]}