{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":14313,"databundleVersionId":862019,"sourceType":"competition"}],"dockerImageVersionId":30673,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.metrics import mean_squared_error\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport matplotlib.pyplot as plt\nimport seaborn as sns\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\nimport networkx as nx\n\nfrom sklearn.preprocessing import LabelEncoder\n\n# Load the datasets\ntrain = pd.read_csv('/kaggle/input/champs-scalar-coupling/train.csv')\ntest = pd.read_csv('/kaggle/input/champs-scalar-coupling/test.csv')\nstructures = pd.read_csv('/kaggle/input/champs-scalar-coupling/structures.csv')\ndipole_moments = pd.read_csv('/kaggle/input/champs-scalar-coupling/dipole_moments.csv')\nmagnetic_shielding_tensors = pd.read_csv('/kaggle/input/champs-scalar-coupling/magnetic_shielding_tensors.csv')\nmulliken_charges = pd.read_csv('/kaggle/input/champs-scalar-coupling/mulliken_charges.csv')\npotential_energy = pd.read_csv('/kaggle/input/champs-scalar-coupling/potential_energy.csv')\nscalar_coupling_contributions = pd.read_csv('/kaggle/input/champs-scalar-coupling/scalar_coupling_contributions.csv')\n\n# Quick look at the data\nprint(train.head())\nprint(structures.head())\nprint(dipole_moments.head())\nprint(magnetic_shielding_tensors.head())\nprint(mulliken_charges.head())\nprint(potential_energy.head())\nprint(scalar_coupling_contributions.head())","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:48:27.958936Z","iopub.execute_input":"2024-04-08T17:48:27.959387Z","iopub.status.idle":"2024-04-08T17:49:03.819425Z","shell.execute_reply.started":"2024-04-08T17:48:27.959353Z","shell.execute_reply":"2024-04-08T17:49:03.818153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.info(verbose=True, show_counts=True)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:49:03.821781Z","iopub.execute_input":"2024-04-08T17:49:03.822315Z","iopub.status.idle":"2024-04-08T17:49:04.891171Z","shell.execute_reply.started":"2024-04-08T17:49:03.822274Z","shell.execute_reply":"2024-04-08T17:49:04.890131Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test.info(verbose=True, show_counts=True)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:49:04.892538Z","iopub.execute_input":"2024-04-08T17:49:04.892843Z","iopub.status.idle":"2024-04-08T17:49:05.446612Z","shell.execute_reply.started":"2024-04-08T17:49:04.892817Z","shell.execute_reply":"2024-04-08T17:49:05.445606Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def merge_charges(dataset, mulliken_charges):\n    # Merge mulliken_charges for atom_index_0\n    charges = pd.merge(dataset, mulliken_charges, how='left', left_on=['molecule_name', 'atom_index_0'], right_on=['molecule_name', 'atom_index'])\n    charges.rename(columns={'mulliken_charge': 'mulliken_charge_0'}, inplace=True)\n\n    # Drop the 'atom_index' column as it's no longer needed after renaming 'mulliken_charge' to 'mulliken_charge_0'\n    charges.drop('atom_index', axis=1, inplace=True)\n\n    # Merge mulliken_charges for atom_index_1\n    charges = pd.merge(charges, mulliken_charges, how='left', left_on=['molecule_name', 'atom_index_1'], right_on=['molecule_name', 'atom_index'])\n    charges.rename(columns={'mulliken_charge': 'mulliken_charge_1'}, inplace=True)\n\n    # Drop the 'atom_index' column again\n    charges.drop('atom_index', axis=1, inplace=True)\n\n    # Now, train_with_charges contains the original train data with mulliken charges for both atoms in the pair\n    print(charges.head())\n    \n    return charges","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:49:05.449003Z","iopub.execute_input":"2024-04-08T17:49:05.449327Z","iopub.status.idle":"2024-04-08T17:49:05.457608Z","shell.execute_reply.started":"2024-04-08T17:49:05.449301Z","shell.execute_reply":"2024-04-08T17:49:05.456256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def merge_tensor(dataset, magnetic_shielding_tensors):\n    \n    mst_0 = magnetic_shielding_tensors.add_suffix('_0')\n    mst_0.rename(columns={'molecule_name_0': 'molecule_name', 'atom_index_0': 'atom_index_0'}, inplace=True)\n\n    mst = pd.merge(dataset, mst_0, how='left', left_on=['molecule_name', 'atom_index_0'], right_on=['molecule_name', 'atom_index_0'])\n\n    # Next, merge for atom_index_1\n    mst_1 = magnetic_shielding_tensors.add_suffix('_1')\n    mst_1.rename(columns={'molecule_name_1': 'molecule_name', 'atom_index_1': 'atom_index_1'}, inplace=True)\n\n    mst = pd.merge(mst, mst_1, how='left', left_on=['molecule_name', 'atom_index_1'], right_on=['molecule_name', 'atom_index_1'])\n\n    # Now, mst contains the original train data with magnetic shielding tensor information for both atoms in the pair\n    print(mst.head())\n    \n    return mst","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:49:05.459223Z","iopub.execute_input":"2024-04-08T17:49:05.459620Z","iopub.status.idle":"2024-04-08T17:49:05.472158Z","shell.execute_reply.started":"2024-04-08T17:49:05.459582Z","shell.execute_reply":"2024-04-08T17:49:05.471242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def join_charges_mst(charges,mst):\n    # Ensure both dataframes have the same index in case they were altered\n    charges.reset_index(drop=True, inplace=True)\n    mst.reset_index(drop=True, inplace=True)\n\n    # Select only the new columns from train_with_mst to avoid duplicating the common columns\n    columns_to_add = [col for col in mst.columns if col not in charges.columns]\n\n    # Concatenate the selected new columns to the train_with_charges dataframe\n    joined_dataset = pd.concat([charges, mst[columns_to_add]], axis=1)\n\n    print(joined_dataset.head())\n    \n    return joined_dataset","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:49:05.473315Z","iopub.execute_input":"2024-04-08T17:49:05.474231Z","iopub.status.idle":"2024-04-08T17:49:05.482614Z","shell.execute_reply.started":"2024-04-08T17:49:05.474201Z","shell.execute_reply":"2024-04-08T17:49:05.481591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def merge_structures(dataset, structures):\n    # Merging the structures information with the train or test dataset\n    # This is to get the 3D coordinates of the first atom in each pair\n    final_dataset = dataset.merge(structures, left_on=['molecule_name', 'atom_index_0'], right_on=['molecule_name', 'atom_index'], how='left')\n\n    # Rename the columns for clarity\n    final_dataset.rename(columns={'x': 'x0', 'y': 'y0', 'z': 'z0'}, inplace=True)\n\n    # Drop the 'atom_index' column\n    final_dataset.drop(['atom_index'], axis=1, inplace=True)\n\n    # Repeat for the second atom in the pair\n    final_dataset = final_dataset.merge(structures, left_on=['molecule_name', 'atom_index_1'], right_on=['molecule_name', 'atom_index'], how='left')\n\n    # Rename the columns for clarity\n    final_dataset.rename(columns={'x': 'x1', 'y': 'y1', 'z': 'z1'}, inplace=True)\n    final_dataset.rename(columns={'atom_x': 'atom_0', 'atom_y': 'atom_1'}, inplace=True)\n\n    # Drop the 'atom_index' column\n    final_dataset.drop(['atom_index'], axis=1, inplace=True)\n\n    # Calculate the distance between atoms in a pair\n    final_dataset['distance'] = np.sqrt((final_dataset['x0'] - final_dataset['x1'])**2 + (final_dataset['y0'] - final_dataset['y1'])**2 + (final_dataset['z0'] - final_dataset['z1'])**2)\n    \n    final_dataset['distance_x'] = (final_dataset['x0'] - final_dataset['x1']) ** 2\n    final_dataset['distance_y'] = (final_dataset['y0'] - final_dataset['y1']) ** 2\n    final_dataset['distance_z'] = (final_dataset['z0'] - final_dataset['z1']) ** 2\n    \n    return final_dataset","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:49:05.483789Z","iopub.execute_input":"2024-04-08T17:49:05.484748Z","iopub.status.idle":"2024-04-08T17:49:05.501302Z","shell.execute_reply.started":"2024-04-08T17:49:05.484716Z","shell.execute_reply":"2024-04-08T17:49:05.499968Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def type_distance_plot(dataset):\n    fig, ax = plt.subplots(figsize = (18, 8))\n    plt.subplot(1, 2, 1);\n    sns.histplot(dataset['distance'], bins=20)\n    plt.title('Distance Histogram');\n    plt.subplot(1, 2, 2);\n    sns.boxplot(x='type', y='distance', data=dataset);\n    plt.title('Boxplot of Distance by Type');\n    \n    return","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:49:05.502582Z","iopub.execute_input":"2024-04-08T17:49:05.502988Z","iopub.status.idle":"2024-04-08T17:49:05.516012Z","shell.execute_reply.started":"2024-04-08T17:49:05.502932Z","shell.execute_reply":"2024-04-08T17:49:05.514861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def type_distance_mean(final_dataset):\n    final_dataset['type_0'] = final_dataset['type'].apply(lambda x: x[0])\n    final_dataset['type_1'] = final_dataset['type'].apply(lambda x: x[1:])\n\n    final_dataset['distance_to_type_mean'] = final_dataset['distance'] / final_dataset.groupby('type')['distance'].transform('mean')\n    final_dataset['distance_to_type_0_mean'] = final_dataset['distance'] / final_dataset.groupby('type_0')['distance'].transform('mean')\n    final_dataset['distance_to_type_1_mean'] = final_dataset['distance'] / final_dataset.groupby('type_1')['distance'].transform('mean')\n    final_dataset[f'molecule_type_distance_mean'] = final_dataset.groupby(['molecule_name', 'type'])['distance'].transform('mean')\n    \n    return final_dataset","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:49:05.517624Z","iopub.execute_input":"2024-04-08T17:49:05.518029Z","iopub.status.idle":"2024-04-08T17:49:05.527414Z","shell.execute_reply.started":"2024-04-08T17:49:05.517998Z","shell.execute_reply":"2024-04-08T17:49:05.526227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Combining Mulliken Charges into New Features\nHere are a few strategies to engineer features from the Mulliken charge data:\n\n### Charge Difference: \nThe difference in Mulliken charges between the two atoms might be significant, as it could indicate the polarity of the bond or the electron distribution in the molecule.\n\n### Charge Sum: \nThe sum of Mulliken charges might reflect the overall electron density involved in interactions between the atom pair.\n\n### Product of Charges: \nThe product of the two charges might capture interactions related to the polarizability or other multiplicative effects of the electron clouds.\n\n## Summarizing Magnetic Shielding Tensor (MST) Data\nHere are a few strategies to engineer features from the MST data:\n\n### Sum of Tensor Elements: \nCalculate the sum of all elements of the tensor for each atom in the pair. This provides a single measure that reflects the overall magnetic shielding effect around an atom.\n\n### Difference in Sum of Tensor Elements Between Atoms: \nThe difference in the sums of tensor elements between atom_index_0 and atom_index_1 might capture the asymmetry in magnetic shielding between the two atoms in a pair.\n\n### Trace of the Tensor: \nThe trace of a tensor (the sum of its diagonal elements) is a simpler summary statistic that can be calculated easily and might also serve as a useful feature.","metadata":{}},{"cell_type":"code","source":"def additional_tensor_and_mulliken_features(final_dataset):\n    # Example of creating features from mulliken charge\n    final_dataset['mulliken_charge_diff'] = abs(final_dataset['mulliken_charge_0'] - final_dataset['mulliken_charge_1'])\n    final_dataset['mulliken_charge_sum'] = final_dataset['mulliken_charge_0'] + final_dataset['mulliken_charge_1']\n    final_dataset['mulliken_charge_product'] = final_dataset['mulliken_charge_0'] * final_dataset['mulliken_charge_1']\n\n    # Assuming final_dataset has columns like 'XX_0', 'YY_0', 'ZZ_0', 'XX_1', 'YY_1', 'ZZ_1', etc., for the tensor elements\n\n    # Sum of tensor elements for atom_index_0 and atom_index_1\n    \n    for idx in ['_0', '_1']:\n        tensor_elements = ['XX', 'YX', 'ZX', 'XY', 'YY', 'ZY', 'XZ', 'YZ', 'ZZ']\n        final_dataset[f'sum_mst{idx}'] = final_dataset[[f'{elem}{idx}' for elem in tensor_elements]].sum(axis=1)\n\n    # Difference in sum of tensor elements between atoms\n    final_dataset['diff_sum_mst'] = abs(final_dataset['sum_mst_0'] - final_dataset['sum_mst_1'])\n\n    # Example for calculating the trace of the tensor for atom_index_0\n    final_dataset['trace_mst_0'] = final_dataset[['XX_0', 'YY_0', 'ZZ_0']].sum(axis=1)\n    # Repeat similarly for atom_index_1\n    final_dataset['trace_mst_1'] = final_dataset[['XX_1', 'YY_1', 'ZZ_1']].sum(axis=1)\n\n    '''\n    def calculate_eigenvalues_sum(row, suffix):\n        tensor_matrix = np.array([[row[f'XX{suffix}'], row[f'XY{suffix}'], row[f'XZ{suffix}']],\n                                  [row[f'YX{suffix}'], row[f'YY{suffix}'], row[f'YZ{suffix}']],\n                                  [row[f'ZX{suffix}'], row[f'ZY{suffix}'], row[f'ZZ{suffix}']]])\n        eigenvalues = np.linalg.eigvals(tensor_matrix)\n        return np.sum(eigenvalues)  # Sum of eigenvalues as a summary statistic\n\n    # Apply the function for atom_index_0\n    final_dataset['eigenvalues_sum_mst_0'] = final_dataset.apply(lambda row: calculate_eigenvalues_sum(row, '_0'), axis=1)\n\n    # Apply the function for atom_index_1\n    final_dataset['eigenvalues_sum_mst_1'] = final_dataset.apply(lambda row: calculate_eigenvalues_sum(row, '_1'), axis=1)\n\n    # Difference in the sum of eigenvalues between atoms\n    final_dataset['diff_eigenvalues_sum_mst'] = abs(final_dataset['eigenvalues_sum_mst_0'] - final_dataset['eigenvalues_sum_mst_1'])\n    '''\n    \n    return final_dataset","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:49:05.531829Z","iopub.execute_input":"2024-04-08T17:49:05.532216Z","iopub.status.idle":"2024-04-08T17:49:05.546595Z","shell.execute_reply.started":"2024-04-08T17:49:05.532185Z","shell.execute_reply":"2024-04-08T17:49:05.545499Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset_charges = merge_charges(train, mulliken_charges)\ntest_dataset_charges = merge_charges(test, mulliken_charges)\n\ntrain_dataset_mst = merge_tensor(train, magnetic_shielding_tensors)\ntest_dataset_mst = merge_tensor(test, magnetic_shielding_tensors)\n\ntrain_joined = join_charges_mst(train_dataset_charges,train_dataset_mst)\ntest_joined = join_charges_mst(test_dataset_charges,test_dataset_mst)\n\ntrain_total = merge_structures(train_joined, structures)\ntest_total = merge_structures(test_joined, structures)\n\ntype_distance_plot(train_total)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:49:05.548711Z","iopub.execute_input":"2024-04-08T17:49:05.549126Z","iopub.status.idle":"2024-04-08T17:50:09.449146Z","shell.execute_reply.started":"2024-04-08T17:49:05.549087Z","shell.execute_reply":"2024-04-08T17:50:09.447862Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Based on the plot presented, it's observed that the distribution of distances between atoms within molecules demonstrates a right-skewed pattern. Also, we observe that the distance values are quite different for different coupling types.\n\nBased on this observations, we will engineer new features: \n\nOne feature will represent the first character of the type (i.e. 1, 2, 3), the other feature will represent remaining characters in the coupling type (JHC, JHH, JHN, e.t.c).\n\nAlso, we will create and use mean distance relative to coupling type features (distance_to_type_mean, distance_to_type_1_mean, e.t.c).","metadata":{}},{"cell_type":"code","source":"train_total = type_distance_mean(train_total)\ntest_total = type_distance_mean(test_total)\n\ntrain_total = additional_tensor_and_mulliken_features(train_total)\ntest_total = additional_tensor_and_mulliken_features(test_total)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tensor_elements = ['XX', 'YX', 'ZX', 'XY', 'YY', 'ZY', 'XZ', 'YZ', 'ZZ']\ntotal_tensor_elements = []\nfor idx in ['_0', '_1']:\n    total_tensor_elements += [f'{elem}{idx}' for elem in tensor_elements]","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:50:09.450568Z","iopub.execute_input":"2024-04-08T17:50:09.451005Z","iopub.status.idle":"2024-04-08T17:50:09.457593Z","shell.execute_reply.started":"2024-04-08T17:50:09.450966Z","shell.execute_reply":"2024-04-08T17:50:09.456391Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X = train_total.drop(['id', 'molecule_name', 'scalar_coupling_constant']+total_tensor_elements+['mulliken_charge_0','mulliken_charge_1','sum_mst_0','sum_mst_1','atom_0'], axis=1)\ny = train_total['scalar_coupling_constant']","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:50:09.458907Z","iopub.execute_input":"2024-04-08T17:50:09.459327Z","iopub.status.idle":"2024-04-08T17:50:10.203954Z","shell.execute_reply.started":"2024-04-08T17:50:09.459287Z","shell.execute_reply":"2024-04-08T17:50:10.202615Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Xtest = test_total.drop(['id', 'molecule_name']+total_tensor_elements+['mulliken_charge_0','mulliken_charge_1','sum_mst_0','sum_mst_1','atom_0'], axis=1)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:50:10.205454Z","iopub.execute_input":"2024-04-08T17:50:10.205787Z","iopub.status.idle":"2024-04-08T17:50:10.656392Z","shell.execute_reply.started":"2024-04-08T17:50:10.205759Z","shell.execute_reply":"2024-04-08T17:50:10.655030Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Split the dataset\nX_train, X_test = train_test_split(X, test_size=0.25, random_state=42)\n\n# Sample DataFrame\nfor f in ['atom_1', 'type_0', 'type_1', 'type']:\n\n    # Initialize LabelEncoder\n    encoder = LabelEncoder()\n\n    # Fit LabelEncoder on the training set\n    encoder.fit(list(X_train[f].values))\n\n    # Transform the training set\n    X_train[f] = encoder.transform(list(X_train[f].values))\n\n    # Handle unseen labels in the test set by using a custom function\n    #def transform_with_unseen(encoder, data):\n    #    classes = encoder.classes_\n    #    return [encoder.transform([item])[0] if item in classes else -1 for item in data]\n\n    # Transform the test set\n    X_test[f] = encoder.transform(list(X_test[f].values))\n    \n    Xtest[f] = encoder.transform(list(Xtest[f].values))\n\n# Show the results\nprint(\"Training Set:\\n\", X_train)\nprint(\"\\nTest Set:\\n\", X_test)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:50:10.657732Z","iopub.execute_input":"2024-04-08T17:50:10.658159Z","iopub.status.idle":"2024-04-08T17:50:52.671028Z","shell.execute_reply.started":"2024-04-08T17:50:10.658131Z","shell.execute_reply":"2024-04-08T17:50:52.669837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Randomly sample 20% of your training dataset\ndf_percent = X_train.sample(frac=0.20)\n","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:50:52.672382Z","iopub.execute_input":"2024-04-08T17:50:52.672704Z","iopub.status.idle":"2024-04-08T17:50:53.168276Z","shell.execute_reply.started":"2024-04-08T17:50:52.672672Z","shell.execute_reply":"2024-04-08T17:50:53.166993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.ensemble import RandomForestRegressor\n\n# Initialize the model\nmodel = RandomForestRegressor(n_estimators=100, random_state=42)\n\n# Fit the model\nmodel.fit(df_percent, y[df_percent.index])","metadata":{"execution":{"iopub.status.busy":"2024-04-08T17:50:53.169579Z","iopub.execute_input":"2024-04-08T17:50:53.169894Z","iopub.status.idle":"2024-04-08T18:51:21.814943Z","shell.execute_reply.started":"2024-04-08T17:50:53.169868Z","shell.execute_reply":"2024-04-08T18:51:21.813703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import mean_squared_error\n\n# Predictions\ny_pred = model.predict(X_test)\n\n# Evaluation\nmse = mean_squared_error(y[X_test.index], y_pred)\nrmse = mean_squared_error(y[X_test.index], y_pred, squared=False)\nprint(f'Mean Squared Error: {mse}')\nprint(f'Root Mean Squared Error: {rmse}')","metadata":{"execution":{"iopub.status.busy":"2024-04-08T18:51:21.817272Z","iopub.execute_input":"2024-04-08T18:51:21.817930Z","iopub.status.idle":"2024-04-08T18:53:11.891160Z","shell.execute_reply.started":"2024-04-08T18:51:21.817897Z","shell.execute_reply":"2024-04-08T18:53:11.889947Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Predictions\ncoupling_constant = model.predict(Xtest)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T18:53:11.892599Z","iopub.execute_input":"2024-04-08T18:53:11.892997Z","iopub.status.idle":"2024-04-08T18:56:05.079875Z","shell.execute_reply.started":"2024-04-08T18:53:11.892965Z","shell.execute_reply":"2024-04-08T18:56:05.078490Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"coupling_constant","metadata":{"execution":{"iopub.status.busy":"2024-04-08T18:56:05.081401Z","iopub.execute_input":"2024-04-08T18:56:05.081816Z","iopub.status.idle":"2024-04-08T18:56:05.089528Z","shell.execute_reply.started":"2024-04-08T18:56:05.081776Z","shell.execute_reply":"2024-04-08T18:56:05.088405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.DataFrame({'id':test.id,'scalar_coupling_constant':coupling_constant})","metadata":{"execution":{"iopub.status.busy":"2024-04-08T18:56:05.091183Z","iopub.execute_input":"2024-04-08T18:56:05.091610Z","iopub.status.idle":"2024-04-08T18:56:05.113805Z","shell.execute_reply.started":"2024-04-08T18:56:05.091573Z","shell.execute_reply":"2024-04-08T18:56:05.112591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission","metadata":{"execution":{"iopub.status.busy":"2024-04-08T19:08:58.399480Z","iopub.execute_input":"2024-04-08T19:08:58.399940Z","iopub.status.idle":"2024-04-08T19:08:58.413758Z","shell.execute_reply.started":"2024-04-08T19:08:58.399902Z","shell.execute_reply":"2024-04-08T19:08:58.412433Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_submission = pd.read_csv('/kaggle/input/champs-scalar-coupling/sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2024-04-08T18:56:05.133710Z","iopub.execute_input":"2024-04-08T18:56:05.134170Z","iopub.status.idle":"2024-04-08T18:56:05.852732Z","shell.execute_reply.started":"2024-04-08T18:56:05.134135Z","shell.execute_reply":"2024-04-08T18:56:05.851681Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission.to_csv('/kaggle/working/submission.csv', index=False)\nsubmission.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T18:56:05.854592Z","iopub.execute_input":"2024-04-08T18:56:05.855032Z","iopub.status.idle":"2024-04-08T18:56:21.416519Z","shell.execute_reply.started":"2024-04-08T18:56:05.854994Z","shell.execute_reply":"2024-04-08T18:56:21.415139Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from IPython.display import FileLink\nFileLink('submission.csv')","metadata":{"execution":{"iopub.status.busy":"2024-04-08T19:10:05.027916Z","iopub.execute_input":"2024-04-08T19:10:05.028367Z","iopub.status.idle":"2024-04-08T19:10:05.036522Z","shell.execute_reply.started":"2024-04-08T19:10:05.028334Z","shell.execute_reply":"2024-04-08T19:10:05.034937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Based on our discussion about modeling the coupling constant in molecules, several key points and conclusions can be drawn regarding the approach, methodology, feature engineering, and the evaluation of the model's performance. Here's a structured conclusion covering these aspects:\n\n## Data Preparation and Feature Engineering\n### Atom-level and Molecular-level Features: \nWe emphasized the importance of incorporating both atom-level features (such as Mulliken charges, magnetic shielding tensors) to capture the intricacies of atomic interactions and aggregating molecules and coupling types to calculate an average distance for use as a feature.\n### Feature Engineering Techniques: \nTechniques like statistical summaries of atom-level features, calculation of molecular descriptors and fingerprints, and creation of ratios and interaction terms between features were discussed to enhance the model's ability to learn from the data.\n### Handling Categorical Data: \nThe use of LabelEncoder was explored for converting categorical data into a machine-readable format, with the recommendation to perform encoding after train-test splitting to avoid data leakage.\n\n## Model Building and Evaluation\n### Regression Model: \nA regression approach was adopted for predicting the scalar coupling constant, given its continuous nature. A Random Forest Regressor was suggested as a starting point due to its robustness and ability to handle nonlinear relationships without extensive hyperparameter tuning.\n### Model Evaluation: \nThe model was evaluated using Mean Squared Error (MSE) and Root Mean Squared Error (RMSE), with observed values of 4.045 and 2.011, respectively. These metrics provide a quantitative measure of the model's accuracy, indicating on average how far the model's predictions are from the actual values.\n\n## Performance Insights\n### Interpretation of MSE and RMSE: \nThe MSE value of 4.045 and the RMSE of 2.011 suggest that the model has a relatively low error rate in predicting the coupling constants. RMSE, being in the same units as the target variable, offers a more interpretable measure, indicating that the average prediction error is approximately ±2.011 units of the scalar coupling constant.\n### Implications: \nThe obtained MSE and RMSE values represent a promising start but require context for full interpretation. Comparing these values against the range and distribution of the coupling constants in the dataset helps assess model performance. Lower RMSE values indicate closer fits to the data, but the goal is to minimize this value in the context of the specific application and data variability.\n## Next Steps and Improvements\n### Feature Importance Analysis: \nInvestigating the importance of each feature in the model can provide insights into the underlying physics captured by the model and guide further feature engineering efforts.\n### Model Tuning and Comparison: \nExperimenting with different models and tuning hyperparameters can potentially improve performance. Techniques like cross-validation are crucial for assessing model robustness and generalizability.\n### Advanced Modeling Techniques: \nDepending on the complexity of the dataset and the relationships it contains, more advanced models or ensemble methods might yield better performance. Techniques such as gradient boosting or neural networks could be explored.\n\n## Conclusion\nThe modeling approach to predict scalar coupling constants using both atom-level and molecular-level features has shown promising initial results, with an RMSE of 2.011. This performance suggests that the model has a reasonable level of accuracy but also highlights the potential for further improvements through more sophisticated feature engineering, model tuning, and exploration of advanced modeling techniques. Achieving lower error rates will enhance the model's utility in practical applications, making it a valuable tool for understanding and predicting molecular interactions.","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}