{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":7391,"databundleVersionId":44328,"mountSlug":"competitions/favorita-grocery-sales-forecasting"},{"sourceType":"datasetVersion","sourceId":16548506,"datasetId":10596734,"databundleVersionId":17554282,"mountSlug":"datasets/pgnjams/ie212-favorita-engineered-features-27-stores"}],"dockerImageVersionId":31401,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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\n\n# Use the kagglehub client library to attach Kaggle resources like competitions, datasets, and models to your session\n# Learn more about kagglehub: https://github.com/Kaggle/kagglehub/blob/main/README.md\n\nimport kagglehub\n# kagglehub.dataset_download('<owner>/<dataset-slug>')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\n\nfrom sklearn.preprocessing import LabelEncoder\n\nimport lightgbm as lgb\n\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import LSTM\nfrom tensorflow.keras.layers import Dense\nfrom tensorflow.keras.layers import Dropout","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:43:23.820949Z","iopub.execute_input":"2026-05-31T06:43:23.821801Z","iopub.status.idle":"2026-05-31T06:43:42.975903Z","shell.execute_reply.started":"2026-05-31T06:43:23.821770Z","shell.execute_reply":"2026-05-31T06:43:42.975205Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load dữ liệu\nimport pandas as pd\nimport numpy as np\n\ndf = pd.read_parquet(\n    \"/kaggle/input/datasets/pgnjams/ie212-favorita-engineered-features-27-stores/kaggle/working/engineered_features_encoded_27_stores.parquet\"\n)\n\nprint(df.shape)\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:47:42.976207Z","iopub.execute_input":"2026-05-31T06:47:42.976897Z","iopub.status.idle":"2026-05-31T06:47:49.508547Z","shell.execute_reply.started":"2026-05-31T06:47:42.976860Z","shell.execute_reply":"2026-05-31T06:47:49.507548Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Sắp xếp dữ liệu\ndf[\"date\"] = pd.to_datetime(df[\"date\"])\n\ndf = df.sort_values(\n    [\"store_nbr\", \"item_nbr\", \"date\"]\n).reset_index(drop=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:47:53.315810Z","iopub.execute_input":"2026-05-31T06:47:53.316652Z","iopub.status.idle":"2026-05-31T06:47:59.637628Z","shell.execute_reply.started":"2026-05-31T06:47:53.316615Z","shell.execute_reply":"2026-05-31T06:47:59.636754Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Drop các cột không dùng\ndrop_cols = [\n    \"id\",\n\n    \"wavelet_soft_sales\",\n    \"wavelet_hard_sales\",\n\n    \"lag_1_wavelet_soft_sales\",\n    \"lag_7_wavelet_soft_sales\",\n    \"lag_16_wavelet_soft_sales\",\n\n    \"lag_1_unit_sales\",\n    \"lag_7_unit_sales\",\n    \"lag_16_unit_sales\",\n\n    \"lag_1_kalman_sales\",\n    \"lag_7_kalman_sales\",\n    \"lag_16_kalman_sales\",\n\n    \"rolling_mean_7\",\n    \"rolling_std_7\",\n    \"rolling_mean_30\",\n\n    \"time_idx\"\n]\n\ndf = df.drop(columns=drop_cols)\n\nprint(df.columns)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:48:05.583395Z","iopub.execute_input":"2026-05-31T06:48:05.584147Z","iopub.status.idle":"2026-05-31T06:48:06.242605Z","shell.execute_reply.started":"2026-05-31T06:48:05.584113Z","shell.execute_reply":"2026-05-31T06:48:06.241747Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tạo 15 Kalman Lags cho LSTM\nfor lag in range(1, 16):\n\n    df[f\"kalman_lag_{lag}\"] = (\n        df.groupby(\n            [\"store_nbr\", \"item_nbr\"]\n        )[\"kalman_sales\"]\n        .shift(lag)\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:48:13.024289Z","iopub.execute_input":"2026-05-31T06:48:13.025014Z","iopub.status.idle":"2026-05-31T06:48:27.548179Z","shell.execute_reply.started":"2026-05-31T06:48:13.024981Z","shell.execute_reply":"2026-05-31T06:48:27.547470Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df[\n    [\n        \"kalman_sales\",\n        \"kalman_lag_1\",\n        \"kalman_lag_2\",\n        \"kalman_lag_3\"\n    ]\n].head(20)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:48:34.782736Z","iopub.execute_input":"2026-05-31T06:48:34.783682Z","iopub.status.idle":"2026-05-31T06:48:35.060839Z","shell.execute_reply.started":"2026-05-31T06:48:34.783651Z","shell.execute_reply":"2026-05-31T06:48:35.059864Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tạo Mean cho 3,7,14 ngày\nwindows = [3, 7, 14]\n\nfor w in windows:\n\n    df[f\"mean_{w}\"] = (\n        df.groupby(\n            [\"store_nbr\", \"item_nbr\"]\n        )[\"unit_sales\"]\n        .transform(\n            lambda x:\n                x.shift(1)\n                 .rolling(w)\n                 .mean()\n        )\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:48:38.406373Z","iopub.execute_input":"2026-05-31T06:48:38.407002Z","iopub.status.idle":"2026-05-31T06:49:54.078242Z","shell.execute_reply.started":"2026-05-31T06:48:38.406967Z","shell.execute_reply":"2026-05-31T06:49:54.077261Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tạo Std cho 3,7,14 ngày\nfor w in windows:\n\n    df[f\"std_{w}\"] = (\n        df.groupby(\n            [\"store_nbr\", \"item_nbr\"]\n        )[\"unit_sales\"]\n        .transform(\n            lambda x:\n                x.shift(1)\n                 .rolling(w)\n                 .std()\n        )\n    )","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tạo Max cho 3,7,14 ngày\nfor w in windows:\n\n    df[f\"max_{w}\"] = (\n        df.groupby(\n            [\"store_nbr\", \"item_nbr\"]\n        )[\"unit_sales\"]\n        .transform(\n            lambda x:\n                x.shift(1)\n                 .rolling(w)\n                 .max()\n        )\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T04:47:03.824679Z","iopub.execute_input":"2026-05-31T04:47:03.825551Z","iopub.status.idle":"2026-05-31T04:48:13.728789Z","shell.execute_reply.started":"2026-05-31T04:47:03.825517Z","shell.execute_reply":"2026-05-31T04:48:13.727879Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tạo Median cho 3,7,14 ngày\nfor w in windows:\n\n    df[f\"median_{w}\"] = (\n        df.groupby(\n            [\"store_nbr\", \"item_nbr\"]\n        )[\"unit_sales\"]\n        .transform(\n            lambda x:\n                x.shift(1)\n                 .rolling(w)\n                 .median()\n        )\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T04:48:17.359688Z","iopub.execute_input":"2026-05-31T04:48:17.360225Z","iopub.status.idle":"2026-05-31T04:50:00.782130Z","shell.execute_reply.started":"2026-05-31T04:48:17.360192Z","shell.execute_reply":"2026-05-31T04:50:00.781463Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Loại bỏ các dòng thiếu dữ liệu\ndf = df.dropna().reset_index(drop=True)\n\nprint(df.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:50:03.996448Z","iopub.execute_input":"2026-05-31T06:50:03.997315Z","iopub.status.idle":"2026-05-31T06:50:10.639469Z","shell.execute_reply.started":"2026-05-31T06:50:03.997282Z","shell.execute_reply":"2026-05-31T06:50:10.638744Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Kiểm tra dataset sau xử lý\nprint(df.columns.tolist())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:50:14.491869Z","iopub.execute_input":"2026-05-31T06:50:14.492726Z","iopub.status.idle":"2026-05-31T06:50:14.496815Z","shell.execute_reply.started":"2026-05-31T06:50:14.492695Z","shell.execute_reply":"2026-05-31T06:50:14.495950Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.to_parquet(\n    \"/kaggle/working/favorita_baseline_processed.parquet\",\n    index=False\n)\n\nprint(\"Saved!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:50:19.882179Z","iopub.execute_input":"2026-05-31T06:50:19.882717Z","iopub.status.idle":"2026-05-31T06:50:36.340114Z","shell.execute_reply.started":"2026-05-31T06:50:19.882683Z","shell.execute_reply":"2026-05-31T06:50:36.339246Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Chia Train/Val/Test\ntrain_df = df[\n    (df[\"date\"] >= \"2016-08-01\") &\n    (df[\"date\"] <= \"2017-07-15\")\n].copy()\n\nval_df = df[\n    (df[\"date\"] >= \"2017-07-16\") &\n    (df[\"date\"] <= \"2017-07-31\")\n].copy()\n\ntest_df = df[\n    (df[\"date\"] >= \"2017-08-01\") &\n    (df[\"date\"] <= \"2017-08-15\")\n].copy()\n\nprint(train_df.shape)\nprint(val_df.shape)\nprint(test_df.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:50:39.488882Z","iopub.execute_input":"2026-05-31T06:50:39.489680Z","iopub.status.idle":"2026-05-31T06:50:42.868225Z","shell.execute_reply.started":"2026-05-31T06:50:39.489648Z","shell.execute_reply":"2026-05-31T06:50:42.867461Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Các feature dùng cho LSTM\nsequence_cols = [\n    f\"kalman_lag_{i}\"\n    for i in range(15,0,-1)\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:50:47.414709Z","iopub.execute_input":"2026-05-31T06:50:47.415379Z","iopub.status.idle":"2026-05-31T06:50:47.419398Z","shell.execute_reply.started":"2026-05-31T06:50:47.415348Z","shell.execute_reply":"2026-05-31T06:50:47.418574Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Scale LSTM Feature\nfrom sklearn.preprocessing import StandardScaler\n\nlstm_scaler = StandardScaler()\n\ntrain_df[sequence_cols] = lstm_scaler.fit_transform(\n    train_df[sequence_cols]\n)\n\nval_df[sequence_cols] = lstm_scaler.transform(\n    val_df[sequence_cols]\n)\n\ntest_df[sequence_cols] = lstm_scaler.transform(\n    test_df[sequence_cols]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:50:53.568168Z","iopub.execute_input":"2026-05-31T06:50:53.568692Z","iopub.status.idle":"2026-05-31T06:50:58.539965Z","shell.execute_reply.started":"2026-05-31T06:50:53.568658Z","shell.execute_reply":"2026-05-31T06:50:58.539266Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"new_df = (\n    df.sample(\n        n=1000,\n        random_state=42\n    )\n    .sort_values(\"date\")\n    .reset_index(drop=True)\n)\n\nn = len(new_df)\n\ntrain_df = new_df.iloc[:int(0.7*n)]\nval_df   = new_df.iloc[int(0.7*n):int(0.85*n)]\ntest_df  = new_df.iloc[int(0.85*n):]\n\nprint(train_df.shape)\nprint(val_df.shape)\nprint(test_df.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:51:02.035723Z","iopub.execute_input":"2026-05-31T06:51:02.036660Z","iopub.status.idle":"2026-05-31T06:51:02.730524Z","shell.execute_reply.started":"2026-05-31T06:51:02.036613Z","shell.execute_reply":"2026-05-31T06:51:02.729792Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tạo Tensor LSTM\nimport numpy as np\n\nX_train_lstm = train_df[\n    sequence_cols\n].values.reshape(-1,15,1)\n\nX_val_lstm = val_df[\n    sequence_cols\n].values.reshape(-1,15,1)\n\nX_test_lstm = test_df[\n    sequence_cols\n].values.reshape(-1,15,1)\n\ny_train = train_df[\"unit_sales\"].values\ny_val = val_df[\"unit_sales\"].values\ny_test = test_df[\"unit_sales\"].values","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:51:07.758307Z","iopub.execute_input":"2026-05-31T06:51:07.759065Z","iopub.status.idle":"2026-05-31T06:51:07.766146Z","shell.execute_reply.started":"2026-05-31T06:51:07.759032Z","shell.execute_reply":"2026-05-31T06:51:07.765031Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Metric NWRMSLE\nimport numpy as np\n\ndef nwrmsle(y_true,\n            y_pred,\n            weights):\n\n    y_pred = np.maximum(0,y_pred)\n\n    return np.sqrt(\n        np.sum(\n            weights *\n            (\n                np.log1p(y_pred)\n                -\n                np.log1p(y_true)\n            )**2\n        )\n        /\n        np.sum(weights)\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:51:13.043252Z","iopub.execute_input":"2026-05-31T06:51:13.043853Z","iopub.status.idle":"2026-05-31T06:51:13.048635Z","shell.execute_reply.started":"2026-05-31T06:51:13.043817Z","shell.execute_reply":"2026-05-31T06:51:13.047797Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train LSTM Search\nimport tensorflow as tf\n\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import LSTM\nfrom tensorflow.keras.layers import Dense\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.layers import Input\nfrom tensorflow.keras.models import Model\n\nbest_score = 999999\nbest_model = None\nbest_params = None\n\ntrain_weights = np.where(\n    train_df[\"perishable\"]==1,\n    1.25,\n    1.0\n)\n\nval_weights = np.where(\n    val_df[\"perishable\"]==1,\n    1.25,\n    1.0\n)\n\ntest_weights = np.where(\n    test_df[\"perishable\"]==1,\n    1.25,\n    1.0\n)\n\nunits_list = [32,64,128]\n\nlr_list = [0.001,0.005,0.01]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:51:17.202185Z","iopub.execute_input":"2026-05-31T06:51:17.202888Z","iopub.status.idle":"2026-05-31T06:51:24.686124Z","shell.execute_reply.started":"2026-05-31T06:51:17.202854Z","shell.execute_reply":"2026-05-31T06:51:24.685444Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for units in units_list:\n\n    for lr in lr_list:\n\n        inp = Input(shape=(15,1))\n\n        x = LSTM(\n            units,\n            name=\"lstm_encoder\"\n        )(inp)\n\n        embedding = Dense(\n            32,\n            activation=\"relu\",\n            name=\"embedding\"\n        )(x)\n\n        output = Dense(1)(embedding)\n\n        model = Model(\n            inputs=inp,\n            outputs=output\n        )\n\n        model.compile(\n            optimizer=tf.keras.optimizers.Adam(\n                learning_rate=lr\n            ),\n            loss=\"mse\"\n        )\n\n        early = EarlyStopping(\n            monitor=\"val_loss\",\n            patience=5,\n            restore_best_weights=True\n        )\n\n        model.fit(\n            X_train_lstm,\n            y_train,\n            validation_data=(X_val_lstm, y_val),\n            epochs=100,\n            batch_size=4096,\n            callbacks=[early],\n            verbose=0\n        )\n\n        pred_val = model.predict(\n            X_val_lstm,\n            batch_size=4096,\n            verbose=0\n        ).flatten()\n\n        score = nwrmsle(\n            y_val,\n            pred_val,\n            val_weights\n        )\n\n        print(\n            f\"units={units}, lr={lr}, score={score:.6f}\"\n        )\n\n        if score < best_score:\n\n            best_score = score\n            best_model = model\n\n            best_params = {\n                \"units\": units,\n                \"lr\": lr\n            }","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:51:29.121148Z","iopub.execute_input":"2026-05-31T06:51:29.122287Z","iopub.status.idle":"2026-05-31T06:53:03.171549Z","shell.execute_reply.started":"2026-05-31T06:51:29.122253Z","shell.execute_reply":"2026-05-31T06:53:03.170642Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Lưu LSTM\nbest_model.save(\n    \"/kaggle/working/track1_lstm.h5\"\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:53:09.235899Z","iopub.execute_input":"2026-05-31T06:53:09.236357Z","iopub.status.idle":"2026-05-31T06:53:09.275605Z","shell.execute_reply.started":"2026-05-31T06:53:09.236325Z","shell.execute_reply":"2026-05-31T06:53:09.274925Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Trích Net Features\nfrom tensorflow.keras.models import Model\n\nfeature_model = tf.keras.Model(\n    inputs=best_model.inputs,\n    outputs=best_model.layers[-2].output\n)\n\ntrain_embed = feature_model.predict(\n    X_train_lstm,\n    batch_size=4096\n)\n\nval_embed = feature_model.predict(\n    X_val_lstm,\n    batch_size=4096\n)\n\ntest_embed = feature_model.predict(\n    X_test_lstm,\n    batch_size=4096\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:53:13.978887Z","iopub.execute_input":"2026-05-31T06:53:13.979818Z","iopub.status.idle":"2026-05-31T06:53:14.406143Z","shell.execute_reply.started":"2026-05-31T06:53:13.979785Z","shell.execute_reply":"2026-05-31T06:53:14.405353Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Features cho LightGBM\ndrop_cols = [\n    \"date\",\n    \"unit_sales\"\n]\nX_train_tab = train_df.drop(\n    columns=drop_cols+sequence_cols\n)\n\nX_val_tab = val_df.drop(\n    columns=drop_cols+sequence_cols\n)\n\nX_test_tab = test_df.drop(\n    columns=drop_cols+sequence_cols\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:53:25.120106Z","iopub.execute_input":"2026-05-31T06:53:25.120864Z","iopub.status.idle":"2026-05-31T06:53:25.129137Z","shell.execute_reply.started":"2026-05-31T06:53:25.120829Z","shell.execute_reply":"2026-05-31T06:53:25.128218Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Ghép Embedding\nX_train = np.concatenate(\n    [\n        X_train_tab.values,\n        train_embed\n    ],\n    axis=1\n)\n\nX_val = np.concatenate(\n    [\n        X_val_tab.values,\n        val_embed\n    ],\n    axis=1\n)\n\nX_test = np.concatenate(\n    [\n        X_test_tab.values,\n        test_embed\n    ],\n    axis=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:53:28.743669Z","iopub.execute_input":"2026-05-31T06:53:28.744521Z","iopub.status.idle":"2026-05-31T06:53:28.752590Z","shell.execute_reply.started":"2026-05-31T06:53:28.744468Z","shell.execute_reply":"2026-05-31T06:53:28.751630Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train LightGBM\nimport lightgbm as lgb\nlgb_model = lgb.LGBMRegressor(\n    objective=\"regression\",\n    learning_rate=0.02,\n    num_leaves=80,\n    n_estimators=2000,\n    subsample=0.8,\n    colsample_bytree=0.8\n)\nlgb_model.fit(\n    X_train,\n    y_train,\n    eval_set=[\n        (X_val,y_val)\n    ]\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Lưu LightGBM\nimport joblib\n\njoblib.dump(\n    lgb_model,\n    \"/kaggle/working/track1_lightgbm.pkl\"\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:53:53.159162Z","iopub.execute_input":"2026-05-31T06:53:53.159962Z","iopub.status.idle":"2026-05-31T06:53:53.293825Z","shell.execute_reply.started":"2026-05-31T06:53:53.159929Z","shell.execute_reply":"2026-05-31T06:53:53.292943Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Kiểm thử mô hình dựa trên tập test\nfrom sklearn.metrics import (\n    mean_squared_error,\n    mean_absolute_error\n)\npred_test = lgb_model.predict(\n    X_test\n)\nrmse = np.sqrt(\n    mean_squared_error(\n        y_test,\n        pred_test\n    )\n)\n\nmae = mean_absolute_error(\n    y_test,\n    pred_test\n)\n\nnwrmsle_score = nwrmsle(\n    y_test,\n    pred_test,\n    test_weights\n)\n\nprint(\"RMSE =\",rmse)\nprint(\"MAE =\",mae)\nprint(\"NWRMSLE =\",nwrmsle_score)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:53:58.712964Z","iopub.execute_input":"2026-05-31T06:53:58.713651Z","iopub.status.idle":"2026-05-31T06:53:58.748603Z","shell.execute_reply.started":"2026-05-31T06:53:58.713618Z","shell.execute_reply":"2026-05-31T06:53:58.747786Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Xuất preds_track1.csv\noutput = pd.DataFrame(\n    {\n        \"date\":\n            test_df[\"date\"]\n            .dt.strftime(\"%Y-%m-%d\"),\n\n        \"store_nbr\":\n            test_df[\"store_nbr\"],\n\n        \"item_nbr\":\n            test_df[\"item_nbr\"],\n\n        \"actual_sales\":\n            np.round(\n                y_test,\n                4\n            ),\n\n        \"predicted_sales\":\n            np.round(\n                pred_test,\n                4\n            )\n    }\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:54:07.088926Z","iopub.execute_input":"2026-05-31T06:54:07.089687Z","iopub.status.idle":"2026-05-31T06:54:07.095814Z","shell.execute_reply.started":"2026-05-31T06:54:07.089646Z","shell.execute_reply":"2026-05-31T06:54:07.094870Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"output.head(20)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:54:10.804087Z","iopub.execute_input":"2026-05-31T06:54:10.805001Z","iopub.status.idle":"2026-05-31T06:54:10.816867Z","shell.execute_reply.started":"2026-05-31T06:54:10.804965Z","shell.execute_reply":"2026-05-31T06:54:10.816227Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"output.to_csv(\n    \"/kaggle/working/preds_track1.csv\",\n    index=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:54:24.318477Z","iopub.execute_input":"2026-05-31T06:54:24.319303Z","iopub.status.idle":"2026-05-31T06:54:24.330298Z","shell.execute_reply.started":"2026-05-31T06:54:24.319271Z","shell.execute_reply":"2026-05-31T06:54:24.329482Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Feature Importance\nimport matplotlib.pyplot as plt\nimportance = lgb_model.feature_importances_\nfeature_names = (\n    list(X_train_tab.columns)\n    +\n    [\n        f\"lstm_{i}\"\n        for i in range(\n            train_embed.shape[1]\n        )\n    ]\n)\nimp_df = pd.DataFrame(\n    {\n        \"feature\":feature_names,\n        \"importance\":importance\n    }\n)\nimp_df = imp_df.sort_values(\n    \"importance\",\n    ascending=False\n).head(30)\nplt.figure(figsize=(12,8))\n\nplt.barh(\n    imp_df[\"feature\"],\n    imp_df[\"importance\"]\n)\n\nplt.tight_layout()\n\nplt.savefig(\n    \"/kaggle/working/feature_importance_track1.png\"\n)\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-31T06:54:29.652738Z","iopub.execute_input":"2026-05-31T06:54:29.653057Z","iopub.status.idle":"2026-05-31T06:54:30.164303Z","shell.execute_reply.started":"2026-05-31T06:54:29.653031Z","shell.execute_reply":"2026-05-31T06:54:30.163438Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}