{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Keras Quickstart for the AMEX competition part 2: Inference\n\nThis notebook uses the trained models of [Keras Quickstart 1: Training]() and computes the test predictions.\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport pickle\nfrom matplotlib import pyplot as plt\nimport random\nimport datetime\nfrom matplotlib.ticker import MaxNLocator\nimport os\n\nimport tensorflow as tf\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-05-27T09:59:46.633729Z","iopub.execute_input":"2022-05-27T09:59:46.634613Z","iopub.status.idle":"2022-05-27T09:59:46.639955Z","shell.execute_reply.started":"2022-05-27T09:59:46.634571Z","shell.execute_reply":"2022-05-27T09:59:46.639090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference\n\nWe perform the same steps as in the training pipeline:\n- Read the test data\n- Keep only the most recent statement of every customer\n- One-hot encode the categorical features\n- Impute missing values\n- Scale the data with the previously saved scaler (for every fold)\n\nThen we predict the target with every model that we have saved before and submit the median of the predictions. We could take the mean instead of the median - I do not yet know whether that makes a difference.\n","metadata":{}},{"cell_type":"code","source":"%%time\nmodel_dir = '../input/amex-keras-quickstart-1-training'\ncat_features = ['B_30', 'B_38', 'D_114', 'D_116', 'D_117', 'D_120', 'D_126', 'D_63', 'D_64', 'D_66', 'D_68']\nwith open(os.path.join(model_dir, \"ohe.pickle\"), 'rb') as f: ohe = pickle.load(f)\n#with open('../input/pickled-shrunken-training-data/test_data.pkl', 'rb') as f: test = pickle.load(f)\ntest = pd.read_feather('../input/parquet-files-amexdefault-prediction/test_data.ftr')\nnum_statements = (test\n          .groupby('customer_ID')\n          .size()\n          .sort_index())\n\n# Keep only the most recent statement of every customer\ntest = (test\n         .groupby('customer_ID')\n         .tail(1)\n         .set_index('customer_ID', drop=True)\n         .sort_index()\n         .drop(['S_2'], axis='columns'))\ntest['num_statements'] = num_statements\n\n# One-hot encode the categorical features\nnot_cat_features = [f for f in test.columns if f not in cat_features]\ntest[cat_features] = test[cat_features].astype(object)\ntest = pd.concat([test[not_cat_features],\n                   pd.DataFrame(ohe.transform(test[cat_features]), index=test.index).rename(columns=str)], axis=1)\n\n# Impute missing values\ntest.fillna(value=0, inplace=True)\n\nfold = 0\ny_pred_list = []\ntry:\n    while True: # loop over all folds\n        # Load the scaler and the model\n        with open(os.path.join(model_dir, f\"scaler_{fold}.pickle\"), 'rb') as f: scaler = pickle.load(f)\n        model = tf.keras.models.load_model(os.path.join(model_dir, f\"model_{fold}\"))\n\n        # Scale and predict\n        y_pred_list.append(model.predict(scaler.transform(test), batch_size=1024*1024, verbose=0).ravel())\n        with np.printoptions(linewidth=150, precision=2, suppress=True):\n            print(fold, y_pred_list[-1])\n\n        fold += 1\nexcept FileNotFoundError:\n    pass\n\n# Ensemble the predictions of all folds\nsub = pd.DataFrame({'customer_ID': test.index,\n                    'prediction': np.median(y_pred_list, axis=0)})\n","metadata":{"execution":{"iopub.status.busy":"2022-05-27T10:08:58.904713Z","iopub.execute_input":"2022-05-27T10:08:58.905410Z","iopub.status.idle":"2022-05-27T10:10:19.161945Z","shell.execute_reply.started":"2022-05-27T10:08:58.905365Z","shell.execute_reply":"2022-05-27T10:10:19.160798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub.to_csv('submission.csv', index=False)\nsub","metadata":{"execution":{"iopub.status.busy":"2022-05-27T10:11:14.884309Z","iopub.execute_input":"2022-05-27T10:11:14.885005Z","iopub.status.idle":"2022-05-27T10:11:17.685230Z","shell.execute_reply.started":"2022-05-27T10:11:14.884961Z","shell.execute_reply":"2022-05-27T10:11:17.684202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As a plausibility test, we plot a histogram of the predictions. The majority of the predictions should be near 0 (because the classes are imbalanced).","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(16, 5))\nplt.hist(sub.prediction, bins=100, density=True)\nplt.title(\"Plausibility check\", fontsize=20)\nplt.xlabel('Prediction')\nplt.ylabel('Density')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-05-27T10:11:19.061230Z","iopub.execute_input":"2022-05-27T10:11:19.061689Z","iopub.status.idle":"2022-05-27T10:11:19.494374Z","shell.execute_reply.started":"2022-05-27T10:11:19.061634Z","shell.execute_reply":"2022-05-27T10:11:19.493405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}