{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":17000,"databundleVersionId":895292,"sourceType":"competition"}],"dockerImageVersionId":30918,"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":"2025-03-26T11:31:44.411644Z","iopub.execute_input":"2025-03-26T11:31:44.411889Z","iopub.status.idle":"2025-03-26T11:31:45.545182Z","shell.execute_reply.started":"2025-03-26T11:31:44.411856Z","shell.execute_reply":"2025-03-26T11:31:45.543878Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ntrain = pd.read_csv(\"/kaggle/input/cat-in-the-dat-ii/train.csv\")\ndisplay(train.head())\ntrain.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-26T11:35:10.760730Z","iopub.execute_input":"2025-03-26T11:35:10.761074Z","iopub.status.idle":"2025-03-26T11:35:13.778443Z","shell.execute_reply.started":"2025-03-26T11:35:10.761049Z","shell.execute_reply":"2025-03-26T11:35:13.777405Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.isnull().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-26T11:35:39.795265Z","iopub.execute_input":"2025-03-26T11:35:39.795606Z","iopub.status.idle":"2025-03-26T11:35:40.301130Z","shell.execute_reply.started":"2025-03-26T11:35:39.795579Z","shell.execute_reply":"2025-03-26T11:35:40.300263Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.duplicated().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-26T11:36:27.214438Z","iopub.execute_input":"2025-03-26T11:36:27.214850Z","iopub.status.idle":"2025-03-26T11:36:28.137641Z","shell.execute_reply.started":"2025-03-26T11:36:27.214824Z","shell.execute_reply":"2025-03-26T11:36:28.136680Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Handle null by dropping it\ntrain_clean = train.dropna(ignore_index=True)\ntrain_clean.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-26T11:37:57.802529Z","iopub.execute_input":"2025-03-26T11:37:57.802960Z","iopub.status.idle":"2025-03-26T11:37:58.599031Z","shell.execute_reply.started":"2025-03-26T11:37:57.802927Z","shell.execute_reply":"2025-03-26T11:37:58.597577Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for col in train_clean.columns:\n    print(f\"{col} - {len(train_clean[col].value_counts())}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-26T11:40:13.252966Z","iopub.execute_input":"2025-03-26T11:40:13.253364Z","iopub.status.idle":"2025-03-26T11:40:13.678165Z","shell.execute_reply.started":"2025-03-26T11:40:13.253335Z","shell.execute_reply":"2025-03-26T11:40:13.677028Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport scipy.stats as stats\n\n# import dataset\ntrain = pd.read_csv(\"/kaggle/input/cat-in-the-dat-ii/train.csv\")\n\n# Handle null by dropping it\ntrain_clean = train.dropna(ignore_index=True)\n\n# Computes Cramér’s V statistic to measure association between categorical features\ndef cramers_v(cat_feature, target):\n    \"\"\"Computes Cramér’s V statistic to measure association between categorical features.\"\"\"\n    confusion_matrix = pd.crosstab(cat_feature, target)\n    chi2 = stats.chi2_contingency(confusion_matrix)[0]\n    n = confusion_matrix.sum().sum()\n    r, k = confusion_matrix.shape\n    return np.sqrt(chi2 / (n * (min(r, k) - 1)))\n\n\nprint(\"Biggest Cramer'V in train\\n-------------------------\")\nlfeat = [v for v in list(train_clean.columns) if v not in [\"id\", \"target\"]]\ndone=[]\nfor v1 in lfeat:\n    done.append(v1)\n    for v2 in [v for v in lfeat if v not in done]:\n        c = cramers_v(train_clean[v1], train_clean[v2])\n        if c > 0.08:\n            print(\"{}, {}, {:.5f}\".format(v1, v2, c))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-26T11:49:31.751800Z","iopub.execute_input":"2025-03-26T11:49:31.752151Z","iopub.status.idle":"2025-03-26T11:50:29.789964Z","shell.execute_reply.started":"2025-03-26T11:49:31.752124Z","shell.execute_reply":"2025-03-26T11:50:29.789106Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"It seems that there are no correlation between features, so a linear model may performs well for this task.","metadata":{}},{"cell_type":"code","source":"# Computes Cramér’s V statistic to measure association between categorical features and target\nres = {}\nfor col in train_clean.columns:\n    if col not in ['id', 'target']:\n        c = cramers_v(train_clean[col], train_clean['target'])\n        res[col] = round(c, 5)\n\nsorted_res = dict(sorted(res.items(), key=lambda item: item[1], reverse=True))\nprint(\"Biggest Cramer'V in train\\n-------------------------\")\nfor col, val in sorted_res.items():\n    print(f\"{col} - {val}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-26T11:50:29.791376Z","iopub.execute_input":"2025-03-26T11:50:29.791794Z","iopub.status.idle":"2025-03-26T11:50:30.797679Z","shell.execute_reply.started":"2025-03-26T11:50:29.791754Z","shell.execute_reply":"2025-03-26T11:50:30.796623Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"bin_3 has lower score, so we can drop this column","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport pandas as pd\nimport numpy as np\n\n# import dataset\ntrain = pd.read_csv(\"/kaggle/input/cat-in-the-dat-ii/train.csv\")\n\ndef color_and_top(nb_mod, feature, typ, top_n=None):\n    if top_n is None:\n        resu = [\"g\", nb_mod]\n    elif nb_mod > 2 * top_n:\n        resu = [\"r\", top_n]\n    elif nb_mod > top_n:\n        resu = [\"orange\", top_n]\n    else:\n        resu = [\"g\", nb_mod]\n    \n    title = feature[:20] + \" (\" + typ[:3] + \"-{})\".format(nb_mod)\n    resu.append(title)\n    \n    return resu\n\n\ndef plot_multiple_categorical(df, features, col_target=None, top_n=None,\n                              nb_subplots_per_row=4, hspace=1.3, wspace=0.5,\n                              figheight=15, m_figwidth=4.2, landmark=0.01):\n    \n    if col_target is not None:\n        ref = df[col_target].mean()  # Reference\n    \n    plt.figure()\n    if len(features) % nb_subplots_per_row > 0:\n        nb_rows = int(np.floor(len(features) / nb_subplots_per_row) + 1)\n    else:\n        nb_rows = int(np.floor(len(features) / nb_subplots_per_row))\n    \n    fig, ax = plt.subplots(nb_rows, nb_subplots_per_row, figsize=(figheight, m_figwidth * nb_rows))\n    plt.subplots_adjust(hspace=hspace, wspace=wspace)\n    \n    i = 0\n    n_row = 0\n    n_col = 0\n    \n    for feature in features:\n        i += 1\n        plt.subplot(nb_rows, nb_subplots_per_row, i)\n        \n        dff = df[[feature, col_target]].copy()\n        \n        # Handling missing values\n        if dff[feature].dtype.name in [\"float16\", \"float32\", \"float64\"]:\n            dff[feature] = dff[feature].fillna(-997)\n        \n        if dff[feature].dtype.name == \"object\":\n            dff[feature] = dff[feature].fillna(\"_NaN\")\n        \n        if dff[feature].dtype.name == \"category\" and dff[feature].isnull().sum() > 0:\n            dff[feature] = dff[feature].astype(str).replace('', '_NaN', regex=False).astype(\"category\")\n        \n        # Colors and title\n        bar_colr, top_nf, title = color_and_top(dff[feature].nunique(), feature, str(dff[feature].dtype), top_n)\n        \n        # Stats\n        tdf = dff.groupby([feature]).agg({col_target: ['count', 'mean']})\n        tdf = tdf.sort_values((col_target, 'count'), ascending=False).head(top_nf).sort_index()\n        \n        tdf.index = tdf.index.map(str)\n        tdf = tdf.rename(index={'-997.0': 'NaN'})\n        \n        if top_n is not None:\n            tdf = tdf.head(top_nf)\n        \n        tdf[\"ref\"] = ref\n        tdf[\"ref-\"] = ref - landmark\n        tdf[\"ref+\"] = ref + landmark\n        \n        # Bar plot for count\n        plt.bar(tdf.index, tdf[col_target]['count'].values, color=bar_colr)\n        \n        plt.title(title, fontsize=11)\n        plt.xticks(rotation=90)\n        \n        # Line plot for mean\n        xx = plt.xlim()\n        if nb_subplots_per_row == 1:\n            ax2 = fig.add_subplot(nb_rows, nb_subplots_per_row, i, sharex=ax[n_row, n_col], frameon=False)\n        else:\n            ax2 = fig.add_subplot(nb_rows, nb_subplots_per_row, i, sharex=ax[n_row, n_col], frameon=False)\n        \n        if col_target is not None:\n            ax2.plot(tdf[col_target]['mean'].values, marker='x', color='b', linestyle=\"solid\")\n            ax2.plot(tdf[\"ref\"].values, marker='_', color='black', linestyle=\"solid\", linewidth=4.0)\n            ax2.plot(tdf[\"ref-\"].values, marker='_', color='black', linestyle=\"solid\", linewidth=1.0)\n            ax2.plot(tdf[\"ref+\"].values, marker='_', color='black', linestyle=\"solid\", linewidth=1.0)\n        \n        ax2.yaxis.tick_right()\n        ax2.axes.get_xaxis().set_visible(False)\n        plt.xlim(xx)\n        \n        n_col += 1\n        if n_col == nb_subplots_per_row:\n            n_col = 0\n            n_row += 1\n    \n    plt.show()\n\n# Call the plotting function\nplot_multiple_categorical(\n    train_clean,\n    features=[col for col in train.columns if col not in ['id', 'target']],  # List of features to plot\n    col_target='target',                # Target variable\n    top_n=17,                            # Top 3 categories to display for each feature\n    nb_subplots_per_row=2,              # 2 subplots per row\n    figheight=10,                       # Height of the figure\n    m_figwidth=4,                       # Width of the figure\n    landmark=0.01                       # Deviation for reference lines\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-26T11:56:59.772656Z","iopub.execute_input":"2025-03-26T11:56:59.773021Z","iopub.status.idle":"2025-03-26T11:57:08.843516Z","shell.execute_reply.started":"2025-03-26T11:56:59.772993Z","shell.execute_reply":"2025-03-26T11:57:08.842120Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.compose import make_column_transformer\nfrom sklearn.model_selection import StratifiedKFold, cross_validate, train_test_split\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.metrics import roc_auc_score, accuracy_score\nimport pandas as pd\n\ntrain = pd.read_csv(\"/kaggle/input/cat-in-the-dat-ii/train.csv\")\n\ntrain_clean = train.dropna(ignore_index=True)\n\n# Define features (X) and target (y)\nX = train_clean.drop(columns=['id', 'target', 'bin_3'])\ny = train_clean['target']\n\n# Split\nX_train, X_test, y_train, y_test = train_test_split(X, y, shuffle=True, random_state=4)\n\n# Define the preprocessor for OneHotEncoding categorical variables\npreprocessor = make_column_transformer(\n    (OneHotEncoder(categories='auto', sparse_output=True, dtype='uint8', handle_unknown=\"ignore\"), [f for f in X.columns]),  # Exclude target' columns\n    remainder='passthrough'  # Keep the other columns (numeric columns) as they are\n)\n\n# Create a pipeline with preprocessor and logistic regression\npipe = Pipeline(steps=[\n    ('preprocessor', preprocessor),\n    ('logreg', LogisticRegression(C= 0.123456789, max_iter=500))\n])\n\n# Define cross-validation strategy\ncv = StratifiedKFold(n_splits=5, shuffle=True, random_state=4)\n\n# Perform cross-validation and get the scores\nscores = cross_validate(pipe, X_train, y_train, cv=cv, scoring=\"roc_auc\", return_train_score=True)\ncv_score = scores[\"test_score\"].mean()\n\nprint(f\"Cross-validation AUC score: {cv_score:.7f}\")\n\n# Eval on the test-set\n# Fit the model on the training data (it has already been done during cross-validation)\npipe.fit(X_train, y_train)\n\n# Make predictions on the test set\ny_pred_test = pipe.predict(X_test)  # Predicted labels\ny_pred_prob = pipe.predict_proba(X_test)[:, 1]  # Predicted probabilities for the positive class (if binary classification)\n\n# Step 3: Evaluate the model on the test set using ROC AUC and accuracy\nroc_auc = roc_auc_score(y_test, y_pred_prob)  # ROC AUC score\n\n# Print the results\nprint(f\"Test ROC AUC score: {roc_auc:.7f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-26T12:12:10.628755Z","iopub.execute_input":"2025-03-26T12:12:10.629215Z","iopub.status.idle":"2025-03-26T12:13:08.909468Z","shell.execute_reply.started":"2025-03-26T12:12:10.629183Z","shell.execute_reply":"2025-03-26T12:13:08.908516Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load test set\ntest = pd.read_csv(\"/kaggle/input/cat-in-the-dat-ii/test.csv\")\nX_test_final = test.drop(columns=['id', 'bin_3'])\n\nX = train_clean.drop(columns=['id', 'target', 'bin_3'])\ny = train_clean['target']\n\n# Fit Model\npipe.fit(X, y)\n\n# Make predictions with probabilities (roc_auc is based on probabilities)\ny_pred_proba_test = pipe.predict_proba(X_test_final)[:, 1]  # Get probability of class 1\n\n# Prepare the submission dataframe with the ID and predicted target (probability)\nsubmission = pd.DataFrame({'id': test['id'], 'target': y_pred_proba_test})\n\n# Save the submission to a CSV file\nsubmission.to_csv('submission.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-26T11:58:22.955439Z","iopub.execute_input":"2025-03-26T11:58:22.955823Z","iopub.status.idle":"2025-03-26T11:58:40.851969Z","shell.execute_reply.started":"2025-03-26T11:58:22.955792Z","shell.execute_reply":"2025-03-26T11:58:40.850918Z"}},"outputs":[],"execution_count":null}]}