Probieren Sie ein einfaches QSAR-Modell mit Chainer aus [Vorhersage der Permeabilität der Blut-Hirn-Schranke von Verbindungen]

2020/3/2

QSAR (Quantitative Structure-Activity Relationship) ist eine statistische Korrelation zwischen der Struktur einer chemischen Substanz und ihrer physiologischen Aktivität (Toxizität, Fähigkeit zur Bindung an Enzyme, Aktivität als Arzneimittel usw.).Die Leistung der Verbindung kann anhand von Korrelationen vorhergesagt werden, die auf umfangreichen experimentellen Datensätzen von Chemikalien basieren.

Dieses Mal werden wir ein einfaches QSAR-Modell erstellen, das "die Durchlässigkeit der Blut-Hirn-Schranke von Verbindungen vorhersagt", indem wir Chainer, ein in Japan hergestelltes Deep-Learning-Framework, verwenden und dessen Leistung anhand des Testsatzes überprüfen.

Vorhersageziel und Daten

Für die Daten wird BBBP von Molecule Net verwendet.Siehe unten für eine Vogelperspektive der Daten.

In Bezug auf die Permeabilität der Blut-Hirn-Schranke der Verbindung ist "Penetration" XNUMX und "Nicht-Penetration" XNUMX.

Modell erstellen

Umwelt

from rdkit import rdBase
import chainer
print('rdkit version: ',rdBase.rdkitVersion)
chainer.print_runtime_info()
rdkit version: 2019.03.4 Plattform: Linux-5.0.0-37-generic-x86_64-with-debian-buster-sid Chainer: 6.2.0 NumPy: 1.17.4 CuPy: CuPy Version: 6.2.0 CUDA Root: / usr / local / cuda CUDA-Build-Version: 10010 CUDA-Treiberversion: 10010 CUDA-Laufzeitversion: 10010 cuDNN Build-Version: 7500 cuDNN-Version: 7605 NCCL-Build-Version: 2402 NCCL-Laufzeitversion: 2402 iDeep: Nicht verfügbar

Sie können die in chainer.print_runtime_info () verwendete Version von Chainer, Numpy, Cupy überprüfen.

Modellbau

import numpy as np
import pandas as pd
from rdkit import Chem
from rdkit.Chem import Draw, PandasTools, Descriptors
 
# データの読み込み
df = pd.read_csv('BBBP.csv',index_col=0)
 
# smilesからmolファイルを生成し、データフレーム中に加える
PandasTools.AddMoleculeColumnToFrame(df, smilesCol = 'smiles')
 
# molができなかった行を削除する
df = df.dropna()
 
# molファイルから化合物記述子を算出する
for i,j in Descriptors.descList:
    df[i] = df['ROMol'].map(j)
df['Ipc'] = [Descriptors.Ipc(mol, avg=True) for mol in df['ROMol']]  
 
# chainer用にデータ型を変換
x = df.iloc[:,4:].values.astype('float32')
y = df['p_np'].values.astype('int32')
indices = np.array(range(x.shape[0])) # train_test_split後も列番号を保持しておく
 
# train, test, valに分割
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test, indices_train, indices_test = train_test_split(x, y, indices, test_size=0.05, random_state=123)
 
# 説明変数の標準化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(x_train)
x_train= scaler.transform(x_train)
x_test = scaler.transform(x_test)
 
print(type(x_train), x_train.shape, type(y_train), y_train.shape)
print(type(x_test), x_test.shape, type(y_test), y_test.shape)
(1937, 200) (1937) (102, 200) (102,) 

Hier finden Sie Informationen zum Erstellen von Deskriptoren aus Mol-Objekten.
Berechnen Sie molekulare Deskriptoren und Fingerabdrücke aus SMILES und speichern Sie sie in einem Datenrahmen [Python, RDKit]

Die offiziellen Tutorials zur Verwendung von Chainer sind sehr umfangreich.
Erste Schritte mit dem Deep Learning Chainer Tutorial

# 説明変数と目的変数のセットで使えるように変換する
from chainer.datasets import TupleDataset
train = TupleDataset(x_train, y_train)
test = TupleDataset(x_test, y_test)
 
