{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":35332,"databundleVersionId":3723648,"sourceType":"competition"},{"sourceId":3727003,"sourceType":"datasetVersion","datasetId":2213609},{"sourceId":3739819,"sourceType":"datasetVersion","datasetId":2231132},{"sourceId":7453542,"sourceType":"datasetVersion","datasetId":921302}],"dockerImageVersionId":30198,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Acknowledgment","metadata":{}},{"cell_type":"markdown","source":"- AMEX PyTorch NN: Training [link](https://www.kaggle.com/code/voix97/amex-pytorch-nn-training)\n- AMEX - TabNet training  [link](https://www.kaggle.com/code/hinepo/amex-tabnet-training)\n- Optiver Volatility Predictions Using TabNet [link](https://www.kaggle.com/code/datafan07/optiver-volatility-predictions-using-tabnet)\n\nIf this notebook is helpful, feel free to upvote :)","metadata":{}},{"cell_type":"markdown","source":"# Importing Libraries","metadata":{}},{"cell_type":"code","source":"!pip -q install ../input/pytorchtabnet/pytorch_tabnet-3.1.1-py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2025-11-13T10:43:00.446033Z","iopub.execute_input":"2025-11-13T10:43:00.446568Z","iopub.status.idle":"2025-11-13T10:43:09.545644Z","shell.execute_reply.started":"2025-11-13T10:43:00.446479Z","shell.execute_reply":"2025-11-13T10:43:09.544718Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport random\nimport time\nimport pickle\nimport psutil\nimport gc\n\n\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nfrom sklearn.preprocessing import OrdinalEncoder, OneHotEncoder\nfrom sklearn.model_selection import KFold, StratifiedKFold\n\nimport torch\nfrom pytorch_tabnet.tab_model import TabNetClassifier\nfrom pytorch_tabnet.metrics import Metric\n\n# setting some globl config\n\nplt.style.use('ggplot')\norange_black = [\n    '#fdc029', '#df861d', '#FF6347', '#aa3d01', '#a30e15', '#800000', '#171820'\n]\nplt.rcParams['figure.figsize'] = (16,9)\nplt.rcParams[\"figure.facecolor\"] = '#FFFACD'\nplt.rcParams[\"axes.facecolor\"] = '#FFFFE0'\nplt.rcParams[\"axes.grid\"] = True\nplt.rcParams[\"grid.color\"] = orange_black[3]\nplt.rcParams[\"grid.alpha\"] = 0.5\nplt.rcParams[\"grid.linestyle\"] = '--'\n\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nINFERENCE = True","metadata":{"execution":{"iopub.status.busy":"2025-11-13T10:43:09.547355Z","iopub.execute_input":"2025-11-13T10:43:09.547653Z","iopub.status.idle":"2025-11-13T10:43:11.657836Z","shell.execute_reply.started":"2025-11-13T10:43:09.547626Z","shell.execute_reply":"2025-11-13T10:43:11.657134Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Loading & Data Processing","metadata":{}},{"cell_type":"code","source":"%%time\nfeatures_avg = ['B_11', 'B_13', 'B_14', 'B_15', 'B_16', 'B_17', 'B_18', 'B_19', 'B_2', \n                'B_20', 'B_28', 'B_29', 'B_3', 'B_33', 'B_36', 'B_37', 'B_4', 'B_42', \n                'B_5', 'B_8', 'B_9', 'D_102', 'D_103', 'D_105', 'D_111', 'D_112', 'D_113', \n                'D_115', 'D_118', 'D_119', 'D_121', 'D_124', 'D_128', 'D_129', 'D_131', \n                'D_132', 'D_133', 'D_139', 'D_140', 'D_141', 'D_143', 'D_144', 'D_145', \n                'D_39', 'D_41', 'D_42', 'D_43', 'D_44', 'D_45', 'D_46', 'D_47', 'D_48', \n                'D_49', 'D_50', 'D_51', 'D_52', 'D_56', 'D_58', 'D_62', 'D_70', 'D_71', \n                'D_72', 'D_74', 'D_75', 'D_79', 'D_81', 'D_83', 'D_84', 'D_88', 'D_91', \n                'P_2', 'P_3', 'R_1', 'R_10', 'R_11', 'R_13', 'R_18', 'R_19', 'R_2', 'R_26', \n                'R_27', 'R_28', 'R_3', 'S_11', 'S_12', 'S_22', 'S_23', 'S_24', 'S_26', \n                'S_27', 'S_5', 'S_7', 'S_8', ]\nfeatures_min = ['B_13', 'B_14', 'B_15', 'B_16', 'B_17', 'B_19', 'B_2', 'B_20', 'B_22', \n                'B_24', 'B_27', 'B_28', 'B_29', 'B_3', 'B_33', 'B_36', 'B_4', 'B_42', \n                'B_5', 'B_9', 'D_102', 'D_103', 'D_107', 'D_109', 'D_110', 'D_111', \n                'D_112', 'D_113', 'D_115', 'D_118', 'D_119', 'D_121', 'D_122', 'D_128', \n                'D_129', 'D_132', 'D_133', 'D_139', 'D_140', 'D_141', 'D_143', 'D_144', \n                'D_145', 'D_39', 'D_41', 'D_42', 'D_45', 'D_46', 'D_48', 'D_50', 'D_51', \n                'D_53', 'D_54', 'D_55', 'D_56', 'D_58', 'D_59', 'D_60', 'D_62', 'D_70', \n                'D_71', 'D_74', 'D_75', 'D_78', 'D_79', 'D_81', 'D_83', 'D_84', 'D_86', \n                'D_88', 'D_96', 'P_2', 'P_3', 'P_4', 'R_1', 'R_11', 'R_13', 'R_17', 'R_19', \n                'R_2', 'R_27', 'R_28', 'R_4', 'R_5', 'R_8', 'S_11', 'S_12', 'S_23', 'S_25', \n                'S_3', 'S_5', 'S_7', 'S_9', ]\nfeatures_max = ['B_1', 'B_11', 'B_13', 'B_15', 'B_16', 'B_17', 'B_18', 'B_19', 'B_2', \n                'B_22', 'B_24', 'B_27', 'B_28', 'B_29', 'B_3', 'B_31', 'B_33', 'B_36', \n                'B_4', 'B_42', 'B_5', 'B_7', 'B_9', 'D_102', 'D_103', 'D_105', 'D_109', \n                'D_110', 'D_112', 'D_113', 'D_115', 'D_121', 'D_124', 'D_128', 'D_129', \n                'D_131', 'D_139', 'D_141', 'D_144', 'D_145', 'D_39', 'D_41', 'D_42', \n                'D_43', 'D_44', 'D_45', 'D_46', 'D_47', 'D_48', 'D_50', 'D_51', 'D_52', \n                'D_53', 'D_56', 'D_58', 'D_59', 'D_60', 'D_62', 'D_70', 'D_72', 'D_74', \n                'D_75', 'D_79', 'D_81', 'D_83', 'D_84', 'D_88', 'D_89', 'P_2', 'P_3', \n                'R_1', 'R_10', 'R_11', 'R_26', 'R_28', 'R_3', 'R_4', 'R_5', 'R_7', 'R_8', \n                'S_11', 'S_12', 'S_23', 'S_25', 'S_26', 'S_27', 'S_3', 'S_5', 'S_7', 'S_8', ]\nfeatures_last = ['B_1', 'B_11', 'B_12', 'B_13', 'B_14', 'B_16', 'B_18', 'B_19', 'B_2', \n                 'B_20', 'B_21', 'B_24', 'B_27', 'B_28', 'B_29', 'B_3', 'B_30', 'B_31', \n                 'B_33', 'B_36', 'B_37', 'B_38', 'B_39', 'B_4', 'B_40', 'B_42', 'B_5', \n                 'B_8', 'B_9', 'D_102', 'D_105', 'D_106', 'D_107', 'D_108', 'D_110', \n                 'D_111', 'D_112', 'D_113', 'D_114', 'D_115', 'D_116', 'D_117', 'D_118', \n                 'D_119', 'D_120', 'D_121', 'D_124', 'D_126', 'D_128', 'D_129', 'D_131', \n                 'D_132', 'D_133', 'D_137', 'D_138', 'D_139', 'D_140', 'D_141', 'D_142', \n                 'D_143', 'D_144', 'D_145', 'D_39', 'D_41', 'D_42', 'D_43', 'D_44', 'D_45', \n                 'D_46', 'D_47', 'D_48', 'D_49', 'D_50', 'D_51', 'D_52', 'D_53', 'D_55', \n                 'D_56', 'D_59', 'D_60', 'D_62', 'D_63', 'D_64', 'D_66', 'D_68', 'D_70', \n                 'D_71', 'D_72', 'D_73', 'D_74', 'D_75', 'D_77', 'D_78', 'D_81', 'D_82', \n                 'D_83', 'D_84', 'D_88', 'D_89', 'D_91', 'D_94', 'D_96', 'P_2', 'P_3', \n                 'P_4', 'R_1', 'R_10', 'R_11', 'R_12', 'R_13', 'R_16', 'R_17', 'R_18', \n                 'R_19', 'R_25', 'R_28', 'R_3', 'R_4', 'R_5', 'R_8', 'S_11', 'S_12', \n                 'S_23', 'S_25', 'S_26', 'S_27', 'S_3', 'S_5', 'S_7', 'S_8', 'S_9', ]\nfeatures_categorical = ['B_30_last', 'B_38_last', 'D_114_last', 'D_116_last',\n                        'D_117_last', 'D_120_last', 'D_126_last',\n                        'D_63_last', 'D_64_last', 'D_66_last', 'D_68_last']\n\nfor i in [0, 1] if INFERENCE else [0]:\n    # i == 0 -> process the train data\n    # i == 1 -> process the test data\n    df = pd.read_feather(['../input/amexfeather/train_data.ftr',\n                          '../input/amexfeather/test_data.ftr'][i])\n    cid = pd.Categorical(df.pop('customer_ID'), ordered=True)\n    last = (cid != np.roll(cid, -1)) # mask for last statement of every customer\n    if i == 0: # train\n        target = df.loc[last, 'target']\n    print('Read', i)\n    gc.collect()\n    df_avg = (df\n              .groupby(cid)\n              .mean()[features_avg]\n              .rename(columns={f: f\"{f}_avg\" for f in features_avg})\n             )\n    print('Computed avg', i)\n    gc.collect()\n    df_max = (df\n              .groupby(cid)\n              .max()[features_max]\n              .rename(columns={f: f\"{f}_max\" for f in features_max})\n             )\n    print('Computed max', i)\n    gc.collect()\n    df_min = (df\n              .groupby(cid)\n              .min()[features_min]\n              .rename(columns={f: f\"{f}_min\" for f in features_min})\n             )\n    print('Computed min', i)\n    gc.collect()\n    df_last = (df.loc[last, features_last]\n               .rename(columns={f: f\"{f}_last\" for f in features_last})\n               .set_index(np.asarray(cid[last]))\n              )\n    df = None # we no longer need the original data\n    print('Computed last', i)\n    \n    df_categorical = df_last[features_categorical].astype(object)\n    features_not_cat = [f for f in df_last.columns if f not in features_categorical]\n    if i == 0: # train\n        ohe = OneHotEncoder(drop='first', sparse=False, dtype=np.float32, handle_unknown='ignore')\n        ohe.fit(df_categorical)\n        with open(\"ohe.pickle\", 'wb') as f: pickle.dump(ohe, f)\n    df_categorical = pd.DataFrame(ohe.transform(df_categorical).astype(np.float16),\n                                  index=df_categorical.index).rename(columns=str)\n    print('Computed categorical', i)\n    \n    df = pd.concat([df_last[features_not_cat], df_categorical, df_avg, df_min, df_max], axis=1)\n    \n    # Impute missing values\n    df.fillna(value=0, inplace=True)\n    \n    del df_avg, df_max, df_min, df_last, df_categorical, cid, last, features_not_cat\n    \n    if i == 0: # train\n        # Free the memory\n        df.reset_index(drop=True, inplace=True) # frees 0.2 GByte\n        df.to_feather('train_processed.ftr')\n        df = None\n        gc.collect()\n\ntrain = pd.read_feather('train_processed.ftr')\ntest = df\ntarget = target.reset_index(drop=True)\ndel df, ohe\n\nprint('Shapes:', train.shape, target.shape)","metadata":{"execution":{"iopub.status.busy":"2025-11-13T10:43:11.658850Z","iopub.execute_input":"2025-11-13T10:43:11.659359Z","iopub.status.idle":"2025-11-13T10:46:29.495352Z","shell.execute_reply.started":"2025-11-13T10:43:11.659333Z","shell.execute_reply":"2025-11-13T10:46:29.494448Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Configuration","metadata":{}},{"cell_type":"code","source":"class CFG:\n    DEBUG = False\n    model = 'tabnet'\n    N_folds = 5\n    seed = 42\n    batch_size = 512\n    max_epochs = 60","metadata":{"execution":{"iopub.status.busy":"2025-11-13T10:46:29.496831Z","iopub.execute_input":"2025-11-13T10:46:29.497192Z","iopub.status.idle":"2025-11-13T10:46:29.501292Z","shell.execute_reply.started":"2025-11-13T10:46:29.497167Z","shell.execute_reply":"2025-11-13T10:46:29.500479Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n\nseed_everything(seed = CFG.seed)","metadata":{"execution":{"iopub.status.busy":"2025-11-13T10:46:29.502266Z","iopub.execute_input":"2025-11-13T10:46:29.502559Z","iopub.status.idle":"2025-11-13T10:46:29.515131Z","shell.execute_reply.started":"2025-11-13T10:46:29.502535Z","shell.execute_reply":"2025-11-13T10:46:29.514272Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"psutil.virtual_memory().percent","metadata":{"execution":{"iopub.status.busy":"2025-11-13T10:46:29.516215Z","iopub.execute_input":"2025-11-13T10:46:29.516573Z","iopub.status.idle":"2025-11-13T10:46:29.529573Z","shell.execute_reply.started":"2025-11-13T10:46:29.516541Z","shell.execute_reply":"2025-11-13T10:46:29.528921Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Setting Metric","metadata":{}},{"cell_type":"code","source":"def amex_metric_numpy(y_true: np.array, y_pred: np.array) -> float:\n\n    # count of positives and negatives\n    n_pos = y_true.sum()\n    n_neg = y_true.shape[0] - n_pos\n\n    # sorting by descring prediction values\n    indices = np.argsort(y_pred)[::-1]\n    preds, target = y_pred[indices], y_true[indices]\n\n    # filter the top 4% by cumulative row weights\n    weight = 20.0 - target * 19.0\n    cum_norm_weight = (weight / weight.sum()).cumsum()\n    four_pct_filter = cum_norm_weight <= 0.04\n\n    # default rate captured at 4%\n    d = target[four_pct_filter].sum() / n_pos\n\n    # weighted gini coefficient\n    lorentz = (target / n_pos).cumsum()\n    gini = ((lorentz - cum_norm_weight) * weight).sum()\n\n    # max weighted gini coefficient\n    gini_max = 10 * n_neg * (1 - 19 / (n_pos + 20 * n_neg))\n\n    # normalized weighted gini coefficient\n    g = gini / gini_max\n\n    return 0.5 * (g + d)","metadata":{"execution":{"iopub.status.busy":"2025-11-13T10:46:29.530595Z","iopub.execute_input":"2025-11-13T10:46:29.530951Z","iopub.status.idle":"2025-11-13T10:46:29.544286Z","shell.execute_reply.started":"2025-11-13T10:46:29.530918Z","shell.execute_reply":"2025-11-13T10:46:29.543555Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# using amex metric to evaluate tabnet\nclass Amex_tabnet(Metric):\n    \n  def __init__(self):\n    self._name = 'amex_tabnet'\n    self._maximize = True\n\n  def __call__(self, y_true, y_pred):\n    amex = amex_metric_numpy(y_true, y_pred[:, 1])\n    return max(amex, 0.)","metadata":{"execution":{"iopub.status.busy":"2025-11-13T10:46:29.545252Z","iopub.execute_input":"2025-11-13T10:46:29.545866Z","iopub.status.idle":"2025-11-13T10:46:29.558594Z","shell.execute_reply.started":"2025-11-13T10:46:29.545811Z","shell.execute_reply":"2025-11-13T10:46:29.557876Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Training + Inference","metadata":{}},{"cell_type":"code","source":"print('\\n ', '-'*50)\nprint('\\nTraining: ', CFG.model)\nprint('\\n ', '-'*50)\n\nprint('\\nSeed: ', CFG.seed)\nprint('N folds: ', CFG.N_folds)\nprint('train shape: ', train.shape)\nprint('targets shape: ', target.shape)\n\n\nprint('\\nN features: ', len(train.columns.values.tolist()))\nprint('\\n')\n\n# Create out of folds array\noof_predictions = np.zeros((train.shape[0]))\ntest_predictions = np.zeros(test.shape[0])\nfeature_importances = pd.DataFrame()\nfeature_importances[\"feature\"] = train.columns.tolist()\nstats = pd.DataFrame()\nexplain_matrices = []\nmasks_ =[]\n\n\n    \nkfold = StratifiedKFold(n_splits = CFG.N_folds, shuffle=True, random_state = CFG.seed)\n\nfor fold, (train_idx, valid_idx) in enumerate(kfold.split(train, target)):\n\n    ## DEBUG MODE\n    if CFG.DEBUG == True:\n        if fold > 0:\n            print('\\nDEBUG mode activated: Will train only one fold...\\n')\n            break      \n\n    start = time.time()\n\n    X_train, y_train = train.loc[train_idx], target.loc[train_idx]\n    X_valid, y_valid = train.loc[valid_idx], target.loc[valid_idx]        \n        \n    model = TabNetClassifier(n_d = 32,\n                             n_a = 32,\n                             n_steps = 3,\n                             gamma = 1.3,\n                             n_independent = 2,\n                             n_shared = 2,\n                             momentum = 0.02,\n                             clip_value = None,\n                             lambda_sparse = 1e-3,\n                             optimizer_fn = torch.optim.Adam,\n                             optimizer_params = dict(lr = 1e-3, weight_decay=1e-3),\n                             scheduler_fn = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts,\n                             scheduler_params = {'T_0':5,\n                                                 'eta_min':1e-4,\n                                                 'T_mult':1,\n                                                 'last_epoch':-1},\n                             mask_type = 'entmax',\n                             seed = CFG.seed)\n    \n    \n\n    ## train\n    model.fit(np.array(X_train),\n              np.array(y_train.values.ravel()),\n              eval_set = [(np.array(X_valid), np.array(y_valid.values.ravel()))],\n              max_epochs = CFG.max_epochs,\n              patience = 50,\n              batch_size = CFG.batch_size,\n              eval_metric = ['auc', 'accuracy', Amex_tabnet]) # Last metric is used for early stopping\n    \n    # Saving best model\n    saving_path_name = f\"./fold{fold}\"\n    saved_filepath = model.save_model(saving_path_name)\n    \n    # model explanability\n    explain_matrix, masks = model.explain(X_valid.values)\n    explain_matrices.append(explain_matrix)\n    masks_.append(masks[0])\n    masks_.append(masks[1])\n    \n    # Inference\n    oof_predictions[valid_idx] = model.predict_proba(X_valid.values)[:, 1]\n    \n    #if CFG\n    # logodds function\n    \n    test_predictions += model.predict_proba(test.values)[:, 1]/5\n    feature_importances[f\"importance_fold{fold}+1\"] = model.feature_importances_\n    \n    # Loss , metric tracking\n    stats[f'fold{fold+1}_train_loss'] = model.history['loss']\n    stats[f'fold{fold+1}_val_metric'] = model.history['val_0_amex_tabnet']\n\n\n    end = time.time()\n    time_delta = np.round((end - start)/60, 2)\n     \n    print(f'\\nFold {fold+1}/{CFG.N_folds} | {time_delta:.2f} min')\n\n    ### free memory\n    del X_train, y_train\n    del X_valid, y_valid\n    gc.collect()\n\nprint(f'OOF score across folds: {amex_metric_numpy(target, oof_predictions.flatten())}')","metadata":{"execution":{"iopub.status.busy":"2025-11-13T10:46:29.559807Z","iopub.execute_input":"2025-11-13T10:46:29.560132Z","iopub.status.idle":"2025-11-13T11:35:11.797266Z","shell.execute_reply.started":"2025-11-13T10:46:29.560068Z","shell.execute_reply":"2025-11-13T11:35:11.795515Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Train loss","metadata":{}},{"cell_type":"code","source":"for i in stats.filter(like='train', axis=1).columns.tolist():\n    plt.plot(stats[i], label=str(i))\nplt.title('Train loss')\nplt.legend()  ","metadata":{"execution":{"iopub.status.busy":"2025-11-13T11:35:20.647663Z","iopub.execute_input":"2025-11-13T11:35:20.648019Z","iopub.status.idle":"2025-11-13T11:35:20.903632Z","shell.execute_reply.started":"2025-11-13T11:35:20.647991Z","shell.execute_reply":"2025-11-13T11:35:20.902828Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Val amex metric","metadata":{}},{"cell_type":"code","source":"for i in stats.filter(like='val', axis=1).columns.tolist():\n    plt.plot(stats[i], label=str(i))\nplt.title('Train RMSPE')\nplt.legend() ","metadata":{"execution":{"iopub.status.busy":"2025-11-13T11:35:25.054851Z","iopub.execute_input":"2025-11-13T11:35:25.055230Z","iopub.status.idle":"2025-11-13T11:35:25.300906Z","shell.execute_reply.started":"2025-11-13T11:35:25.055203Z","shell.execute_reply":"2025-11-13T11:35:25.300130Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Feature Importances","metadata":{}},{"cell_type":"code","source":"feature_importances['mean_importance']=feature_importances[['importance_fold0+1','importance_fold1+1']].mean(axis=1)\nfeature_importances.sort_values(by='mean_importance', ascending=False, inplace=True)\nsns.barplot(y=feature_importances['feature'][:50],x=feature_importances['mean_importance'][:50], palette='inferno')\nplt.title('Mean Feature Importance by Folds')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2025-11-13T11:35:28.657304Z","iopub.execute_input":"2025-11-13T11:35:28.657654Z","iopub.status.idle":"2025-11-13T11:35:29.409781Z","shell.execute_reply.started":"2025-11-13T11:35:28.657628Z","shell.execute_reply":"2025-11-13T11:35:29.408957Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Masks","metadata":{}},{"cell_type":"code","source":"fig, axs = plt.subplots(5, 2, figsize=(16,16))\naxs = axs.flatten()\n\nk=-1    \nfor i, (mask, j) in enumerate(zip(masks_, axs)):\n    sns.heatmap(mask[:150], ax=j)\n    if i%2 == 0:\n        k+=1\n    j.set_title((f\"Fold{k} Mask for First 150 Instances\"))\nplt.tight_layout()","metadata":{"execution":{"iopub.status.busy":"2025-11-13T11:35:35.450955Z","iopub.execute_input":"2025-11-13T11:35:35.451596Z","iopub.status.idle":"2025-11-13T11:35:38.839321Z","shell.execute_reply.started":"2025-11-13T11:35:35.451549Z","shell.execute_reply":"2025-11-13T11:35:38.838532Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Explain Matrices","metadata":{}},{"cell_type":"code","source":"fig, axs = plt.subplots(len(explain_matrices), 1, figsize=(20,8))\nfor i,matrix in enumerate(explain_matrices):\n    axs[i].set_title(f'Fold{i} Explain Matrix for First 150 Instances')\n    sns.heatmap(matrix[:150], ax=axs[i])\nplt.tight_layout() ","metadata":{"execution":{"iopub.status.busy":"2025-11-13T11:35:48.639137Z","iopub.execute_input":"2025-11-13T11:35:48.639810Z","iopub.status.idle":"2025-11-13T11:35:51.268795Z","shell.execute_reply.started":"2025-11-13T11:35:48.639780Z","shell.execute_reply":"2025-11-13T11:35:51.267864Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"sub = pd.DataFrame({'customer_ID': test.index,\n                    'prediction': test_predictions})\nsub.to_csv('submission_tabnet.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2025-11-13T11:35:57.763576Z","iopub.execute_input":"2025-11-13T11:35:57.763937Z","iopub.status.idle":"2025-11-13T11:36:00.937959Z","shell.execute_reply.started":"2025-11-13T11:35:57.763907Z","shell.execute_reply":"2025-11-13T11:36:00.937124Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sub","metadata":{"execution":{"iopub.status.busy":"2025-11-13T11:35:11.806695Z","iopub.status.idle":"2025-11-13T11:35:11.807138Z","shell.execute_reply.started":"2025-11-13T11:35:11.806898Z","shell.execute_reply":"2025-11-13T11:35:11.806918Z"},"trusted":true},"outputs":[],"execution_count":null}]}