{"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-30T13:03:15.651460Z","iopub.execute_input":"2025-06-30T13:03:15.651967Z","iopub.status.idle":"2025-06-30T13:03:15.656686Z","shell.execute_reply.started":"2025-06-30T13:03:15.651935Z","shell.execute_reply":"2025-06-30T13:03:15.655695Z"}},"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-30T13:03:15.658173Z","iopub.execute_input":"2025-06-30T13:03:15.658469Z","iopub.status.idle":"2025-06-30T13:03:16.202474Z","shell.execute_reply.started":"2025-06-30T13:03:15.658447Z","shell.execute_reply":"2025-06-30T13:03:16.201555Z"}},"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-30T13:03:16.203364Z","iopub.execute_input":"2025-06-30T13:03:16.203668Z","iopub.status.idle":"2025-06-30T13:03:16.352572Z","shell.execute_reply.started":"2025-06-30T13:03:16.203640Z","shell.execute_reply":"2025-06-30T13:03:16.351557Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ----------------------------------------------\n# メインテーブルの特徴量作成\n#  + 取引テーブル(historical/new)集約特徴の追加\n# ----------------------------------------------\nimport numpy as np, gc, warnings\nwarnings.filterwarnings(\"ignore\")\n\n# ---- 1) メインテーブル: first_active_month を数値化 ----\ntrain_x = train.copy().drop(columns=[\"target\"])\ntest_x  = test.copy()\n\nfor df in (train_x, test_x):\n    df[\"first_active_month\"] = df[\"first_active_month\"].fillna(\"Unknown\")\n\nle = LabelEncoder().fit(\n    pd.concat([train_x[\"first_active_month\"], test_x[\"first_active_month\"]])\n)\ntrain_x[\"fam_label\"] = le.transform(train_x[\"first_active_month\"])\ntest_x [\"fam_label\"] = le.transform(test_x[\"first_active_month\"])\n\ntrain_x.drop(columns=[\"first_active_month\"], inplace=True)\ntest_x .drop(columns=[\"first_active_month\"], inplace=True)\n\n# ---- 2) 取引テーブルを読み込み ----\nusecols = [\n    \"card_id\", \"authorized_flag\",\n    \"category_1\", \"category_2\", \"category_3\",\n    \"city_id\", \"state_id\", \"subsector_id\",\n    \"merchant_id\", \"merchant_category_id\",\n    \"purchase_amount\", \"installments\", \"month_lag\",\n    \"purchase_date\"\n]\n\nhist = pd.read_csv(f\"{DATA_DIR}/historical_transactions.csv\",\n                   usecols=usecols, parse_dates=[\"purchase_date\"])\nnew  = pd.read_csv(f\"{DATA_DIR}/new_merchant_transactions.csv\",\n                   usecols=usecols, parse_dates=[\"purchase_date\"])\n\n# ---- 3) 簡易前処理（型変換と欠損補完）----\nfor df in (hist, new):\n    df[\"authorized_flag\"] = (df[\"authorized_flag\"] == \"Y\").astype(np.int8)\n    df[\"category_1\"]      = (df[\"category_1\"]      == \"Y\").astype(np.int8)\n    df[\"purchase_dt\"]     = df[\"purchase_date\"].astype(np.int64) // 10**9          # Unix 秒\n    df[\"category_2\"]      = df[\"category_2\"].fillna(-1).astype(np.int8)\n    df[\"category_3\"]      = df[\"category_3\"].map({\"A\":0, \"B\":1, \"C\":2}).fillna(-1).astype(np.int8)\n    df[\"installments\"]    = df[\"installments\"].replace(-1, 0).astype(np.int16)\n\n# ---- 4) 集約関数定義（min/max/count 以外も追加）----\ndef range_ptp(x): return x.max() - x.min()\ndef q25(x): return x.quantile(0.25)\ndef q75(x): return x.quantile(0.75)\n\nagg_dict = {\n    \"purchase_amount\":  [\"min\",\"max\",\"mean\",\"sum\",\"std\",range_ptp,q25,q75],\n    \"installments\":     [\"min\",\"max\",\"mean\",\"sum\",\"std\"],\n    \"month_lag\":        [\"min\",\"max\",\"mean\",\"std\"],\n    \"purchase_dt\":      [\"min\",\"max\",range_ptp],\n    \"authorized_flag\":  [\"mean\"],\n    \"category_1\":       [\"mean\"],\n    \"category_2\":       [\"nunique\"],\n    \"category_3\":       [\"nunique\"],\n    \"merchant_id\":      [\"nunique\"],\n    \"merchant_category_id\":[\"nunique\"],\n    \"city_id\":          [\"nunique\"],\n    \"state_id\":         [\"nunique\"],\n    \"subsector_id\":     [\"nunique\"],\n    \"purchase_date\":    [\"count\"],\n}\n\ndef make_agg(df, prefix):\n    agg = df.groupby(\"card_id\").agg(agg_dict)\n    # 列名を prefix_元変数_統計量 へ平坦化\n    agg.columns = [\n        f\"{prefix}_{c[0]}_{(c[1] if isinstance(c[1], str) else c[1].__name__)}\"\n        for c in agg.columns.to_flat_index()\n    ]\n    return agg.reset_index()\n\nhist_agg = make_agg(hist, \"hist\")\nnew_agg  = make_agg(new,  \"new\")\n\ndel hist, new\ngc.collect()\n\n# ---- 5) メインテーブルと結合 ----\ntrain_x = train_x.merge(hist_agg, on=\"card_id\", how=\"left\")\ntrain_x = train_x.merge(new_agg,  on=\"card_id\", how=\"left\")\ntest_x  = test_x .merge(hist_agg, on=\"card_id\", how=\"left\")\ntest_x  = test_x .merge(new_agg,  on=\"card_id\", how=\"left\")\n\n# 欠損は -1 で埋める\nfor df in (train_x, test_x):\n    df.fillna(-1, inplace=True)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-30T13:03:16.354413Z","iopub.execute_input":"2025-06-30T13:03:16.354672Z"}},"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},"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},"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},"outputs":[],"execution_count":null}]}