{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"competition","sourceId":10445,"databundleVersionId":200747}],"dockerImageVersionId":31286,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:22:06.077429Z","iopub.execute_input":"2026-03-12T12:22:06.078145Z","iopub.status.idle":"2026-03-12T12:22:06.087259Z","shell.execute_reply.started":"2026-03-12T12:22:06.078110Z","shell.execute_reply":"2026-03-12T12:22:06.085880Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport gc\nimport time\nimport datetime\n\n\nfrom sklearn.model_selection import KFold\nfrom sklearn.metrics import mean_squared_error\nimport lightgbm as lgb","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:22:06.089055Z","iopub.execute_input":"2026-03-12T12:22:06.089976Z","iopub.status.idle":"2026-03-12T12:22:06.108568Z","shell.execute_reply.started":"2026-03-12T12:22:06.089948Z","shell.execute_reply":"2026-03-12T12:22:06.107127Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# reduce memory usage\ndef reduce_mem_usage(df):\n    \n    start_mem = df.memory_usage().sum() / 1024**2\n    \n    for col in df.columns:\n        \n        col_type = df[col].dtype\n        \n        if col_type != object:\n            \n            c_min = df[col].min()\n            c_max = df[col].max()\n            \n            if str(col_type)[:3] == 'int':\n                \n                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n                    df[col] = df[col].astype(np.int8)\n                    \n                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n                    df[col] = df[col].astype(np.int16)\n                    \n                elif c_min > np.iinfo(np.int32).min:\n                    df[col] = df[col].astype(np.int32)\n            \n            else:\n                \n                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:\n                    df[col] = df[col].astype(np.float16)\n                    \n                elif c_min > np.finfo(np.float32).min:\n                    df[col] = df[col].astype(np.float32)\n\n    end_mem = df.memory_usage().sum() / 1024**2\n    \n    print('Mem usage reduced from {:.2f} MB to {:.2f} MB'.format(start_mem,end_mem))\n    \n    return df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:22:06.109833Z","iopub.execute_input":"2026-03-12T12:22:06.110268Z","iopub.status.idle":"2026-03-12T12:22:06.128582Z","shell.execute_reply.started":"2026-03-12T12:22:06.110232Z","shell.execute_reply":"2026-03-12T12:22:06.127143Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 讀資料\ntrain = pd.read_csv(\"/kaggle/input/competitions/elo-merchant-category-recommendation/train.csv\")\ntest = pd.read_csv(\"/kaggle/input/competitions/elo-merchant-category-recommendation/test.csv\")\n\ntrain = reduce_mem_usage(train)\ntest = reduce_mem_usage(test)\n\n# 合併 card_id\ncard_all = pd.concat([train['card_id'], test['card_id']]).unique()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:22:06.130722Z","iopub.execute_input":"2026-03-12T12:22:06.131171Z","iopub.status.idle":"2026-03-12T12:22:06.683687Z","shell.execute_reply.started":"2026-03-12T12:22:06.131144Z","shell.execute_reply":"2026-03-12T12:22:06.682159Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"hist = pd.read_csv('/kaggle/input/competitions/elo-merchant-category-recommendation/historical_transactions.csv')\nnew = pd.read_csv('/kaggle/input/competitions/elo-merchant-category-recommendation/new_merchant_transactions.csv')\n\nhist = reduce_mem_usage(hist)\nnew = reduce_mem_usage(new)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:22:06.684928Z","iopub.execute_input":"2026-03-12T12:22:06.685168Z","iopub.status.idle":"2026-03-12T12:23:36.392275Z","shell.execute_reply.started":"2026-03-12T12:22:06.685145Z","shell.execute_reply":"2026-03-12T12:23:36.391111Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Card Features\nfor df in [train,test]:\n\n    df[\"first_active_month\"] = pd.to_datetime(df[\"first_active_month\"])\n\n    df[\"fam_year\"] = df[\"first_active_month\"].dt.year\n    df[\"fam_month\"] = df[\"first_active_month\"].dt.month\n\n    df[\"fam_elapsed_time\"] = (\n        datetime.datetime.today() - df[\"first_active_month\"]\n    ).dt.days\n\n    df[\"feature_sum\"] = df[\"feature_1\"] + df[\"feature_2\"] + df[\"feature_3\"]\n    \n    df[\"feature_mean\"] = df[\"feature_sum\"] / 3","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:23:36.394051Z","iopub.execute_input":"2026-03-12T12:23:36.394445Z","iopub.status.idle":"2026-03-12T12:23:36.518049Z","shell.execute_reply.started":"2026-03-12T12:23:36.394407Z","shell.execute_reply":"2026-03-12T12:23:36.516742Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Transaction Preprocessing\ndef preprocess_transaction(df):\n\n    #impute missing values - This is now excluded.\n    df['category_2'] = df['category_2'].fillna(1.0,inplace=True)\n    df['category_3'] = df['category_3'].fillna('A',inplace=True)\n    df['merchant_id'] = df['merchant_id'].fillna('M_ID_00a6ca8a8a',inplace=True)\n\n    df[\"purchase_date\"] = pd.to_datetime(df[\"purchase_date\"])\n\n    df[\"month\"] = df[\"purchase_date\"].dt.month\n    df[\"hour\"] = df[\"purchase_date\"].dt.hour\n    df[\"weekday\"] = df[\"purchase_date\"].dt.weekday\n\n    df[\"weekend\"] = (df[\"weekday\"] >= 5).astype(int)\n    df['weekofyear'] = df['purchase_date'].dt.isocalendar().week.astype(int)\n    \n    df[\"month_diff\"] = (\n        (datetime.datetime.today() - df[\"purchase_date\"]).dt.days // 30\n    )\n\n    df[\"duration\"] = df[\"purchase_amount\"] * df[\"month_diff\"]\n\n    df[\"price\"] = df[\"purchase_amount\"] / (df[\"installments\"] + 1)\n\n    df[\"amount_month_ratio\"] = (\n        df[\"purchase_amount\"] / (df[\"month_diff\"] + 1)\n    )\n    df['merchant_freq'] = df.groupby('merchant_id')['card_id'].transform('count')\n\n    df['city_freq'] = df.groupby('city_id')['card_id'].transform('count')\n    \n    df[\"authorized_flag\"] = df[\"authorized_flag\"].map({\"Y\":1,\"N\":0})\n    df[\"category_1\"] = df[\"category_1\"].map({\"Y\":1,\"N\":0})\n    df['category_3'] = df['category_3'].map({\n        'A':0,\n        'B':1,\n        'C':2\n    })\n\n    return df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:23:36.520802Z","iopub.execute_input":"2026-03-12T12:23:36.521281Z","iopub.status.idle":"2026-03-12T12:23:36.534224Z","shell.execute_reply.started":"2026-03-12T12:23:36.521249Z","shell.execute_reply":"2026-03-12T12:23:36.532668Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"hist = preprocess_transaction(hist)\nnew = preprocess_transaction(new)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:23:36.536174Z","iopub.execute_input":"2026-03-12T12:23:36.536780Z","iopub.status.idle":"2026-03-12T12:24:10.931770Z","shell.execute_reply.started":"2026-03-12T12:23:36.536736Z","shell.execute_reply":"2026-03-12T12:24:10.929954Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def transaction_agg(df,prefix):\n\n    agg_func = {\n\n        \"purchase_amount\":[\n            \"sum\",\"mean\",\"max\",\"min\",\"std\"\n        ],\n\n        \"installments\":[\n            \"sum\",\"mean\",\"max\",\"std\"\n        ],\n\n        \"month_diff\":[\n            \"mean\",\"max\",\"min\",\"std\"\n        ],\n\n        \"duration\":[\n            \"mean\",\"sum\",\"std\"\n        ],\n\n        \"price\":[\n            \"mean\",\"max\",\"std\"\n        ],\n\n        \"amount_month_ratio\":[\n            \"mean\",\"std\"\n        ],\n\n        \"authorized_flag\":[\n            \"mean\",\"sum\"\n        ],\n\n        \"category_1\":[\n            \"mean\"\n        ],\n\n        \"merchant_id\":[\n            \"nunique\"\n        ],\n\n        \"merchant_category_id\":[\n            \"nunique\"\n        ],\n\n        \"subsector_id\":[\n            \"nunique\"\n        ],\n\n        \"month\":[\n            \"nunique\"\n        ],\n\n        \"hour\":[\n            \"mean\",\"std\"\n        ],\n\n        \"weekend\":[\n            \"mean\"\n        ]\n    }\n\n    agg = df.groupby(\"card_id\").agg(agg_func)\n\n    agg.columns = [\n        prefix + \"_\" + \"_\".join(col) for col in agg.columns\n    ]\n\n    agg.reset_index(inplace=True)\n\n    return agg","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:24:10.933469Z","iopub.execute_input":"2026-03-12T12:24:10.934026Z","iopub.status.idle":"2026-03-12T12:24:10.943730Z","shell.execute_reply.started":"2026-03-12T12:24:10.933963Z","shell.execute_reply":"2026-03-12T12:24:10.942483Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Generate Aggregated Features\nhist_agg = transaction_agg(hist,\"hist\")\nnew_agg = transaction_agg(new,\"new\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:24:10.946039Z","iopub.execute_input":"2026-03-12T12:24:10.946525Z","iopub.status.idle":"2026-03-12T12:24:34.184664Z","shell.execute_reply.started":"2026-03-12T12:24:10.946493Z","shell.execute_reply":"2026-03-12T12:24:34.183354Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = train.merge(hist_agg,on=\"card_id\",how=\"left\")\ntrain = train.merge(new_agg,on=\"card_id\",how=\"left\")\n\ntest = test.merge(hist_agg,on=\"card_id\",how=\"left\")\ntest = test.merge(new_agg,on=\"card_id\",how=\"left\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:24:34.186040Z","iopub.execute_input":"2026-03-12T12:24:34.186545Z","iopub.status.idle":"2026-03-12T12:24:35.617132Z","shell.execute_reply.started":"2026-03-12T12:24:34.186504Z","shell.execute_reply":"2026-03-12T12:24:35.616109Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Additional Interaction Features\nfor df in [train,test]:\n\n    df[\"purchase_ratio\"] = (\n        df[\"hist_purchase_amount_sum\"] /\n        (df[\"new_purchase_amount_sum\"] + 1)\n    )\n\n    df[\"merchant_ratio\"] = (\n        df[\"hist_merchant_id_nunique\"] /\n        (df[\"new_merchant_id_nunique\"] + 1)\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:24:35.618562Z","iopub.execute_input":"2026-03-12T12:24:35.618900Z","iopub.status.idle":"2026-03-12T12:24:35.635822Z","shell.execute_reply.started":"2026-03-12T12:24:35.618871Z","shell.execute_reply":"2026-03-12T12:24:35.634697Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Prepare Training Data\ntarget = train[\"target\"]\n\nfeatures = [\n    c for c in train.columns\n    if c not in [\"target\",\"card_id\",\"first_active_month\"]\n]\n\nX = train[features].copy()\nX_test = test[features].copy()\ny = target","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:24:35.637583Z","iopub.execute_input":"2026-03-12T12:24:35.638053Z","iopub.status.idle":"2026-03-12T12:24:35.801490Z","shell.execute_reply.started":"2026-03-12T12:24:35.638023Z","shell.execute_reply":"2026-03-12T12:24:35.800069Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"params = {\n\n'objective':'regression',\n'metric':'rmse',\n'learning_rate':0.01,\n'num_leaves':50,\n'feature_fraction':0.8,\n'bagging_fraction':0.8,\n'bagging_freq':5,\n'seed':42\n}\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:24:35.803112Z","iopub.execute_input":"2026-03-12T12:24:35.803532Z","iopub.status.idle":"2026-03-12T12:24:35.809433Z","shell.execute_reply.started":"2026-03-12T12:24:35.803490Z","shell.execute_reply":"2026-03-12T12:24:35.808256Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\nfor col in X.columns:\n    if X[col].dtype == \"float64\":\n        X[col] = X[col].astype(\"float32\")\n        X_test[col] = X_test[col].astype(\"float32\")\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:24:35.814260Z","iopub.execute_input":"2026-03-12T12:24:35.814674Z","iopub.status.idle":"2026-03-12T12:24:35.833886Z","shell.execute_reply.started":"2026-03-12T12:24:35.814638Z","shell.execute_reply":"2026-03-12T12:24:35.832747Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"     \nprint(X.dtypes.value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:24:35.834998Z","iopub.execute_input":"2026-03-12T12:24:35.835425Z","iopub.status.idle":"2026-03-12T12:24:35.853278Z","shell.execute_reply.started":"2026-03-12T12:24:35.835398Z","shell.execute_reply":"2026-03-12T12:24:35.852084Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# LightGBM\n\n\nfolds = KFold(n_splits=5, shuffle=True, random_state=42)\n\noof = np.zeros(len(X))\npredictions = np.zeros(len(X_test))\n\nfor fold,(trn_idx,val_idx) in enumerate(folds.split(X)):\n\n    print(\"Fold\", fold)\n\n    X_train = X.iloc[trn_idx]\n    y_train = y.iloc[trn_idx]\n\n    X_val = X.iloc[val_idx]\n    y_val = y.iloc[val_idx]\n\n    train_data = lgb.Dataset(X_train, label=y_train)\n    val_data = lgb.Dataset(X_val, label=y_val)\n\n    model = lgb.train(\n        params,\n        train_data,\n        num_boost_round=10000,\n        valid_sets=[train_data, val_data],\n        valid_names=[\"train\",\"valid\"],\n        callbacks=[\n            lgb.early_stopping(200),\n            lgb.log_evaluation(200)\n        ]\n    )\n\n    oof[val_idx] = model.predict(X_val)\n    predictions += model.predict(X_test) / folds.n_splits\n\nfrom sklearn.metrics import mean_squared_error\nimport numpy as np\n\nrmse = np.sqrt(mean_squared_error(y, oof))\nprint(\"CV RMSE:\", rmse)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:24:35.854619Z","iopub.execute_input":"2026-03-12T12:24:35.855043Z","iopub.status.idle":"2026-03-12T12:27:48.312715Z","shell.execute_reply.started":"2026-03-12T12:24:35.855005Z","shell.execute_reply":"2026-03-12T12:27:48.311389Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"importance_df = pd.DataFrame()\n\nfor fold,(trn_idx,val_idx) in enumerate(folds.split(X)):\n\n\n    fold_importance = pd.DataFrame()\n    fold_importance[\"feature\"] = X.columns\n    fold_importance[\"importance\"] = model.feature_importance(importance_type=\"gain\")\n    fold_importance[\"fold\"] = fold\n\n    importance_df = pd.concat([importance_df, fold_importance])\n\nimportance = importance_df.groupby(\"feature\")[\"importance\"].mean().reset_index()\n\nimportance = importance.sort_values(\"importance\", ascending=False)\n\nimportance.head(30)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:48.314213Z","iopub.execute_input":"2026-03-12T12:27:48.314478Z","iopub.status.idle":"2026-03-12T12:27:48.360196Z","shell.execute_reply.started":"2026-03-12T12:27:48.314452Z","shell.execute_reply":"2026-03-12T12:27:48.359208Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nlgb.plot_importance(model, max_num_features=30)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:48.361368Z","iopub.execute_input":"2026-03-12T12:27:48.361681Z","iopub.status.idle":"2026-03-12T12:27:48.735304Z","shell.execute_reply.started":"2026-03-12T12:27:48.361656Z","shell.execute_reply":"2026-03-12T12:27:48.734205Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# Transaction Time Window Features\ndef time_window_features(df, prefix, windows=[3,6,12]):\n    df[\"month_diff\"] = (datetime.datetime.today() - df[\"purchase_date\"]).dt.days // 30\n    feats = []\n    \n    for w in windows:\n        tmp = df[df[\"month_diff\"] <= w].copy()\n        agg = tmp.groupby(\"card_id\")[\"purchase_amount\"].agg([\"sum\",\"mean\",\"std\"]).reset_index()\n        agg.columns = [\"card_id\"] + [f\"{prefix}_purchase_amount_{w}m_{c}\" for c in [\"sum\",\"mean\",\"std\"]]\n        feats.append(agg)\n        \n    # merge all\n    from functools import reduce\n    out = reduce(lambda left,right: pd.merge(left,right,on=\"card_id\",how=\"left\"), feats)\n    return out\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:48.736793Z","iopub.execute_input":"2026-03-12T12:27:48.737227Z","iopub.status.idle":"2026-03-12T12:27:48.745534Z","shell.execute_reply.started":"2026-03-12T12:27:48.737139Z","shell.execute_reply":"2026-03-12T12:27:48.744496Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nhist_time = time_window_features(hist,\"hist\")\nnew_time = time_window_features(new,\"new\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:48.746922Z","iopub.execute_input":"2026-03-12T12:27:48.747308Z","iopub.status.idle":"2026-03-12T12:27:50.117208Z","shell.execute_reply.started":"2026-03-12T12:27:48.747267Z","shell.execute_reply":"2026-03-12T12:27:50.116140Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\ntrain = train.merge(hist_time,on=\"card_id\",how=\"left\")\ntrain = train.merge(new_time,on=\"card_id\",how=\"left\")\n\ntest = test.merge(hist_time,on=\"card_id\",how=\"left\")\ntest = test.merge(new_time,on=\"card_id\",how=\"left\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:50.118628Z","iopub.execute_input":"2026-03-12T12:27:50.118905Z","iopub.status.idle":"2026-03-12T12:27:50.404483Z","shell.execute_reply.started":"2026-03-12T12:27:50.118881Z","shell.execute_reply":"2026-03-12T12:27:50.403552Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\n# Merchant / Category Target Encoding\nfrom sklearn.model_selection import KFold\n\ndef kfold_target_encoding(train, test, col, target, n_splits=5):\n\n    kf = KFold(n_splits=n_splits, shuffle=True, random_state=42)\n\n    train[f\"{col}_te\"] = np.nan\n\n    for tr_idx, val_idx in kf.split(train):\n\n        tr, val = train.iloc[tr_idx], train.iloc[val_idx]\n\n        means = tr.groupby(col)[target].mean().astype(\"float32\")\n\n        train.loc[val_idx, f\"{col}_te\"] = val[col].map(means)\n\n    global_mean = train[target].mean().astype(\"float32\")\n\n    train[f\"{col}_te\"] = train[f\"{col}_te\"].fillna(global_mean)\n\n    # test\n    means = train.groupby(col)[target].mean().astype(\"float32\")\n\n    test[f\"{col}_te\"] = test[col].map(means)\n\n    test[f\"{col}_te\"] = test[f\"{col}_te\"].fillna(global_mean)\n    \n    return train, test\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:50.405585Z","iopub.execute_input":"2026-03-12T12:27:50.406011Z","iopub.status.idle":"2026-03-12T12:27:50.412838Z","shell.execute_reply.started":"2026-03-12T12:27:50.405967Z","shell.execute_reply":"2026-03-12T12:27:50.411853Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\ntransaction = pd.concat([hist, new], axis=0)\n\ncat_cols = [\n\"merchant_category_id\",\n\"subsector_id\",\n\"category_1\",\n\"category_2\",\n\"category_3\"\n]\n\nagg_dict = {}\n\nfor col in cat_cols:\n    agg_dict[col] = [\"nunique\"]\n\ncard_cat = transaction.groupby(\"card_id\").agg(agg_dict)\ncard_cat.columns = [\"_\".join(col) for col in card_cat.columns]\ncard_cat = card_cat.reset_index()\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:50.413955Z","iopub.execute_input":"2026-03-12T12:27:50.414238Z","iopub.status.idle":"2026-03-12T12:27:50.434248Z","shell.execute_reply.started":"2026-03-12T12:27:50.414157Z","shell.execute_reply":"2026-03-12T12:27:50.432965Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\ntrain = train.merge(card_cat, on=\"card_id\", how=\"left\")\ntest = test.merge(card_cat, on=\"card_id\", how=\"left\")\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:50.435645Z","iopub.execute_input":"2026-03-12T12:27:50.436389Z","iopub.status.idle":"2026-03-12T12:27:50.456844Z","shell.execute_reply.started":"2026-03-12T12:27:50.436332Z","shell.execute_reply":"2026-03-12T12:27:50.455917Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\ncat_cols = [\n\"merchant_category_id_nunique\",\n\"subsector_id_nunique\",\n\"category_1_nunique\",\n\"category_2_nunique\",\n\"category_3_nunique\"\n]\ntrain[\"target\"] = train[\"target\"].astype(\"float32\")\n\nfor col in cat_cols:\n    train, test = kfold_target_encoding(train, test, col, \"target\")\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:50.458105Z","iopub.execute_input":"2026-03-12T12:27:50.458479Z","iopub.status.idle":"2026-03-12T12:27:50.475566Z","shell.execute_reply.started":"2026-03-12T12:27:50.458443Z","shell.execute_reply":"2026-03-12T12:27:50.474466Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\n# Prepare Training Data\ntarget = train[\"target\"]\n\nfeatures = [\n    c for c in train.columns\n    if c not in [\"target\",\"card_id\",\"first_active_month\"]\n]\nX = train[features].copy()\nX_test = test[features].copy()\ny = target\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:50.476883Z","iopub.execute_input":"2026-03-12T12:27:50.477318Z","iopub.status.idle":"2026-03-12T12:27:50.494396Z","shell.execute_reply.started":"2026-03-12T12:27:50.477267Z","shell.execute_reply":"2026-03-12T12:27:50.493288Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\noutlier_threshold = -30\ntrain[\"outlier\"] = (train[\"target\"] < outlier_threshold).astype(int)\n\nfolds = KFold(n_splits=5, shuffle=True, random_state=42)\n\noof_outlier = np.zeros(len(train))\ntest_outlier = np.zeros(len(test))\n\nfor trn_idx, val_idx in folds.split(X):\n\n    X_train, X_val = X.iloc[trn_idx], X.iloc[val_idx]\n    y_train = train[\"outlier\"].iloc[trn_idx]\n\n    clf = lgb.LGBMClassifier(\n        n_estimators=500,\n        learning_rate=0.05,\n        num_leaves=31\n    )\n\n    clf.fit(X_train, y_train)\n\n    oof_outlier[val_idx] = clf.predict_proba(X_val)[:,1]\n\n    test_outlier += clf.predict_proba(X_test)[:,1] / folds.n_splits\n\ntrain[\"outlier_prob\"] = oof_outlier\ntest[\"outlier_prob\"] = test_outlier\n\nX[\"outlier_prob\"] = train[\"outlier_prob\"]\nX_test[\"outlier_prob\"] = test[\"outlier_prob\"]\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:50.563304Z","iopub.execute_input":"2026-03-12T12:27:50.564093Z","iopub.status.idle":"2026-03-12T12:27:50.570105Z","shell.execute_reply.started":"2026-03-12T12:27:50.564054Z","shell.execute_reply":"2026-03-12T12:27:50.569048Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\nimportance_threshold = 100\n\nlow_importance = importance[\n    importance[\"importance\"] < importance_threshold\n][\"feature\"].tolist()\n\nprint(\"Low importance features:\", len(low_importance))\n\nX = X.drop(low_importance, axis=1)\nX_test = X_test.drop(low_importance, axis=1)\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:50.495608Z","iopub.execute_input":"2026-03-12T12:27:50.496036Z","iopub.status.idle":"2026-03-12T12:27:50.561989Z","shell.execute_reply.started":"2026-03-12T12:27:50.495998Z","shell.execute_reply":"2026-03-12T12:27:50.560957Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"params = {'num_leaves': 31,\n         'min_data_in_leaf': 30, \n         'objective':'regression',\n         'max_depth': -1,\n         'learning_rate': 0.01,\n         \"boosting\": \"gbdt\",\n         \"feature_fraction\": 0.9,\n         \"bagging_freq\": 1,\n         \"bagging_fraction\": 0.9 ,\n         \"bagging_seed\": 11,\n         \"metric\": 'rmse',\n         \"lambda_l1\": 0.1,\n         \"verbosity\": -1,\n         \"nthread\": 4,\n         \"random_state\": 4590}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:50.571272Z","iopub.execute_input":"2026-03-12T12:27:50.571978Z","iopub.status.idle":"2026-03-12T12:27:50.592088Z","shell.execute_reply.started":"2026-03-12T12:27:50.571952Z","shell.execute_reply":"2026-03-12T12:27:50.591201Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# LightGBM\n\n\nfolds = KFold(n_splits=5, shuffle=True, random_state=42)\n\noof_lgb = np.zeros(len(X))\npred_lgb = np.zeros(len(X_test))\n\nfor fold,(trn_idx,val_idx) in enumerate(folds.split(X)):\n\n    print(\"Fold\", fold)\n\n    X_train = X.iloc[trn_idx]\n    y_train = y.iloc[trn_idx]\n\n    X_val = X.iloc[val_idx]\n    y_val = y.iloc[val_idx]\n\n    train_data = lgb.Dataset(X_train, label=y_train)\n    val_data = lgb.Dataset(X_val, label=y_val)\n\n    LightGBM_model = lgb.train(\n        params,\n        train_data,\n        num_boost_round=10000,\n        valid_sets=[train_data, val_data],\n        valid_names=[\"train\",\"valid\"],\n        callbacks=[\n            lgb.early_stopping(200),\n            lgb.log_evaluation(200)\n        ]\n    )\n\n    oof_lgb[val_idx] = LightGBM_model.predict(X_val)\n    pred_lgb += LightGBM_model.predict(X_test) / folds.n_splits\n\nfrom sklearn.metrics import mean_squared_error\nimport numpy as np\n\nrmse = np.sqrt(mean_squared_error(y, oof_lgb))\nprint(\"CV RMSE:\", rmse)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:27:50.593377Z","iopub.execute_input":"2026-03-12T12:27:50.593725Z","iopub.status.idle":"2026-03-12T12:32:34.508231Z","shell.execute_reply.started":"2026-03-12T12:27:50.593690Z","shell.execute_reply":"2026-03-12T12:32:34.506521Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"importance_df = pd.DataFrame()\n\nfor fold,(trn_idx,val_idx) in enumerate(folds.split(X)):\n\n\n    fold_importance = pd.DataFrame()\n    fold_importance[\"feature\"] = X.columns\n    fold_importance[\"importance\"] = LightGBM_model.feature_importance(importance_type=\"gain\")\n    fold_importance[\"fold\"] = fold\n\n    importance_df = pd.concat([importance_df, fold_importance])\n\nimportance = importance_df.groupby(\"feature\")[\"importance\"].mean().reset_index()\n\nimportance = importance.sort_values(\"importance\", ascending=False)\n\nimportance.head(30)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:32:34.510302Z","iopub.execute_input":"2026-03-12T12:32:34.510646Z","iopub.status.idle":"2026-03-12T12:32:34.586542Z","shell.execute_reply.started":"2026-03-12T12:32:34.510614Z","shell.execute_reply":"2026-03-12T12:32:34.585312Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nimportance_threshold = 100\n\nlow_importance = importance[\n    importance[\"importance\"] < importance_threshold\n][\"feature\"].tolist()\n\nprint(\"Low importance features:\", len(low_importance))\n\nX = X.drop(low_importance, axis=1)\nX_test = X_test.drop(low_importance, axis=1)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:32:34.588133Z","iopub.execute_input":"2026-03-12T12:32:34.589565Z","iopub.status.idle":"2026-03-12T12:32:34.675614Z","shell.execute_reply.started":"2026-03-12T12:32:34.589522Z","shell.execute_reply":"2026-03-12T12:32:34.673864Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# CatBoost\nfrom catboost import CatBoostRegressor, Pool\nparams = {\n    \"loss_function\":\"RMSE\",\n    \"eval_metric\":\"RMSE\",\n    \"learning_rate\":0.03,\n    \"depth\":8,\n    \"iterations\":20000,\n    \"l2_leaf_reg\":3,\n    \"random_seed\":42,\n    \"early_stopping_rounds\":200,\n    \"verbose\":200\n}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:32:34.677284Z","iopub.execute_input":"2026-03-12T12:32:34.677719Z","iopub.status.idle":"2026-03-12T12:32:34.685496Z","shell.execute_reply.started":"2026-03-12T12:32:34.677677Z","shell.execute_reply":"2026-03-12T12:32:34.684262Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"folds = KFold(n_splits=5, shuffle=True, random_state=42)\n\noof_cat = np.zeros(len(X))\npred_cat = np.zeros(len(X_test))\n\nfor fold,(trn_idx,val_idx) in enumerate(folds.split(X)):\n\n    print(\"Fold\", fold+1)\n\n    X_train = X.iloc[trn_idx]\n    y_train = y.iloc[trn_idx]\n\n    X_val = X.iloc[val_idx]\n    y_val = y.iloc[val_idx]\n\n    train_pool = Pool(X_train, y_train)\n    val_pool = Pool(X_val, y_val)\n\n    CatBoost_model = CatBoostRegressor(**params)\n\n    CatBoost_model.fit(\n        train_pool,\n        eval_set=val_pool,\n        use_best_model=True\n    )\n\n\n    oof_cat[val_idx] = CatBoost_model.predict(X_val)\n    pred_cat += CatBoost_model.predict(X_test) / folds.n_splits\n\nfrom sklearn.metrics import mean_squared_error\nimport numpy as np\n\nrmse = np.sqrt(mean_squared_error(y, oof_cat))\nprint(\"CV RMSE:\", rmse)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:32:34.687009Z","iopub.execute_input":"2026-03-12T12:32:34.687522Z","iopub.status.idle":"2026-03-12T12:38:04.232853Z","shell.execute_reply.started":"2026-03-12T12:32:34.687488Z","shell.execute_reply":"2026-03-12T12:38:04.231372Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"importance = pd.DataFrame()\n\nimportance[\"feature\"] = X.columns\nimportance[\"importance\"] = CatBoost_model.get_feature_importance()\n\nimportance = importance.sort_values(\"importance\", ascending=False)\n\nimportance.head(30)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:38:04.234591Z","iopub.execute_input":"2026-03-12T12:38:04.235647Z","iopub.status.idle":"2026-03-12T12:38:04.290535Z","shell.execute_reply.started":"2026-03-12T12:38:04.235611Z","shell.execute_reply":"2026-03-12T12:38:04.288875Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"'''\nimportance_threshold = 100\n\nlow_importance = importance[\n    importance[\"importance\"] < importance_threshold\n][\"feature\"].tolist()\n\nprint(\"Low importance features:\", len(low_importance))\n\nX = X.drop(low_importance, axis=1)\nX_test = X_test.drop(low_importance, axis=1)\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:38:04.292465Z","iopub.execute_input":"2026-03-12T12:38:04.292987Z","iopub.status.idle":"2026-03-12T12:38:04.300659Z","shell.execute_reply.started":"2026-03-12T12:38:04.292938Z","shell.execute_reply":"2026-03-12T12:38:04.299607Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nnp.isinf(X).sum().sum()\nnp.isinf(X_test).sum().sum()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:38:04.302115Z","iopub.execute_input":"2026-03-12T12:38:04.302575Z","iopub.status.idle":"2026-03-12T12:38:04.397990Z","shell.execute_reply.started":"2026-03-12T12:38:04.302513Z","shell.execute_reply":"2026-03-12T12:38:04.396822Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def clean_inf_nan(df):\n\n    df = df.replace([np.inf, -np.inf], np.nan)\n\n    for col in df.columns:\n        if df[col].isna().sum() > 0:\n            df[col] = df[col].fillna(df[col].median())\n\n    return df\n\nX = clean_inf_nan(X)\nX_test = clean_inf_nan(X_test)\nnp.isinf(X).sum().sum()\nnp.isinf(X_test).sum().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:38:04.404243Z","iopub.execute_input":"2026-03-12T12:38:04.404607Z","iopub.status.idle":"2026-03-12T12:38:05.160689Z","shell.execute_reply.started":"2026-03-12T12:38:04.404580Z","shell.execute_reply":"2026-03-12T12:38:05.159526Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"X shape:\", X.shape)\nprint(\"X_test shape:\", X_test.shape)\nprint(\"Feature count:\", X.shape[1])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:38:05.162457Z","iopub.execute_input":"2026-03-12T12:38:05.163759Z","iopub.status.idle":"2026-03-12T12:38:05.171290Z","shell.execute_reply.started":"2026-03-12T12:38:05.163707Z","shell.execute_reply":"2026-03-12T12:38:05.169145Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# XGBoost \nimport xgboost as xgb\n\nparams = {\n    \"objective\":\"reg:squarederror\",\n    \"eval_metric\":\"rmse\",\n    \"learning_rate\":0.02,\n    \"max_depth\":8,\n    \"subsample\":0.8,\n    \"colsample_bytree\":0.8,\n    \"lambda\":1,\n    \"alpha\":0,\n    \"tree_method\":\"hist\",\n    \"seed\":42\n}\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:38:05.173508Z","iopub.execute_input":"2026-03-12T12:38:05.174234Z","iopub.status.idle":"2026-03-12T12:38:05.210416Z","shell.execute_reply.started":"2026-03-12T12:38:05.174142Z","shell.execute_reply":"2026-03-12T12:38:05.209336Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"folds = KFold(n_splits=5, shuffle=True, random_state=42)\n\noof_xgb = np.zeros(len(X))\npred_xgb = np.zeros(len(X_test))\n\nfor fold,(trn_idx,val_idx) in enumerate(folds.split(X)):\n\n    print(\"Fold\", fold+1)\n\n    X_train = X.iloc[trn_idx]\n    y_train = y.iloc[trn_idx]\n\n    X_val = X.iloc[val_idx]\n    y_val = y.iloc[val_idx]\n\n    dtrain = xgb.DMatrix(X_train, label=y_train)\n    dval = xgb.DMatrix(X_val, label=y_val)\n    dtest = xgb.DMatrix(X_test)\n\n    XGBoost_model = xgb.train(\n        params,\n        dtrain,\n        num_boost_round=10000,\n        evals=[(dtrain,\"train\"),(dval,\"valid\")],\n        early_stopping_rounds=200,\n        verbose_eval=200\n    )\n\n    oof_xgb[val_idx] = XGBoost_model.predict(dval)\n    pred_xgb += XGBoost_model.predict(dtest) / folds.n_splits\n    \nrmse = np.sqrt(mean_squared_error(y, oof_xgb))\nprint(\"CV RMSE:\", rmse)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:38:05.211755Z","iopub.execute_input":"2026-03-12T12:38:05.212130Z","iopub.status.idle":"2026-03-12T12:40:05.618017Z","shell.execute_reply.started":"2026-03-12T12:38:05.212092Z","shell.execute_reply":"2026-03-12T12:40:05.616967Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"importance_dict = XGBoost_model.get_score(importance_type=\"gain\")\nimportance = pd.DataFrame({\n    \"feature\": list(importance_dict.keys()),\n    \"importance\": list(importance_dict.values())\n})\n\n\nimportance = importance.sort_values(\"importance\", ascending=False)\nimportance.head(20)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:40:05.619207Z","iopub.execute_input":"2026-03-12T12:40:05.619878Z","iopub.status.idle":"2026-03-12T12:40:05.639075Z","shell.execute_reply.started":"2026-03-12T12:40:05.619844Z","shell.execute_reply":"2026-03-12T12:40:05.638141Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# stack","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:40:05.640379Z","iopub.execute_input":"2026-03-12T12:40:05.640851Z","iopub.status.idle":"2026-03-12T12:40:05.645097Z","shell.execute_reply.started":"2026-03-12T12:40:05.640821Z","shell.execute_reply":"2026-03-12T12:40:05.644109Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"stack_train = pd.DataFrame({\n    \"lgb\": oof_lgb,\n    \"xgb\": oof_xgb,\n    \"cat\": oof_cat\n})\n\nstack_test = pd.DataFrame({\n    \"lgb\": pred_lgb,\n    \"xgb\": pred_xgb,\n    \"cat\": pred_cat\n})","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:40:05.646311Z","iopub.execute_input":"2026-03-12T12:40:05.646685Z","iopub.status.idle":"2026-03-12T12:40:05.665976Z","shell.execute_reply.started":"2026-03-12T12:40:05.646651Z","shell.execute_reply":"2026-03-12T12:40:05.665006Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"stack_oof = np.zeros(len(X))\nstack_pred = np.zeros(len(X_test))\n\nfor fold, (tr_idx, val_idx) in enumerate(folds.split(stack_train)):\n    X_tr, X_val = stack_train.iloc[tr_idx], stack_train.iloc[val_idx]\n    y_tr, y_val = y.iloc[tr_idx], y.iloc[val_idx]\n\n    model = lgb.LGBMRegressor(\n        n_estimators=10000,\n        learning_rate=0.01\n    )\n    \n    model.fit(\n    X_tr, y_tr,\n    eval_set=[(X_val, y_val)],\n    callbacks=[\n        lgb.early_stopping(200),\n        lgb.log_evaluation(200)\n    ]\n    )\n\n    stack_oof[val_idx] = model.predict(X_val)\n    stack_pred += model.predict(stack_test) / folds.n_splits\n\nfrom sklearn.metrics import mean_squared_error\nrmse = np.sqrt(mean_squared_error(y, stack_oof))\nprint(\"Stacked CV RMSE:\", rmse)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:40:05.667229Z","iopub.execute_input":"2026-03-12T12:40:05.667625Z","iopub.status.idle":"2026-03-12T12:40:24.959643Z","shell.execute_reply.started":"2026-03-12T12:40:05.667589Z","shell.execute_reply":"2026-03-12T12:40:24.958759Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sub = pd.read_csv(\"/kaggle/input/competitions/elo-merchant-category-recommendation/sample_submission.csv\")\n\nsub[\"target\"] = stack_pred\n\nsub.to_csv(\"submission.csv\",index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-12T12:40:24.960779Z","iopub.execute_input":"2026-03-12T12:40:24.961114Z","iopub.status.idle":"2026-03-12T12:40:25.469602Z","shell.execute_reply.started":"2026-03-12T12:40:24.961078Z","shell.execute_reply":"2026-03-12T12:40:25.468532Z"}},"outputs":[],"execution_count":null}]}