# イテレータの準備
from chainer.iterators import SerialIterator
train_iter = SerialIterator(train, batch_size=64, repeat=True, shuffle=True)
test_iter = SerialIterator(test, batch_size=64, shuffle=False, repeat=False)
 
# ニューラルネットワークの作成
# 3層のmulti layer perceptron(MLP)
import chainer.links as L
import chainer.functions as F
from chainer import Chain
from chainer import optimizers, training
from chainer.training import extensions

class MLP(chainer.Chain):
 
    def __init__(self):
        super().__init__()
        with self.init_scope():
            self.fc1 = L.Linear(None, 100)
            self.fc2 = L.Linear(None, 20)
            self.fc3 = L.Linear(None, 2)
 
    def forward(self, x):
        h = F.relu(self.fc1(x))
        h = F.relu(self.fc2(h))
        h = self.fc3(h)
        return h
 
# ネットワークをClassifierでラップしする
# (目的関数(デフォルトはsoftmax交差エントロピー)の計算し、損失を返す)
predictor = MLP()
net = L.Classifier(predictor)
 
# 最適化手法を選択して、オプティマイザを作成する
optimizer = optimizers.MomentumSGD(lr=0.1).setup(net)
 
# アップデータにイテレータとオプティマイザを渡す
updater = training.StandardUpdater(train_iter, optimizer, device=-1)
trainer = training.Trainer(updater, (50, 'epoch'), out='/results/')
from chainer.training import extensions
 
trainer.extend(extensions.LogReport(trigger=(5, 'epoch'), log_name='log'))
trainer.extend(extensions.snapshot(filename='snapshot_epoch-{.updater.epoch}'))
trainer.extend(extensions.dump_graph('main/loss'))
trainer.extend(extensions.Evaluator(test_iter, net, device=-1), name='val')
trainer.extend(extensions.PrintReport(['epoch', 'iteration', 'main/loss', 'main/accuracy', 'val/main/loss', 'val/main/accuracy', 'fc1/W/data/mean', 'elapsed_time']))
trainer.extend(extensions.PlotReport(['fc1/W/grad/mean'], x_key='epoch', file_name='mean.png'))
trainer.extend(extensions.PlotReport(['main/loss', 'val/main/loss'], x_key='epoch', file_name='loss.png'))
trainer.extend(extensions.PlotReport(['main/accuracy', 'val/main/accuracy'], x_key='epoch', file_name='accuracy.png'))
trainer.extend(extensions.ParameterStatistics(net.predictor.fc1, {'mean': np.mean}, report_grads=True))
 
trainer.run()
from IPython.display import Image, display
display(Image(filename='results/accuracy.png'))

Es scheint, dass die Genauigkeit angemessen ist, aber die Genauigkeit für den Testsatz hat sich nicht wesentlich verbessert, selbst wenn das Lernen fortschreitet ...

Inferenz

# 学習したモデルで推論してみる
with chainer.using_config('train', False), chainer.using_config('enable_backprop', False):
    y_pred = predictor(x_test)
 
# 推論結果の確認
print('accuracy', F.accuracy(y_pred, y_test)) # accuracy variable(0.88235295)
 
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test, y_pred.data.argmax(axis=1))
 Array ([[21, 7], [5, 69]]) 

Genauigkeit ist ein Wert, wie Sie aus der Abbildung sehen können.Bei der Bewertung der Genauigkeit der Klassifizierung durch die Verwirrungsmatrix gibt es falsch positive und falsch negative Ergebnisse, aber es scheint, dass die Genauigkeit nicht durch die Klassifizierung erreicht wird, die auf eine Seite verzerrt ist.

# 一部予測結果を見てみる
for i in range(int(len(y_pred)/10)):
    print('No.', indices_test[i])
    print('label:', y_test[i])
    print('pred :', np.argmax(y_pred[i].array))
    img = Draw.MolToImage(df.ROMol[indices_test[i]])
    display(img)

Das Bild ist Teil der Ausgabe, aber die richtige Antwort ist, dass es vom menschlichen Auge erkannt werden kann.Es scheint Spaß zu machen, zu überprüfen, was Sie einen Fehler gemacht haben.