В этом посте я собираюсь показать, как приступить к разработке моделей машинного обучения для предсказания молекулярных свойств. Это должен быть очень минимальный пример. Мы рассмотрим другие методы улучшения этой модели в следующих постах. Мы собираемся предсказать липофильность малых молекул. Набор данных можно скачать с сайта MoleculeNet.
Прогнозирование липофильности — это регрессионная задача, и мы собираемся использовать алгоритм Random Forest, реализованный в пакете scikit-learn. Нам также потребуется создать молекулярные признаки для каждой молекулы в наборе данных. Мы будем использовать mordred и rdkit для создания этих функций. Если у вас еще нет этих пакетов, используйте pip для их установки.
pip install mordred pip install rdkit-pypi
Импортировать необходимые пакеты
Ниже приведен полный список импорта, который нам понадобится.
import numpy as np import pandas as pd import mordred from rdkit import Chem from mordred import Calculator, descriptors from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.metrics import r2_score, mean_squared_error import matplotlib.pyplot as plt
Загрузите данные и создайте молекулярные функции
Первым шагом является загрузка данных. Перейдите на этот веб-сайт MoleculeNet и выполните поиск липофильности, чтобы найти ссылку для загрузки набора данных. После того, как вы нажмете на ссылку, файл csv будет загружен.
Прочитайте данные.
lipo_data = pd.read_csv("/path/to/data/Lipophilicity.csv")
Фрейм данных содержит столбец ID (CMPD_CHEMBLID), столбец для экспериментальных значений липофильности (exp) и столбец для строк SMILES молекул (smiles). >)
Теперь давайте создадим молекулярные объекты с помощью mordred. Сначала нам нужно создать объект класса Calculator mordred, как показано ниже.
calc = Calculator(descriptors, ignore_3D=True)
ignore_id=True означает, что мы будем создавать только 2-мерные объекты. В классе калькулятора есть метод pandas, который представит нам молекулярные функции в виде кадра данных pandas. Входными данными для этого метода является список объектов rdkit mol наших молекул.
Итак, давайте создадим эти вот эти объекты mol.
mols = [Chem.MolFromSmiles(i) for i in lipo_data.smiles]
Хорошо, теперь мы создаем молекулярные функции.
mol_features = calc.pandas(mols)
Иногда определенные характеристики определенных молекул не рассчитываются должным образом. Такие функции содержат неверные данные, которые мы не можем использовать для обучения. Быстрый способ избавиться от столбцов, содержащих недопустимые данные, — выполнить некоторые вычисления с использованием этих данных. Я собираюсь масштабировать функции, используя StandardScaler sklearn. Затем я собираюсь найти, какие столбцы содержат недопустимые значения. Затем я откажусь от этих столбцов.
# standard scale tmp = sc.fit_transform(mol_features.astype(float)) # find the columns that contain NaN values nan_cols = np.where(np.isnan(tmp))[1] nan_col_headers = mol_features.columns[nan_cols] # drop the columns that contain NaN values data = mol_features.drop(nan_col_headers, axis=1)
Хорошо! Теперь у нас есть чистый набор молекулярных признаков. Давайте добавим целевое свойство, значения липофильности в этот фрейм данных.
data.loc[:, 'exp'] = lipo.exp.values
Обучение, проверка и тестовые данные
Теперь нам нужно разделить набор данных, чтобы сформировать обучающие, проверочные и тестовые данные. Несмотря на то, что я не собираюсь использовать набор проверки в этом примере, набор данных проверки необходим для определения достоверности нашей модели для невидимого набора данных.
Мы будем использовать 80% данных в качестве данных для обучения и 10% данных для проверки и тестирования.
train, test = train_test_split(data, test_size=0.2, random_state=42) test, val = train_test_split(test, test_size=0.5, random_state=42)
Теперь давайте разделим данные функций и целевые данные.
# features x_train = train.drop(['exp'], axis=1) # train features x_val = val.drop(['exp'], axis=1) # validation features x_test = test.drop(['exp'], axis=1) # test features # targets y_train = train.exp.values # train targets y_val = val.exp.values # validation targets y_test = test.exp.values # test targets
При желании можно масштабировать функции. Я собираюсь масштабировать функции так, чтобы каждая функция имела среднее значение, равное нулю, и стандартное отклонение, равное единице. StandardScaler sklearn может это сделать.
sc = StandardScaler() x_train = sc.fit_transform(x_train.values) x_val = sc.transform(x_val.values) x_test = sc.transform(x_test.values)
Обратите внимание, что я использовал только данные поезда, чтобы найти параметры масштабирования для данных поезда, проверки и тестирования.
Определить модель и обучить
Теперь мы готовы обучить модель. Давайте определим модель, как показано ниже.
rf = RandomForestRegressor(n_estimators=100, random_state=42)
И приступайте к тренировкам.
rf.fit(X=x_train, y=y_train)
Вот и все! Теперь мы можем найти производительность модели на тестовых данных.
Делать предсказания
Мы можем использовать метод прогнозирования случайного леса scikit-learn, чтобы найти прогнозы модели.
test_pred = rf.predict(x_test) r2 = r2_score(y_pred = test_pred, y_true = y_test) rmse = mean_squared_error(y_pred=test_pred, y_true=y_test)**.5 print(f'r2 score = {r2}') print(f'rmse = {rmse}')
Я получил оценку r2 0,66 и RMSE 0,70. Не так уж и плохо для очень простой модели. Вы можете получить разные результаты в зависимости от случайных состояний, которые вы используете для разделения поезда/теста и для случайных лесов.
Давайте также построим график истинной и предсказанной липофильности.
plt.plot(y_test, test_pred, 'o'); plt.plot([-1, 5], [-1,5], 'k--') plt.xticks(fontsize=16, fontweight='bold') plt.yticks(fontsize=16, fontweight='bold') plt.xlabel('True', fontsize=16, fontweight='bold'); plt.ylabel('Predicted', fontsize=16, fontweight='bold'); plt.tight_layout(); plt.savefig('lipo_test.png')
Полный код можно найти в моем репозитории на GitHub.