Probeer een eenvoudig QSAR-model met Chainer [Voorspellen van de doorlaatbaarheid van de bloed-hersenbarrière van verbindingen]

2020 年 3 月 2 日

QSAR (kwantitatieve structuur-activiteitsrelatie) is een statistische correlatie tussen de structuur van een chemische stof en zijn fysiologische activiteit (toxiciteit, vermogen om aan enzymen te binden, activiteit als medicijn, enz.).De prestaties van verbindingen kunnen worden voorspeld op basis van correlaties op basis van uitgebreide experimentele gegevenssets van chemicaliën.

Deze keer zullen we een eenvoudig QSAR-model maken dat "de permeabiliteit van de bloed-hersenbarrière van een verbinding voorspelt" met behulp van Chainer, een diepgaand leerkader gemaakt in Japan, en de prestaties ervan verifiëren met een testset.

Voorspellingsdoel en gegevens

Voor gegevens wordt BBBP van Molecule Net gebruikt.Zie hieronder voor een overzicht van de gegevens in vogelvlucht.

Met betrekking tot de permeabiliteit van de bloed-hersenbarrière van de verbinding is "penetratie" XNUMX en "niet-penetratie" XNUMX.

Een model maken

環境

from rdkit import rdBase
import chainer
print('rdkit version: ',rdBase.rdkitVersion)
chainer.print_runtime_info()
rdkit-versie: 2019.03.4 Platform: Linux-5.0.0-37-generic-x86_64-met-debian-buster-sid Chainer: 6.2.0 NumPy: 1.17.4 CuPy: CuPy Versie: 6.2.0 CUDA Root: / usr / local / cuda CUDA Build-versie: 10010 CUDA Driver-versie: 10010 CUDA Runtime-versie: 10010 cuDNN Build-versie: 7500 cuDNN-versie: 7605 NCCL Build-versie: 2402 NCCL Runtime-versie: 2402 iDeep: niet beschikbaar

U kunt de versie van Chainer, Numpy, Cupy controleren die wordt gebruikt in chainer.print_runtime_info ().

Model gebouw

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,) 

Zie hier voor het maken van descriptoren van mol-objecten.
Bereken de moleculaire descriptor en vingerafdruk van SMILES en sla deze op in het dataframe [Python, RDKit]

De officiële tutorials over het gebruik van Chainer zijn erg uitgebreid.
Aan de slag met Deep Learning Chainer-zelfstudie

# 説明変数と目的変数のセットで使えるように変換する
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'))

Het lijkt erop dat de nauwkeurigheid redelijk is, maar de nauwkeurigheid van de testset is niet veel verbeterd, zelfs niet naarmate het leren vordert ...

gevolgtrekking

# 学習したモデルで推論してみる
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))
 matrix ([[21, 7], [5, 69]]) 

nauwkeurigheid is een waarde zoals je kunt zien in de figuur.Bij het evalueren van de nauwkeurigheid van classificatie door de verwarringmatrix, zijn er vals-positieven en vals-negatieven, maar het lijkt erop dat de nauwkeurigheid niet wordt verkregen door de classificatie die naar één kant is vertekend.

# 一部予測結果を見てみる
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)

Het beeld is een onderdeel van de output, maar het juiste antwoord is dat het door het menselijk oog kan worden onderscheiden.Het lijkt me leuk om te onderzoeken wat je een fout hebt gemaakt.