{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nfrom tqdm import tqdm\nimport itertools\n\nimport numpy as np\nimport pandas as pd\n\nfrom collections import OrderedDict\n\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.model_selection import GroupKFold\nfrom sklearn.metrics import mean_absolute_error","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training and Test Data"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"# Import the training data and inspect the first few entries:\ntrain_data = pd.read_csv(\"../input/train.csv\", index_col='id')\ny_label = train_data.pop('scalar_coupling_constant')\nprint(f\"Training data is of shape: {train_data.shape}\")\ntrain_data.head(3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Import the test data and inspect the first few entries:\ntest_data = pd.read_csv(\"../input/test.csv\", index_col='id')\nprint(f\"Test data is of shape: {test_data.shape}\")\ntest_data.head(3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Quick Inspections on the training and test data:\nprint(f\"Training Data has {train_data.molecule_name.nunique()} unique molecules with {train_data.type.nunique()} unique types\")\nprint(f\"Test Data has {test_data.molecule_name.nunique()} unique molecules with {test_data.type.nunique()} unique types\")\nprint(f\"Coupling Constant Dist.: mean={round(y_label.mean(),2)} ± std={round(y_label.std(),2)}\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Structures\nStructures file contains the coordinates (x,y,z) of every atom in every molecule. It has the mappings from the \"atom_index\" to the name of the atom and it's coordinates."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Inspection on the structures data set:\nstructures = pd.read_csv(\"../input/structures.csv\")\nstructures.head(3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Merge the coordinates of both atoms to the training and test data:\ndef MergeData(data, structures):\n    \n    for i in range(2):\n        data = pd.merge(data, structures, how = \"inner\", left_on = [\"molecule_name\", f\"atom_index_{i}\"], right_on = [\"molecule_name\", \"atom_index\"])\n        data.drop(columns=[\"atom_index\"], inplace=True)\n        data.rename(index=str, columns={\"atom\": f\"atom_{i}\", \"x\": f\"x_{i}\", \"y\": f\"y_{i}\", \"z\": f\"z_{i}\"}, inplace=True)\n    \n    data = data.reindex(columns=['molecule_name', 'type', 'atom_index_0', 'atom_0', 'x_0', 'y_0', 'z_0', 'atom_index_1', 'atom_1', 'x_1', 'y_1', 'z_1'])\n    return data\n\ntrain_data = MergeData(train_data, structures)\ntest_data = MergeData(test_data, structures)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Encode the categorical variables: molecule type and atoms names:\nfor f in ['type', 'atom_0', 'atom_1']:\n    lbl = LabelEncoder()\n    lbl.fit(list(train_data[f].values) + list(test_data[f].values))\n    train_data[f] = lbl.transform(list(train_data[f].values))\n    test_data[f] = lbl.transform(list(test_data[f].values))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Calculate the distance between two atoms:\ntrain_p_0 = train_data[['x_0', 'y_0', 'z_0']].values\ntrain_p_1 = train_data[['x_1', 'y_1', 'z_1']].values\ntest_p_0 = test_data[['x_0', 'y_0', 'z_0']].values\ntest_p_1 = test_data[['x_1', 'y_1', 'z_1']].values\n\ntrain_data['distance'] = np.linalg.norm(train_p_0 - train_p_1, axis=1)\ntest_data['distance'] = np.linalg.norm(test_p_0 - test_p_1, axis=1)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"molecules = train_data.pop('molecule_name')\ntest_data = test_data.drop('molecule_name', axis=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Regression Model:"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Simple Regressor, using only the encoded values:\nfeature_columns = ['type', 'atom_0', 'atom_index_0', 'x_0', 'y_0', 'z_0',\n                   'atom_index_1', 'atom_1', 'x_1', 'y_1', 'z_1', 'distance']\ntrain = train_data[feature_columns]\ntest = test_data[feature_columns]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def metric(df, prediction, labels):\n    df = df.copy()\n    df.loc[:, \"prediction\"] = prediction\n    df.loc[:, \"scalar_coupling_constant\"] = labels\n    maes = []\n    for t in df.type.unique():\n        y_true = df[df.type==t].scalar_coupling_constant.values\n        y_pred = df[df.type==t].prediction.values        \n        mae = np.log(mean_absolute_error(y_true, y_pred))\n        # print(f\"MAE for type {t} is {round(mae, 2)}\")\n        maes.append(mae)\n    return np.mean(maes)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\nyoof = np.zeros(len(train))\nyhat = np.zeros(len(test))\n\nn_splits = 3\ngkf = GroupKFold(n_splits=n_splits)\n\nfold = 0\nfor in_index, oof_index in gkf.split(train, y_label, groups=molecules):\n    fold += 1\n    print(f'fold {fold} of {n_splits}')\n    X_in, X_oof = train.values[in_index], train.values[oof_index]\n    y_in, y_oof = y_label.values[in_index], y_label.values[oof_index]\n    \n    reg = RandomForestRegressor(n_estimators=1,\n                                max_depth=5,\n                                min_samples_leaf=3,\n                                n_jobs=-1)\n    reg.fit(X_in, y_in)\n    yoof[oof_index] = reg.predict(X_oof)\n    \n    cur_fold_mea = metric(train[oof_index], yoof[oof_index], y_label[oof_index].values)\n    print(f\"The MEA for current fold is {round(cur_fold_mea, 2)}\")\n\n    cur_yhat = reg.predict(test)\n    yhat += cur_yhat\n\nyhat /= n_splits\n'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create the Hyper Parameters Grid Search:\nmax_features = ['sqrt']  #log2\nmax_depth = [12]\nproperties_list = list(itertools.product(max_features, max_depth))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create Regressor for every parameters combination:\nregressors = []\nfor cur_prop in properties_list:\n    regressors.append((\"RF: {} max feat + {} max depth\".format(*cur_prop),\n                        RandomForestRegressor(warm_start=True,\n                                               max_features=cur_prop[0],\n                                               max_depth=cur_prop[1])))\n\n# Map a regressor name to a list of (<n_estimators>, <error rate>) pairs.\noof_error_rate = OrderedDict((label, []) for label, _ in regressors)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Range of `n_estimators` values to explore.\nmin_estimators = 1\nmax_estimators = 101\nstep_estimators = 50\n\ngkf = GroupKFold(n_splits=2)\nin_index, oof_index = gkf.split(train, y_label, groups=molecules)\nin_index = in_index[0]\noof_index = oof_index[0]\n        \nfor label, reg in tqdm(regressors, desc=\"Regressors Loop\"):\n    for i in tqdm(range(min_estimators, max_estimators + 1, step_estimators), desc=\"Trees Loop\"):\n        \n        reg.set_params(n_estimators=i)\n        reg.fit(train.values[in_index], y_label.values[in_index])\n        yoof = reg.predict(train.values[oof_index])\n\n        # Record the Validation Error for each `n_estimators=i` setting.\n        oof_error = metric(train.iloc[oof_index], yoof, y_label.values[oof_index])\n        print(f\"Current OOF Error is {oof_error}\")\n        oof_error_rate[label].append((i, oof_error))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(oof_error_rate)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# print(f\"Final Metric for all Out Of Sample data: {round(metric(train, yoof, y_label.values),2)}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''\nsample_submission = pd.read_csv('../input/sample_submission.csv', index_col='id')\nbenchmark = sample_submission.copy()\nbenchmark['scalar_coupling_constant'] = yhat\nbenchmark.to_csv('simple_benchmark.csv')\n'''","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}