{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"colab":{"collapsed_sections":["8vC3UbUfX5RF","2FLm07EBF_7_"],"provenance":[]},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":103436,"databundleVersionId":12476472,"sourceType":"competition"}],"dockerImageVersionId":31040,"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":{"id":"uvs65J_kNPhY","trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:36:59.052206Z","iopub.execute_input":"2025-06-18T07:36:59.052512Z","iopub.status.idle":"2025-06-18T07:37:01.470213Z","shell.execute_reply.started":"2025-06-18T07:36:59.052484Z","shell.execute_reply":"2025-06-18T07:37:01.469212Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport datetime as dt","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:37:44.739067Z","iopub.execute_input":"2025-06-18T07:37:44.739367Z","iopub.status.idle":"2025-06-18T07:37:45.742162Z","shell.execute_reply.started":"2025-06-18T07:37:44.739344Z","shell.execute_reply":"2025-06-18T07:37:45.740658Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Import dataset","metadata":{"id":"Dv-4CeOTzaUr"}},{"cell_type":"code","source":"df_delay_79 = pd.read_csv('/kaggle/input/ds-108-p-21-assigment-06/delay_7_9_CONDITION_PRODUCT_SUPPLIER.csv')\ndf_not_delay_79 = pd.read_csv('/kaggle/input/ds-108-p-21-assigment-06/not_delay_7_9_CONDITION_PRODUCT_SUPPLIER.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:37:49.114228Z","iopub.execute_input":"2025-06-18T07:37:49.114685Z","iopub.status.idle":"2025-06-18T07:37:58.218470Z","shell.execute_reply.started":"2025-06-18T07:37:49.114658Z","shell.execute_reply":"2025-06-18T07:37:58.217530Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_79 = pd.concat([df_delay_79, df_not_delay_79], ignore_index=True)","metadata":{"id":"vwvsOONhNwN4","trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:37:58.220058Z","iopub.execute_input":"2025-06-18T07:37:58.220342Z","iopub.status.idle":"2025-06-18T07:37:58.413012Z","shell.execute_reply.started":"2025-06-18T07:37:58.220310Z","shell.execute_reply":"2025-06-18T07:37:58.412004Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Basic EDA and Deal with Missing values","metadata":{"id":"lC7NnJ2fzoM6"}},{"cell_type":"code","source":"def plot_missing_values(df):\n    cols = df.columns\n    count = [df[col].isnull().sum() for col in cols]\n    percent = [i / len(df) for i in count]\n    \n    missing = pd.DataFrame({'proportion': percent}, index=cols)\n    # Chỉ giữ lại các cột có giá trị thiếu\n    missing = missing[missing['proportion'] > 0]\n    \n    if missing.empty:\n        print(\"Không có cột nào bị thiếu giá trị.\")\n        return missing, []\n\n    # Sắp xếp giảm dần theo tỉ lệ missing\n    missing = missing.sort_values(by='proportion', ascending=False)\n    \n    plt.figure(figsize=(12, 0.5 * len(missing)))  # chiều cao động theo số cột\n    plt.title('Missing values in columns', fontsize=14)\n    ax = sns.barplot(x=missing['proportion'], y=missing.index, palette='viridis')\n\n    for i, p in enumerate(ax.patches):\n        ax.text(p.get_x() + p.get_width() + 0.01, \n                p.get_y() + p.get_height() / 2, \n                f\"{missing.iloc[i]['proportion']*100:.2f}%\", \n                va='center')\n\n    mean = np.mean(missing['proportion'])\n    std = np.std(missing['proportion'])\n\n    plt.xlabel('Proportion of Missing Values')\n    plt.ylabel('Columns')\n    plt.plot([], [], ' ', label=f'Average missing: {mean:.2f} ± {std:.2f}')\n    plt.legend()\n    plt.tight_layout()\n    plt.show()\n\n    return missing, missing.index.tolist()","metadata":{"id":"dBWvUGA8K7rk","trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:09.264864Z","iopub.execute_input":"2025-06-18T07:38:09.265271Z","iopub.status.idle":"2025-06-18T07:38:09.278147Z","shell.execute_reply.started":"2025-06-18T07:38:09.265173Z","shell.execute_reply":"2025-06-18T07:38:09.276695Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"missing_train_79, train_cols_79 = plot_missing_values(data_79)","metadata":{"id":"4g2Lu35kLCyV","outputId":"c0b48e99-aa44-475f-cffa-754415de65a6","trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:13.619602Z","iopub.execute_input":"2025-06-18T07:38:13.619911Z","iopub.status.idle":"2025-06-18T07:38:14.645799Z","shell.execute_reply.started":"2025-06-18T07:38:13.619884Z","shell.execute_reply":"2025-06-18T07:38:14.644717Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Missing values","metadata":{}},{"cell_type":"code","source":"# Xử lý thay thế các vị trí trống thành nan\ndata_79 = data_79.replace(r'^\\s*$', np.nan, regex=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:17.559131Z","iopub.execute_input":"2025-06-18T07:38:17.559471Z","iopub.status.idle":"2025-06-18T07:38:23.419546Z","shell.execute_reply.started":"2025-06-18T07:38:17.559431Z","shell.execute_reply":"2025-06-18T07:38:23.418570Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Xoá các cột chắc chắn không dùng do thiếu nhiều và có sau khi giao hàng","metadata":{}},{"cell_type":"code","source":"eliminated_cols_by_missing = ['QTUF_RCV_NO', 'SOUF_RCV_NO', 'REASON_CD', 'SHIP DECISION NO']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:23.420976Z","iopub.execute_input":"2025-06-18T07:38:23.421322Z","iopub.status.idle":"2025-06-18T07:38:23.425770Z","shell.execute_reply.started":"2025-06-18T07:38:23.421283Z","shell.execute_reply":"2025-06-18T07:38:23.424908Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_79.drop(columns = eliminated_cols_by_missing, inplace=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:23.426562Z","iopub.execute_input":"2025-06-18T07:38:23.426839Z","iopub.status.idle":"2025-06-18T07:38:23.630320Z","shell.execute_reply.started":"2025-06-18T07:38:23.426797Z","shell.execute_reply":"2025-06-18T07:38:23.629508Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_79 = data_79.dropna(subset=['Ship Mode','SUPPLIER_DIV'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:23.631887Z","iopub.execute_input":"2025-06-18T07:38:23.632185Z","iopub.status.idle":"2025-06-18T07:38:23.933255Z","shell.execute_reply.started":"2025-06-18T07:38:23.632162Z","shell.execute_reply":"2025-06-18T07:38:23.932482Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_79['OTHER AREA SHIP DIV'] = data_79['OTHER AREA SHIP DIV'].fillna('0')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:23.934106Z","iopub.execute_input":"2025-06-18T07:38:23.934402Z","iopub.status.idle":"2025-06-18T07:38:24.043628Z","shell.execute_reply.started":"2025-06-18T07:38:23.934371Z","shell.execute_reply":"2025-06-18T07:38:24.042604Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Datatype convertion","metadata":{"id":"oDDMHsE8imzS"}},{"cell_type":"code","source":"attribute_types = {\n    \"Order date\": \"datetime\",\n    'SUBSIDIARY_CD': \"category\",\n    \"GLOBAL_NO\": \"category\",\n    \"CLASSIFY_CD\": \"category\",\n    \"BRAND_CD\": \"category\",\n    \"INNER_CD\": \"category\",\n    \"CUST_CD\": \"category\",\n    \"SUPPLIER_CD\": \"category\",\n    \"Sales order line number\": \"numerical\",\n    \"Stock class\": \"category\",\n    \"Consider count hodiday Saturday\": \"numerical\",\n    \"SO QTY\": \"numerical\",\n    \"OTHER AREA SHIP DIV\": \"category\",\n    \"ALLOCATION QTY\": \"numerical\",\n    \"SUPPLIER INV AMOUNT\": \"numerical\",\n    \"PACKING RANK\": \"category\",\n    \"PRODUCT_CD\": \"category\",\n    \"PRODUCT ATTRIBUTION\": \"category\",\n    \"SPECIAL DIV\": \"category\",\n    \"LOGICAL PLANT\": \"category\",\n    \"PURCHASE AMOUNT\": \"numerical\",\n    \"VSD\": \"datetime\",\n    \"DIRECT SHIP FLG\": \"category\",\n    \"DELI_DIV\": \"category\",\n    \"label\": \"category\",\n    \"Ship Mode\": \"category\",\n    \"PACK QTY\": \"numerical\",\n    \"WEIGHT PER PIECE\": \"numerical\",\n    \"SUPPLIER_DIV\": \"category\",\n    \"SPECIAL_DIV\": \"category\",\n    \"SO_TIME\": \"numerical\",\n    \"SO_DAY_OF_MONTH\": \"numerical\",\n    \"SO_DAY_OF_WEEK\": \"numerical\"\n}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:24.044797Z","iopub.execute_input":"2025-06-18T07:38:24.045115Z","iopub.status.idle":"2025-06-18T07:38:24.051990Z","shell.execute_reply.started":"2025-06-18T07:38:24.045088Z","shell.execute_reply":"2025-06-18T07:38:24.050902Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class DataTypeConverter:\n    def __init__(self, type_mapping):\n        self.type_mapping = type_mapping\n\n    def convert(self, df):\n        df = df.copy()\n        for col, dtype in self.type_mapping.items():\n            try:\n                if dtype == 'datetime':\n                    # Convert mixed formats and normalize (drop time part)\n                    df[col] = pd.to_datetime(df[col], errors='coerce').dt.normalize()\n                elif dtype == 'category':\n                    df[col] = df[col].astype('category')\n                elif dtype == 'numerical':\n                    df[col] = pd.to_numeric(df[col], errors='coerce')\n            except Exception as e:\n                print(f\"❌ Failed to convert column {col} to {dtype}: {e}\")\n\n        return df","metadata":{"id":"b_I9HKbLl__R","trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:26.491126Z","iopub.execute_input":"2025-06-18T07:38:26.491508Z","iopub.status.idle":"2025-06-18T07:38:26.498775Z","shell.execute_reply.started":"2025-06-18T07:38:26.491445Z","shell.execute_reply":"2025-06-18T07:38:26.497723Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"converter = DataTypeConverter(attribute_types)","metadata":{"id":"AyqFvVAAq5Ey","trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:29.964301Z","iopub.execute_input":"2025-06-18T07:38:29.965121Z","iopub.status.idle":"2025-06-18T07:38:29.969748Z","shell.execute_reply.started":"2025-06-18T07:38:29.965084Z","shell.execute_reply":"2025-06-18T07:38:29.968630Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_79 = converter.convert(data_79)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:30.258903Z","iopub.execute_input":"2025-06-18T07:38:30.259224Z","iopub.status.idle":"2025-06-18T07:38:37.782748Z","shell.execute_reply.started":"2025-06-18T07:38:30.259198Z","shell.execute_reply":"2025-06-18T07:38:37.781575Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_79.drop(columns = 'SUBSIDIARY_CD', inplace=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:37.784364Z","iopub.execute_input":"2025-06-18T07:38:37.785053Z","iopub.status.idle":"2025-06-18T07:38:37.845132Z","shell.execute_reply.started":"2025-06-18T07:38:37.785018Z","shell.execute_reply":"2025-06-18T07:38:37.844179Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Feature selection","metadata":{}},{"cell_type":"markdown","source":"### Tính IV, WOE tìm ra các thuộc tính mạnh","metadata":{}},{"cell_type":"code","source":"import warnings\n\ndef iv_woe(data, target, bins=10, show_woe=False, plot_iv=True):\n    # Ẩn các cảnh báo FutureWarning\n    warnings.filterwarnings(\"ignore\", category=FutureWarning)\n\n    data = data.copy()\n    data[target] = data[target].astype(int)  # Fix: Ensure target is numeric\n\n    newDF, woeDF = pd.DataFrame(), pd.DataFrame()\n    cols = data.columns\n    strong_features = []\n\n    for ivars in cols[~cols.isin([target])]:\n        if (data[ivars].dtype.kind in 'bifc') and (len(np.unique(data[ivars])) > 10):\n            binned_x = pd.qcut(data[ivars], bins, duplicates='drop')\n            d0 = pd.DataFrame({'x': binned_x, 'y': data[target]})\n        else:\n            d0 = pd.DataFrame({'x': data[ivars], 'y': data[target]})\n\n        d = d0.groupby(\"x\", as_index=False).agg({\"y\": [\"count\", \"sum\"]})\n        d.columns = ['Cutoff', 'N', 'Events']\n        d['% of Events'] = np.maximum(d['Events'], 0.5) / d['Events'].sum()\n        d['Non-Events'] = d['N'] - d['Events']\n        d['% of Non-Events'] = np.maximum(d['Non-Events'], 0.5) / d['Non-Events'].sum()\n        d['WoE'] = np.log(d['% of Events'] / d['% of Non-Events'])\n        d['IV'] = d['WoE'] * (d['% of Events'] - d['% of Non-Events'])\n        d.insert(loc=0, column='Variable', value=ivars)\n\n        total_iv = d['IV'].sum()\n        print(\"Information value of \" + ivars + \" is \" + str(round(total_iv, 6)))\n\n        temp = pd.DataFrame({\"Variable\": [ivars], \"IV\": [total_iv]})\n        newDF = pd.concat([newDF, temp], axis=0)\n        woeDF = pd.concat([woeDF, d], axis=0)\n\n        if total_iv >= 0.3:\n            strong_features.append(ivars)\n\n        if show_woe:\n            print(d)\n\n    newDF.reset_index(drop=True, inplace=True)\n\n    if plot_iv:\n        plt.figure(figsize=(10, 6))\n        sorted_df = newDF.sort_values(by='IV', ascending=False)\n        plt.barh(sorted_df['Variable'], sorted_df['IV'], color='skyblue')\n        plt.xlabel(\"Information Value (IV)\")\n        plt.title(\"Information Value of Features\")\n        plt.gca().invert_yaxis()\n        plt.tight_layout()\n        plt.show()\n\n    if strong_features:\n        print(\"\\n💪 Strong predictive features (IV >= 0.3):\")\n        for feat in strong_features:\n            print(f\" - {feat}\")\n    else:\n        print(\"\\n⚠️ No strong features found (IV >= 0.3).\")\n\n    return newDF, woeDF","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:37.846163Z","iopub.execute_input":"2025-06-18T07:38:37.846405Z","iopub.status.idle":"2025-06-18T07:38:37.859370Z","shell.execute_reply.started":"2025-06-18T07:38:37.846385Z","shell.execute_reply":"2025-06-18T07:38:37.858227Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"iv_79, woe_79 = iv_woe(df_79, target='label', bins=20, show_woe=False, plot_iv=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:38.399631Z","iopub.execute_input":"2025-06-18T07:38:38.399914Z","iopub.status.idle":"2025-06-18T07:38:46.354818Z","shell.execute_reply.started":"2025-06-18T07:38:38.399894Z","shell.execute_reply":"2025-06-18T07:38:46.353705Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def split_columns_by_type(df):\n    categorical_cols = df.select_dtypes(include=['category']).columns.tolist()\n    numerical_cols = df.select_dtypes(include=['number']).columns.tolist()\n    cat_cols = [col for col in categorical_cols if col not in ['label']]\n    return cat_cols, numerical_cols","metadata":{"id":"rCEQWoGmGFrc","trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:46.356299Z","iopub.execute_input":"2025-06-18T07:38:46.356647Z","iopub.status.idle":"2025-06-18T07:38:46.361998Z","shell.execute_reply.started":"2025-06-18T07:38:46.356606Z","shell.execute_reply":"2025-06-18T07:38:46.361253Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Chuẩn bị dữ liệu để Modeling","metadata":{}},{"cell_type":"code","source":"useful_cols = [\n    'GLOBAL_NO',\n    'CLASSIFY_CD',\n    'Order date',\n    'BRAND_CD',\n    'Sales order line number',\n    'VSD',\n    'DIRECT SHIP FLG',\n    'PRODUCT ATTRIBUTION',\n    'DELI_DIV',\n    'OTHER AREA SHIP DIV',\n    'SUPPLIER_DIV',\n    'SPECIAL DIV',\n    'SO_TIME',\n    'SUPPLIER INV AMOUNT',\n    'SO_DAY_OF_MONTH',\n    'SO_DAY_OF_WEEK',\n    'label'\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:50.445154Z","iopub.execute_input":"2025-06-18T07:38:50.445484Z","iopub.status.idle":"2025-06-18T07:38:50.450362Z","shell.execute_reply.started":"2025-06-18T07:38:50.445435Z","shell.execute_reply":"2025-06-18T07:38:50.449469Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train_on_79 = df_79[useful_cols]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:55.425370Z","iopub.execute_input":"2025-06-18T07:38:55.425741Z","iopub.status.idle":"2025-06-18T07:38:55.456086Z","shell.execute_reply.started":"2025-06-18T07:38:55.425716Z","shell.execute_reply":"2025-06-18T07:38:55.454562Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"datetime_cols = ['Order date', 'VSD']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:56.003487Z","iopub.execute_input":"2025-06-18T07:38:56.003769Z","iopub.status.idle":"2025-06-18T07:38:56.007884Z","shell.execute_reply.started":"2025-06-18T07:38:56.003750Z","shell.execute_reply":"2025-06-18T07:38:56.007105Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train_on_79['range_day'] = (df_train_on_79['VSD'] - df_train_on_79['Order date']).dt.days.astype(int)\ndf_train_on_79['order month'] = df_train_on_79['Order date'].dt.month.astype(int)\ndf_train_on_79 = df_train_on_79.drop(columns=datetime_cols)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:56.330435Z","iopub.execute_input":"2025-06-18T07:38:56.330736Z","iopub.status.idle":"2025-06-18T07:38:56.437812Z","shell.execute_reply.started":"2025-06-18T07:38:56.330716Z","shell.execute_reply":"2025-06-18T07:38:56.436696Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train_on_79['SUPPLIER_DIV'] = df_train_on_79['SUPPLIER_DIV'].astype(int)\ndf_train_on_79['SUPPLIER_DIV'] = df_train_on_79['SUPPLIER_DIV'].astype('category')\ndf_train_on_79['SUPPLIER_DIV'] = df_train_on_79['SUPPLIER_DIV'].astype(int)\ndf_train_on_79['SUPPLIER_DIV'] = df_train_on_79['SUPPLIER_DIV'].astype('category')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:56.928611Z","iopub.execute_input":"2025-06-18T07:38:56.928909Z","iopub.status.idle":"2025-06-18T07:38:56.972693Z","shell.execute_reply.started":"2025-06-18T07:38:56.928887Z","shell.execute_reply":"2025-06-18T07:38:56.971770Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train_on_79['OTHER AREA SHIP DIV'] = df_train_on_79['OTHER AREA SHIP DIV'].astype(int)\ndf_train_on_79['OTHER AREA SHIP DIV'] = df_train_on_79['OTHER AREA SHIP DIV'].astype('category')\ndf_train_on_79['OTHER AREA SHIP DIV'] = df_train_on_79['OTHER AREA SHIP DIV'].astype(int)\ndf_train_on_79['OTHER AREA SHIP DIV'] = df_train_on_79['OTHER AREA SHIP DIV'].astype('category')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:58.807797Z","iopub.execute_input":"2025-06-18T07:38:58.808153Z","iopub.status.idle":"2025-06-18T07:38:58.850241Z","shell.execute_reply.started":"2025-06-18T07:38:58.808129Z","shell.execute_reply":"2025-06-18T07:38:58.849388Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cat_col, num_col = split_columns_by_type(df_train_on_79)\ncat_col, num_col","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:38:59.765835Z","iopub.execute_input":"2025-06-18T07:38:59.766142Z","iopub.status.idle":"2025-06-18T07:38:59.817820Z","shell.execute_reply.started":"2025-06-18T07:38:59.766114Z","shell.execute_reply":"2025-06-18T07:38:59.816951Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ndef undersample_to_ratio(df, label_col='label', minority_class=1, ratio=1/20, random_state=24):\n    \"\"\"\n    Undersample lớp đa số để đạt tỷ lệ mong muốn giữa lớp thiểu số và đa số.\n    \n    Parameters:\n        df (pd.DataFrame): Dữ liệu đầu vào.\n        label_col (str): Tên cột label.\n        minority_class (int or str): Giá trị đại diện lớp thiểu số.\n        ratio (float): Tỷ lệ lớp thiểu số / lớp đa số (vd: 1/20).\n        random_state (int): Seed cho việc lấy mẫu ngẫu nhiên.\n        \n    Returns:\n        pd.DataFrame: Dataset sau khi undersample.\n    \"\"\"\n    # Tách lớp thiểu số và đa số\n    minority_df = df[df[label_col] == minority_class]\n    majority_df = df[df[label_col] != minority_class]\n    \n    # Số mẫu cần từ lớp đa số\n    n_minority = len(minority_df)\n    n_majority = int(n_minority / ratio)\n    \n    # Kiểm tra nếu thiếu dữ liệu\n    if n_majority > len(majority_df):\n        raise ValueError(\"Không đủ mẫu trong lớp đa số để thực hiện undersampling theo tỷ lệ yêu cầu.\")\n    \n    majority_sampled = majority_df.sample(n=n_majority, random_state=24)\n    \n    # Gộp lại và shuffle\n    df_balanced = pd.concat([minority_df, majority_sampled])\n    df_balanced = df_balanced.sample(frac=1, random_state=24).reset_index(drop=True)\n    \n    return df_balanced\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:39:01.618786Z","iopub.execute_input":"2025-06-18T07:39:01.619132Z","iopub.status.idle":"2025-06-18T07:39:01.626732Z","shell.execute_reply.started":"2025-06-18T07:39:01.619109Z","shell.execute_reply":"2025-06-18T07:39:01.625722Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Chia dữ liệu x_train, x_test, y_train, y_test","metadata":{}},{"cell_type":"code","source":"X_79 = df_train_on_79.drop(columns=['label'])\ny_79 = df_train_on_79['label']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:39:05.347135Z","iopub.execute_input":"2025-06-18T07:39:05.347566Z","iopub.status.idle":"2025-06-18T07:39:05.378918Z","shell.execute_reply.started":"2025-06-18T07:39:05.347538Z","shell.execute_reply":"2025-06-18T07:39:05.378144Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:39:05.664993Z","iopub.execute_input":"2025-06-18T07:39:05.665302Z","iopub.status.idle":"2025-06-18T07:39:05.964849Z","shell.execute_reply.started":"2025-06-18T07:39:05.665271Z","shell.execute_reply":"2025-06-18T07:39:05.963879Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_train_79, x_test_79, y_train_79, y_test_79 = train_test_split(X_79, y_79, test_size=0.2, random_state=1009)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:39:05.966139Z","iopub.execute_input":"2025-06-18T07:39:05.966502Z","iopub.status.idle":"2025-06-18T07:39:06.227887Z","shell.execute_reply.started":"2025-06-18T07:39:05.966426Z","shell.execute_reply":"2025-06-18T07:39:06.227104Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Undersample tập train","metadata":{}},{"cell_type":"code","source":"df_train = pd.concat([x_train_79, y_train_79], axis=1)\ndf_train = undersample_to_ratio(df_train, label_col='label', minority_class=1, ratio=1/10, random_state=24)\nx_train_79 = df_train.drop(columns=['label'])\ny_train_79 = df_train['label']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:39:06.440994Z","iopub.execute_input":"2025-06-18T07:39:06.441344Z","iopub.status.idle":"2025-06-18T07:39:07.222346Z","shell.execute_reply.started":"2025-06-18T07:39:06.441317Z","shell.execute_reply":"2025-06-18T07:39:07.221364Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Modeling","metadata":{}},{"cell_type":"markdown","source":"## CATBOOST MODEL","metadata":{}},{"cell_type":"code","source":"from catboost import CatBoostClassifier\nfrom sklearn.metrics import classification_report, confusion_matrix","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:39:09.329782Z","iopub.execute_input":"2025-06-18T07:39:09.330086Z","iopub.status.idle":"2025-06-18T07:39:09.882116Z","shell.execute_reply.started":"2025-06-18T07:39:09.330061Z","shell.execute_reply":"2025-06-18T07:39:09.881211Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def plot_catboost_importance(model, feature_names, top_n=20):\n    importance = model.get_feature_importance()\n    importance_df = pd.DataFrame({\n        'Feature': feature_names,\n        'Importance': importance\n    }).sort_values(by='Importance', ascending=False).head(top_n)\n    # print the importance_df' feature names and importance values\n    print(importance_df)\n    plt.figure(figsize=(10, 6))\n    plt.barh(importance_df['Feature'][::-1], importance_df['Importance'][::-1], color='lightcoral')\n    plt.title('Top Feature Importances (CatBoost)')\n    plt.xlabel('Importance')\n    plt.tight_layout()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:39:09.883726Z","iopub.execute_input":"2025-06-18T07:39:09.884316Z","iopub.status.idle":"2025-06-18T07:39:09.890760Z","shell.execute_reply.started":"2025-06-18T07:39:09.884283Z","shell.execute_reply":"2025-06-18T07:39:09.889569Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Train 79 ","metadata":{}},{"cell_type":"code","source":"model_catboost_1=CatBoostClassifier(\niterations=1000,          # Số vòng lặp (có thể điều chỉnh)\nlearning_rate=0.1,        # Tỷ lệ học\ndepth=5,                  # Độ sâu cây\nloss_function='Logloss',  # Hàm mất mát cho bài toán phân loại nhị phân\nverbose=100,              # In thông tin sau mỗi 100 vòng\nrandom_seed=42,\ncat_features=cat_col\n)   ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:39:11.671153Z","iopub.execute_input":"2025-06-18T07:39:11.671496Z","iopub.status.idle":"2025-06-18T07:39:11.678779Z","shell.execute_reply.started":"2025-06-18T07:39:11.671469Z","shell.execute_reply":"2025-06-18T07:39:11.677701Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_catboost_1.fit(x_train_79, y_train_79)\ny_pred_79 = model_catboost_1.predict(x_test_79)\nprint(classification_report(y_test_79, y_pred_79))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:39:12.048602Z","iopub.execute_input":"2025-06-18T07:39:12.048906Z","iopub.status.idle":"2025-06-18T07:42:13.024356Z","shell.execute_reply.started":"2025-06-18T07:39:12.048884Z","shell.execute_reply":"2025-06-18T07:42:13.023225Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plot_catboost_importance(model_catboost_1, X_79.columns, top_n=20)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:42:37.620596Z","iopub.execute_input":"2025-06-18T07:42:37.620881Z","iopub.status.idle":"2025-06-18T07:42:37.901916Z","shell.execute_reply.started":"2025-06-18T07:42:37.620862Z","shell.execute_reply":"2025-06-18T07:42:37.900293Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Xử lí tập Test_final để chuẩn bị dữ liệu Predict cuối cùng","metadata":{}},{"cell_type":"code","source":"final_test_path = r'/kaggle/input/ds-108-p-21-assigment-06/PILOT_10.csv'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:42:50.652905Z","iopub.execute_input":"2025-06-18T07:42:50.653249Z","iopub.status.idle":"2025-06-18T07:42:50.658721Z","shell.execute_reply.started":"2025-06-18T07:42:50.653224Z","shell.execute_reply":"2025-06-18T07:42:50.657615Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_data = pd.read_csv(final_test_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:42:52.113828Z","iopub.execute_input":"2025-06-18T07:42:52.114178Z","iopub.status.idle":"2025-06-18T07:42:52.927844Z","shell.execute_reply.started":"2025-06-18T07:42:52.114154Z","shell.execute_reply":"2025-06-18T07:42:52.926899Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_test_cols = useful_cols.copy()\nif 'label' in x_test_cols:\n    x_test_cols.remove('label')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:42:52.929284Z","iopub.execute_input":"2025-06-18T07:42:52.929574Z","iopub.status.idle":"2025-06-18T07:42:52.934168Z","shell.execute_reply.started":"2025-06-18T07:42:52.929552Z","shell.execute_reply":"2025-06-18T07:42:52.933157Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_test_cols","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:42:53.257112Z","iopub.execute_input":"2025-06-18T07:42:53.257432Z","iopub.status.idle":"2025-06-18T07:42:53.263440Z","shell.execute_reply.started":"2025-06-18T07:42:53.257407Z","shell.execute_reply":"2025-06-18T07:42:53.262682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_test_final = test_data[x_test_cols]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:42:54.706907Z","iopub.execute_input":"2025-06-18T07:42:54.707834Z","iopub.status.idle":"2025-06-18T07:42:54.718542Z","shell.execute_reply.started":"2025-06-18T07:42:54.707804Z","shell.execute_reply":"2025-06-18T07:42:54.717525Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_test_final['OTHER AREA SHIP DIV'] = x_test_final['OTHER AREA SHIP DIV'].fillna('0')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:42:56.300921Z","iopub.execute_input":"2025-06-18T07:42:56.301685Z","iopub.status.idle":"2025-06-18T07:42:56.316141Z","shell.execute_reply.started":"2025-06-18T07:42:56.301654Z","shell.execute_reply":"2025-06-18T07:42:56.315288Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_test_final['SUPPLIER_DIV'] = x_test_final['SUPPLIER_DIV'].fillna(1.0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:42:59.041570Z","iopub.execute_input":"2025-06-18T07:42:59.042504Z","iopub.status.idle":"2025-06-18T07:42:59.048812Z","shell.execute_reply.started":"2025-06-18T07:42:59.042473Z","shell.execute_reply":"2025-06-18T07:42:59.047855Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_test_final = converter.convert(x_test_final)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:43:07.025182Z","iopub.execute_input":"2025-06-18T07:43:07.025527Z","iopub.status.idle":"2025-06-18T07:43:07.159376Z","shell.execute_reply.started":"2025-06-18T07:43:07.025503Z","shell.execute_reply":"2025-06-18T07:43:07.158522Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_test_final['range_day'] = (x_test_final['VSD'] - x_test_final['Order date']).dt.days.astype(int)\nx_test_final['order month'] = x_test_final['Order date'].dt.month.astype(int)\nx_test_final = x_test_final.drop(columns=datetime_cols)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:43:08.819442Z","iopub.execute_input":"2025-06-18T07:43:08.819886Z","iopub.status.idle":"2025-06-18T07:43:08.847392Z","shell.execute_reply.started":"2025-06-18T07:43:08.819852Z","shell.execute_reply":"2025-06-18T07:43:08.846340Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_test_final['OTHER AREA SHIP DIV'] = x_test_final['OTHER AREA SHIP DIV'].astype(int)\nx_test_final['OTHER AREA SHIP DIV'] = x_test_final['OTHER AREA SHIP DIV'].astype('category')\nx_test_final['SUPPLIER_DIV'] = x_test_final['SUPPLIER_DIV'].astype(int)\nx_test_final['SUPPLIER_DIV'] = x_test_final['SUPPLIER_DIV'].astype('category')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:43:09.135009Z","iopub.execute_input":"2025-06-18T07:43:09.135830Z","iopub.status.idle":"2025-06-18T07:43:09.148740Z","shell.execute_reply.started":"2025-06-18T07:43:09.135789Z","shell.execute_reply":"2025-06-18T07:43:09.147689Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Final Prdiction on x_test_final for submission","metadata":{}},{"cell_type":"markdown","source":"### Train 76 test final","metadata":{}},{"cell_type":"markdown","source":"#### Catboost","metadata":{}},{"cell_type":"code","source":"y_final_test_pred_cat_79 = model_catboost_1.predict(x_test_final)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:43:14.363964Z","iopub.execute_input":"2025-06-18T07:43:14.364267Z","iopub.status.idle":"2025-06-18T07:43:15.616480Z","shell.execute_reply.started":"2025-06-18T07:43:14.364244Z","shell.execute_reply":"2025-06-18T07:43:15.615543Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame({\n    \"ID\": x_test_final.index+1,       # hoặc index nếu không có cột id\n    \"label\": y_final_test_pred_cat_79       # nhãn dự đoán\n})\n\nsubmission.to_csv(\"submission_catboost_train_79.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-18T07:43:29.036299Z","iopub.execute_input":"2025-06-18T07:43:29.036749Z","iopub.status.idle":"2025-06-18T07:43:29.142754Z","shell.execute_reply.started":"2025-06-18T07:43:29.036715Z","shell.execute_reply":"2025-06-18T07:43:29.141817Z"}},"outputs":[],"execution_count":null}]}