{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Naive Kernel for Magnetic Interaction Prediction\nThis is a work-in-progress kernel."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"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 in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom sklearn.linear_model import LinearRegression\nfrom sklearn import metrics\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load data sets"},{"metadata":{"trusted":true},"cell_type":"code","source":"trainSet = pd.read_csv('../input/train.csv')\ndisplay(trainSet.head())","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"testSet = pd.read_csv('../input/test.csv')\ndisplay(testSet.head())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"structures = pd.read_csv('../input/structures.csv')\ndisplay(structures.head())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Atomic distance\nhttps://www.kaggle.com/inversion/atomic-distance-benchmark/"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Map the atom structure data into train and test files\n\ndef map_atom_info(df, atom_idx):\n    df = pd.merge(df, structures, how = 'left',\n                  left_on  = ['molecule_name', f'atom_index_{atom_idx}'],\n                  right_on = ['molecule_name',  'atom_index'])\n    \n    df = df.drop('atom_index', axis=1)\n    df = df.rename(columns={'atom': f'atom_{atom_idx}',\n                            'x': f'x_{atom_idx}',\n                            'y': f'y_{atom_idx}',\n                            'z': f'z_{atom_idx}'})\n    return df\n\ntrainSet = map_atom_info(trainSet, 0)\ntrainSet = map_atom_info(trainSet, 1)\n\ntestSet = map_atom_info(testSet, 0)\ntestSet = map_atom_info(testSet, 1)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"display(trainSet.head())\ndisplay(testSet.head())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# https://www.kaggle.com/jazivxt/all-this-over-a-dog\n# https://www.kaggle.com/artgor/molecular-properties-eda-and-models\ntrain_p0 = trainSet[['x_0', 'y_0', 'z_0']].values\ntrain_p1 = trainSet[['x_1', 'y_1', 'z_1']].values\ntest_p0 = testSet[['x_0', 'y_0', 'z_0']].values\ntest_p1 = testSet[['x_1', 'y_1', 'z_1']].values\n\ntrainSet['dist'] = np.linalg.norm(train_p0 - train_p1, axis=1)\ntestSet['dist'] = np.linalg.norm(test_p0 - test_p1, axis=1)\n\ntrainSet['dist_to_type_mean'] = trainSet['dist'] / trainSet.groupby('type')['dist'].transform('mean')\ntestSet['dist_to_type_mean'] = testSet['dist'] / testSet.groupby('type')['dist'].transform('mean')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Atom types"},{"metadata":{"trusted":true},"cell_type":"code","source":"# All atom_0 are hydrogens\nassert all(trainSet[\"atom_0\"].astype('category').cat.categories == ['H'])\nassert all(testSet[\"atom_0\"].astype('category').cat.categories == ['H'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# atom_1 are carbon, hydrogen or nitrogen\nprint(trainSet[\"atom_1\"].astype('category').cat.categories)\nprint(testSet[\"atom_1\"].astype('category').cat.categories)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# We use the interaction types, that already include the type of atoms involved\nprint(testSet[\"type\"].astype('category').cat.categories)\nprint(trainSet[\"type\"].astype('category').cat.categories)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in trainSet[\"type\"].astype('category').cat.categories.values:\n    trainSet['type_'+str(i)] = (trainSet['type'] == i)\n    testSet['type_'+str(i)] = (testSet['type'] == i)","execution_count":46,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Simple linear regression"},{"metadata":{"trusted":true},"cell_type":"code","source":"model = LinearRegression(n_jobs = -1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.linear_model import LinearRegression\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# NB: no need to include type_3JHN as this is redundant: this is always true when all other types are false\nfitDist = model.fit(np.array(trainSet[['type_1JHC', 'type_1JHN', 'type_2JHC', 'type_2JHH', 'type_2JHN', \n                                       'type_3JHC', 'type_3JHH', 'dist', 'dist_to_type_mean']]), \n                    trainSet['scalar_coupling_constant'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Display factors to learn what is important for the prediction\nfitDist.coef_","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Evaluate performance\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# See https://www.kaggle.com/uberkinder/efficient-metric\ndef group_mean_log_mae(y_true, y_pred, types, floor=1e-9):\n    maes = (y_true-y_pred).abs().groupby(types).mean()\n    return np.log(maes.map(lambda x: max(x, floor))).mean()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"group_mean_log_mae(trainSet['scalar_coupling_constant'], \n                   model.predict(np.array(trainSet[['type_1JHC', 'type_1JHN', 'type_2JHC', 'type_2JHH', 'type_2JHN', \n                                       'type_3JHC', 'type_3JHH', 'dist', 'dist_to_type_mean']])), trainSet['type'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Control: this should perform better than outputing the same overfitted value for all interactions\nprint(group_mean_log_mae(trainSet['scalar_coupling_constant'], trainSet['scalar_coupling_constant'].median(), trainSet['type']))\nprint(group_mean_log_mae(trainSet['scalar_coupling_constant'], 0.85, trainSet['type']))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"resultSet = pd.DataFrame( { \"id\" : testSet['id'],\n                            \"scalar_coupling_constant\" : model.predict(np.array(testSet[['type_1JHC', 'type_1JHN', \n                                                                                         'type_2JHC', 'type_2JHH', \n                                                                                         'type_2JHN', 'type_3JHC', \n                                                                                         'type_3JHH', 'dist', \n                                                                                         'dist_to_type_mean']]))} )","execution_count":48,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Export results"},{"metadata":{"trusted":true},"cell_type":"code","source":"resultSet.to_csv(\"results.csv\", index = False, header = True)","execution_count":49,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Check content of the output file\nwith open(\"results.csv\", \"r\") as f:\n    for i, line in enumerate(f):\n        print(line)\n        if i > 5:\n            break","execution_count":50,"outputs":[{"output_type":"stream","text":"id,scalar_coupling_constant\n\n4658147,-0.8781299757870258\n\n4658148,96.62848787029725\n\n4658149,4.918767332170326\n\n4658150,96.62848787029725\n\n4658151,-0.8781299757870258\n\n4658152,94.4726202594656\n\n","name":"stdout"}]}],"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}