{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":17000,"databundleVersionId":895292,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Matrix Team \n- Mohammad Al-Momani \n- Abdulrahman JOJO","metadata":{}},{"cell_type":"markdown","source":"## Data Description \n\n**bin_0=>** 0 - 1 Very Low Cardinality\n\n**bin_1 =>** 0 - 1 Very Low Cardinality\n\n**bin_2 =>** 0 - 1 Very Low Cardinality\n\n**bin_3 =>** T/F Binary Categorical\n\n**bin_4 =>** Y/N Binary Categorical\n\n**nom_0 =>** Color Low Cardinality\n\n**nom_1 =>** Shape Low Cardinality\n\n**nom_2 =>** Animal Low Cardinality\n\n**nom_3 =>** Contry Low Cardinality\n\n**nom_4 =>** Musical_instruments Low Cardinality\n\n**nom_5-9 =>** code High Cardinality \n\n**ord_0 =>** code Categorical (Code) Low Cardinality Ordinal\n\n**ord_1 =>** Ranking Low Cardinality Ordinal \n\n**ord_2 =>** Temperature Low Cardinality Ordinal\n\n**ord_3 =>** code Medium/High Cardinality Ordinal\n\n**ord_4 =>** code Medium/High Cardinality Ordinal\n\n**ord_5 =>** code Medium/High Cardinality Ordinal\n\n**day =>** 1-7  Low Cardinality Cyclical\n\n**month =>** 1-12 Low Cardinality Cyclical\n\n**target =>** 0-1\n\ntrain[\"bin_4\"].sample(50)\n\n**Class imbalance**\n\n**Fix by =>**\n* class_weight=\"balanced\" أو\n\n* SMOTE \n\n* Focal Loss (لو استخدمنا NN)\n\n## **Encoding** \n**Low Cardinality Nominal =>**\tOne-Hot Encoding\n\n**High Cardinality Nominal =>**\tTarget Encoding أو Frequency Encoding\n\n**Ordinal =>**\tOrdinal Encoding\n\n**Cyclical (day, month)=>** Cyclical Encoding (sin/cos)\n\n**High Ordinal Codes =>**\tTarget Encoding أو Leave-One-Out","metadata":{"execution":{"iopub.status.busy":"2025-10-23T08:26:45.555306Z","iopub.execute_input":"2025-10-23T08:26:45.555618Z","iopub.status.idle":"2025-10-23T08:26:45.564279Z","shell.execute_reply.started":"2025-10-23T08:26:45.555597Z","shell.execute_reply":"2025-10-23T08:26:45.562616Z"}}},{"cell_type":"code","source":"# --- Setup and Libraries ---\nprint(\"--- Step 0: Installing CatBoost Library ---\")\n!pip install catboost --quiet\nprint(\"--- CatBoost installed successfully ---\")\n\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom catboost import CatBoostClassifier\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import roc_auc_score\nfrom sklearn.preprocessing import OrdinalEncoder\nimport warnings\n\n# Display settings and warning suppression\nwarnings.filterwarnings('ignore')\nsns.set_style('whitegrid')\npd.set_option('display.max_columns', 100) # To display more columns when printing\nprint(\"--- Libraries loaded and settings configured ---\")\n\n# --- 1. Data Loading and Initial Setup ---\n\nBASE_PATH = '/kaggle/input/cat-in-the-dat-ii/'\n\ntrain_df = pd.read_csv(BASE_PATH + 'train.csv')\ntest_df = pd.read_csv(BASE_PATH + 'test.csv')\n\n# Separate variables\ny = train_df['target']\ntest_ids = test_df['id']\ntrain_df = train_df.drop(['id', 'target'], axis=1)\ntest_df = test_df.drop('id', axis=1)\n\nprint(f\"✅ Data loaded successfully.\")\nprint(f\"Train data shape: {train_df.shape}\")\nprint(f\"Test data shape: {test_df.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:17.771404Z","iopub.execute_input":"2025-11-07T17:46:17.772253Z","iopub.status.idle":"2025-11-07T17:46:23.599339Z","shell.execute_reply.started":"2025-11-07T17:46:17.772219Z","shell.execute_reply":"2025-11-07T17:46:23.598527Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Quick look at the data¶**","metadata":{}},{"cell_type":"code","source":"print(\"First 5 rows of the training data:\")\ntrain_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:23.600808Z","iopub.execute_input":"2025-11-07T17:46:23.601038Z","iopub.status.idle":"2025-11-07T17:46:23.619865Z","shell.execute_reply.started":"2025-11-07T17:46:23.601019Z","shell.execute_reply":"2025-11-07T17:46:23.619060Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:23.620733Z","iopub.execute_input":"2025-11-07T17:46:23.621141Z","iopub.status.idle":"2025-11-07T17:46:24.082139Z","shell.execute_reply.started":"2025-11-07T17:46:23.621121Z","shell.execute_reply":"2025-11-07T17:46:24.081231Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.describe()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:24.083830Z","iopub.execute_input":"2025-11-07T17:46:24.084084Z","iopub.status.idle":"2025-11-07T17:46:24.255043Z","shell.execute_reply.started":"2025-11-07T17:46:24.084067Z","shell.execute_reply":"2025-11-07T17:46:24.254323Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.describe(include='O')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:24.255756Z","iopub.execute_input":"2025-11-07T17:46:24.255992Z","iopub.status.idle":"2025-11-07T17:46:25.349523Z","shell.execute_reply.started":"2025-11-07T17:46:24.255975Z","shell.execute_reply":"2025-11-07T17:46:25.348828Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.isnull().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:25.350263Z","iopub.execute_input":"2025-11-07T17:46:25.350488Z","iopub.status.idle":"2025-11-07T17:46:25.789101Z","shell.execute_reply.started":"2025-11-07T17:46:25.350469Z","shell.execute_reply":"2025-11-07T17:46:25.788338Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.duplicated().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:25.789874Z","iopub.execute_input":"2025-11-07T17:46:25.790164Z","iopub.status.idle":"2025-11-07T17:46:26.625786Z","shell.execute_reply.started":"2025-11-07T17:46:25.790146Z","shell.execute_reply":"2025-11-07T17:46:26.625008Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# EDA (Exploratory Data Analysis)¶\n","metadata":{}},{"cell_type":"code","source":"# --- 1. Calculation (Fixes NameError) ---\n# Calculate the absolute counts of each target class (0 and 1)\ntarget_counts = y.value_counts()\ntotal_count = len(y)\n# Calculate the percentage distribution\ntarget_percentage = (target_counts / total_count) * 100\n\nprint(\"--- Target (y) Distribution Counts ---\")\nprint(target_counts)\nprint(\"\\n--- Target Class Percentage ---\")\nprint(target_percentage.round(2).astype(str) + '%')\n\n# --- 2. Visualization (Countplot) ---\nplt.figure(figsize=(6, 4))\n# Note: The 'palette' uses distinct colors for clear visualization.\nsns.countplot(x=y, palette=['#1f77b4', '#ff7f0e']) \nplt.title('Target Variable Distribution (Target: 0 and 1)', fontsize=14)\nplt.xlabel('Target Value')\nplt.ylabel('Count')\n\n# Adding the percentage directly above the bars\nfor i, count in enumerate(target_counts):\n    percentage = target_percentage.iloc[i]\n    # Placing the text slightly above the bar (count + 1000) for visibility.\n    plt.text(i, count + 1000, f'{percentage:.2f}%', \n             ha='center', va='bottom', fontsize=12)\n\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:26.626584Z","iopub.execute_input":"2025-11-07T17:46:26.626863Z","iopub.status.idle":"2025-11-07T17:46:26.816504Z","shell.execute_reply.started":"2025-11-07T17:46:26.626843Z","shell.execute_reply":"2025-11-07T17:46:26.815730Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Concatenate data for combined analysis\nfull_df = pd.concat([train_df, test_df], axis=0, ignore_index=True)\n\n# --- 2. Calculate and Filter Missing Data ---\n# Calculate the percentage of missing values for all columns\nmissing_percentage = full_df.isnull().mean() * 100\n\n# Filter to keep only columns with missing data and sort them\nmissing_data = missing_percentage[missing_percentage > 0].sort_values(ascending=False)\n\n# --- 3. Visualization and Output ---\nif not missing_data.empty:\n    plt.figure(figsize=(10, 8))\n    \n    # Plotting the missing percentage for all relevant features\n    sns.barplot(x=missing_data.values, y=missing_data.index, palette=\"viridis\")\n\n    plt.title('Percentage of Missing Values Per Feature', fontsize=16)\n    plt.xlabel('Missing Percentage (%)', fontsize=12)\n    plt.ylabel('Features', fontsize=12)\n    plt.grid(axis='x', alpha=0.6) # Added slight transparency to the grid\n    plt.tight_layout()\n    plt.show()\n    \n    print(\"\\n--- Top Missing Features ---\")\n    # Display the top features and their missing percentage\n    print(missing_data.head(10).apply(lambda x: f\"{x:.2f}%\").to_string())\nelse:\n    print(\"No missing values found in the combined dataset.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:26.817351Z","iopub.execute_input":"2025-11-07T17:46:26.817597Z","iopub.status.idle":"2025-11-07T17:46:28.262610Z","shell.execute_reply.started":"2025-11-07T17:46:26.817569Z","shell.execute_reply":"2025-11-07T17:46:28.261895Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Assuming 'train_eda' (full original train_df) is available\n\n# Recalculate train_eda just to be safe (if run standalone)\ntrain_eda = pd.read_csv(BASE_PATH + 'train.csv')\n\n\nprint(\"--- 3. Ordinal Features (ord_2) vs. Target Rate ---\")\n\n# Calculate P(Target=1) for each category in ord_2\ntarget_rate_ord2 = train_eda.groupby('ord_2')['target'].mean().sort_values()\n\nplt.figure(figsize=(8, 5))\n# Plot the mean of the target, which is the probability P(Target=1)\ntarget_rate_ord2.plot(kind='bar', color='darkgreen')\nplt.title('Target Rate by Category: ord_2 (P(Target=1))', fontsize=14)\nplt.xlabel('ord_2 Categories (Ordered)')\nplt.ylabel('Probability of Target=1')\nplt.xticks(rotation=45, ha='right')\nplt.grid(axis='y', alpha=0.5)\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:28.265125Z","iopub.execute_input":"2025-11-07T17:46:28.265408Z","iopub.status.idle":"2025-11-07T17:46:29.934188Z","shell.execute_reply.started":"2025-11-07T17:46:28.265389Z","shell.execute_reply":"2025-11-07T17:46:29.933511Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Assuming 'train_df' is available (features only)\n\nprint(\"--- 4. Nominal Feature Cardinality ---\")\n\n# Select only nominal columns for cardinality check\nnominal_cols = [col for col in train_df.columns if 'nom_' in col]\ncardinality = train_df[nominal_cols].nunique().sort_values(ascending=False)\n\nplt.figure(figsize=(10, 6))\nsns.barplot(x=cardinality.index, y=cardinality.values, palette=\"rocket\")\nplt.title('Unique Values Count (Cardinality) for Nominal Features', fontsize=16)\nplt.xlabel('Nominal Features')\nplt.ylabel('Number of Unique Values')\nplt.xticks(rotation=45, ha='right')\nplt.grid(axis='y', alpha=0.6)\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:29.934821Z","iopub.execute_input":"2025-11-07T17:46:29.935009Z","iopub.status.idle":"2025-11-07T17:46:30.455997Z","shell.execute_reply.started":"2025-11-07T17:46:29.934994Z","shell.execute_reply":"2025-11-07T17:46:30.454953Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Assuming 'train_eda' (full original train_df) is available\n\nprint(\"--- 5. Cyclical Feature Impact (Monthly Rate) ---\")\n\n# Calculate the mean target rate for each month\nmonthly_target_rate = train_eda.groupby('month')['target'].mean()\n\nplt.figure(figsize=(8, 5))\n# Use a line plot to show the cyclical nature\nmonthly_target_rate.plot(kind='line', marker='o', color='darkblue')\nplt.title('Average P(Target=1) Rate Across Months', fontsize=14)\nplt.xlabel('Month')\nplt.ylabel('Probability of Target=1')\nplt.xticks(range(1, 13)) # Ensure all months (1-12) are labeled\nplt.grid(True, linestyle='--', alpha=0.6)\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:30.456859Z","iopub.execute_input":"2025-11-07T17:46:30.457125Z","iopub.status.idle":"2025-11-07T17:46:30.718031Z","shell.execute_reply.started":"2025-11-07T17:46:30.457105Z","shell.execute_reply":"2025-11-07T17:46:30.717037Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Feature Engineering¶\n","metadata":{}},{"cell_type":"code","source":"# --- 3. Feature Engineering ---\nprint(\"\\n--- 3. Feature Engineering ---\")\n\n# Concatenate data\nfull_df = pd.concat([train_df, test_df], axis=0, ignore_index=True)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:30.719004Z","iopub.execute_input":"2025-11-07T17:46:30.719461Z","iopub.status.idle":"2025-11-07T17:46:30.806920Z","shell.execute_reply.started":"2025-11-07T17:46:30.719440Z","shell.execute_reply":"2025-11-07T17:46:30.806202Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3.1: Handling Missing Values and Creating Indicators\nprint(\"--- 3.1: Handling Missing Values and Creating Indicators ---\")\nfor col in full_df.columns:\n    if full_df[col].isnull().any():\n        full_df[f'{col}_was_missing'] = full_df[col].isnull().astype(int)\n        \n        if pd.api.types.is_numeric_dtype(full_df[col]):\n            full_df[col] = full_df[col].fillna(-1)  \n        else:\n            full_df[col] = full_df[col].fillna('NONE')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:30.807548Z","iopub.execute_input":"2025-11-07T17:46:30.807729Z","iopub.status.idle":"2025-11-07T17:46:33.302347Z","shell.execute_reply.started":"2025-11-07T17:46:30.807714Z","shell.execute_reply":"2025-11-07T17:46:33.301726Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3.2: Ordinal Feature Encoding (ord_*)\nprint(\"--- 3.2: Ordinal Feature Encoding (ord_*) ---\")\nord_1_mapping = {'Novice': 1, 'Contributor': 2, 'Expert': 3, 'Master': 4, 'Grandmaster': 5, 'NONE': 0, -1: 0}\nord_2_mapping = {'Freezing': 1, 'Cold': 2, 'Warm': 3, 'Hot': 4, 'Boiling Hot': 5, 'Lava Hot': 6, 'NONE': 0, -1: 0}\n\nfull_df['ord_1'] = full_df['ord_1'].map(ord_1_mapping)\nfull_df['ord_2'] = full_df['ord_2'].map(ord_2_mapping)\n\nord_3_col = ['ord_3', 'ord_4', 'ord_5']\nfor col in ord_3_col:\n    # Use OrdinalEncoder after filling missing values\n    full_df[col] = full_df[col].replace('NONE', chr(ord('a') - 1)).fillna(chr(ord('a') - 1))\n    encoder = OrdinalEncoder(categories=[sorted(full_df[col].unique())], dtype=int)\n    full_df[col] = encoder.fit_transform(full_df[[col]])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:33.303238Z","iopub.execute_input":"2025-11-07T17:46:33.303416Z","iopub.status.idle":"2025-11-07T17:46:34.448020Z","shell.execute_reply.started":"2025-11-07T17:46:33.303402Z","shell.execute_reply":"2025-11-07T17:46:34.447316Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3.3: Frequency Encoding\nprint(\"--- 3.3: Frequency Encoding ---\")\nall_cat_cols = [col for col in full_df.columns if 'nom_' in col or 'bin_' in col or 'day' in col or 'month' in col]\nfor col in all_cat_cols:\n    freq_map = full_df[col].value_counts().to_dict()\n    full_df[f'{col}_freq'] = full_df[col].map(freq_map)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:34.448736Z","iopub.execute_input":"2025-11-07T17:46:34.449034Z","iopub.status.idle":"2025-11-07T17:46:36.155404Z","shell.execute_reply.started":"2025-11-07T17:46:34.449000Z","shell.execute_reply":"2025-11-07T17:46:36.154737Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3.4: Cyclical Feature Engineering\nprint(\"--- 3.4: Cyclical Feature Engineering (day, month) ---\")\nfull_df['day_sin'] = np.sin(2 * np.pi * full_df['day'] / 7.0)\nfull_df['day_cos'] = np.cos(2 * np.pi * full_df['day'] / 7.0)\nfull_df['month_sin'] = np.sin(2 * np.pi * full_df['month'] / 12.0)\nfull_df['month_cos'] = np.cos(2 * np.pi * full_df['month'] / 12.0)\nfull_df = full_df.drop(['day', 'month'], axis=1)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:36.156193Z","iopub.execute_input":"2025-11-07T17:46:36.156522Z","iopub.status.idle":"2025-11-07T17:46:36.577180Z","shell.execute_reply.started":"2025-11-07T17:46:36.156498Z","shell.execute_reply":"2025-11-07T17:46:36.576448Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3.5: Feature Interactions\nprint(\"--- 3.5: Feature Interactions ---\")\nfull_df['ord_1_nom_3'] = full_df['ord_1'].astype(str) + '_' + full_df['nom_3'].astype(str)\nfull_df['ord_1_ord_2'] = full_df['ord_1'].astype(str) + '_' + full_df['ord_2'].astype(str)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:36.577993Z","iopub.execute_input":"2025-11-07T17:46:36.578286Z","iopub.status.idle":"2025-11-07T17:46:37.594864Z","shell.execute_reply.started":"2025-11-07T17:46:36.578261Z","shell.execute_reply":"2025-11-07T17:46:37.594239Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3.6: Converting Categorical Columns to 'category' (for CatBoost)\nprint(\"--- 3.6: Converting Categorical Columns to 'category' ---\")\n# Ensure bin_x columns are string type before converting to category\nbinary_cols_to_fix = [col for col in full_df.columns if 'bin_' in col]\nfor col in binary_cols_to_fix:\n    full_df[col] = full_df[col].astype(str)\n\nnominal_cols = [col for col in full_df.columns if 'nom_' in col or 'bin_' in col]\ninteraction_cols = ['ord_1_nom_3', 'ord_1_ord_2']\nfor col in nominal_cols + interaction_cols:\n    full_df[col] = full_df[col].astype('category')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:37.595624Z","iopub.execute_input":"2025-11-07T17:46:37.595869Z","iopub.status.idle":"2025-11-07T17:46:44.778530Z","shell.execute_reply.started":"2025-11-07T17:46:37.595851Z","shell.execute_reply":"2025-11-07T17:46:44.777942Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Separate data back\nX = full_df.iloc[:len(train_df)]\nX_test = full_df.iloc[len(train_df):]","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define Categorical Columns for CatBoost\ncategorical_features = [col for col in X.columns if X[col].dtype.name == 'category']\nprint(f\"Total number of features: {len(X.columns)}\")\nprint(f\"Number of categorical features for CatBoost: {len(categorical_features)}\")\nprint(\"--- Feature Engineering completed. ---\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-07T17:46:59.073249Z","iopub.execute_input":"2025-11-07T17:46:59.073903Z","iopub.status.idle":"2025-11-07T17:46:59.095245Z","shell.execute_reply.started":"2025-11-07T17:46:59.073877Z","shell.execute_reply":"2025-11-07T17:46:59.094433Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Train ML model¶\n","metadata":{}},{"cell_type":"code","source":"## --- 4. Train ML Model (CatBoost Training) ---\nprint(\"\\n--- 4. Train ML Model (Training with CatBoost) ---\")\nprint(\"🔥 Using StratifiedKFold and GPU training (requires GPU environment).\")\n\n# CatBoost parameters definition\ncat_params = {\n    'iterations': 3000,\n    'learning_rate': 0.02,\n    'depth': 6,\n    'eval_metric': 'AUC',\n    'random_seed': 42,\n    'verbose': 0,\n    'early_stopping_rounds': 1000,\n    'task_type': 'GPU',     # Modification to enable GPU acceleration\n    'metric_period': 20     # Reduce number of output metric prints to minimize slowdown\n}\n\nN_SPLITS = 10\nskf = StratifiedKFold(n_splits=N_SPLITS, shuffle=True, random_state=42)\n\noof_preds_cat = np.zeros(len(X))\ntest_preds_cat = np.zeros(len(X_test))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training and Cross-Validation loop\nfor fold, (train_index, val_index) in enumerate(skf.split(X, y)):\n  \n    print(f\"\\n--- FOLD {fold + 1}/{N_SPLITS} ---\") \n    \n    X_train, X_val = X.iloc[train_index], X.iloc[val_index]\n    y_train, y_val = y.iloc[train_index], y.iloc[val_index]\n    \n    model_cat = CatBoostClassifier(**cat_params)\n    \n    model_cat.fit(X_train, y_train,\n                  eval_set=[(X_val, y_val)],\n                  cat_features=categorical_features,\n                  verbose=0\n                  )\n    \n    val_preds = model_cat.predict_proba(X_val)[:, 1]\n    oof_preds_cat[val_index] = val_preds\n    test_preds_cat += model_cat.predict_proba(X_test)[:, 1] / N_SPLITS\n    \n    print(f\"Fold {fold + 1} AUC: {roc_auc_score(y_val, val_preds):.6f}\")\n    \n        # The preceding code block calculates val_preds and roc_auc_score\n    print(f\"Fold {fold+1} AUC: {roc_auc_score(y_val, val_preds)}\")\n    \n \noverall_auc_cat = roc_auc_score(y, oof_preds_cat)\nprint(f\"\\n===================================\")\nprint(f\"Overall OOF AUC (CatBoost): {overall_auc_cat:.6f}\")\nprint(f\"===================================\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- 5. Submission (Creating Submission File) ---\nprint(\"\\n--- 5. Submission (Creating Submission File) ---\")\nsubmission_df_cat = pd.DataFrame({'id': test_ids, 'target': test_preds_cat})\nsubmission_df_cat.to_csv('submission.csv', index=False)\n\nprint(\"✅ 'submission.csv' file created successfully.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}