Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@kimisyo

DeepChemで欠損値を含む列を除去するTransformerを書いてみる

More than 1 year has passed since last update.

はじめに

前回mordredをDeepChemのFeaturizerとして使う の記事でmordredで計算エラーが発生した場合0に置き換えていた。しかし前回もお伝えしたように通常はnanを含む記述子そのものを取り除くか、nanをそのまま欠損値を処理できるアルゴリズムに投入することが一般的に行われる。今回は、DeepChemのTransformerを継承し、欠損値を除去するTransformerを作成し、このTransformerによりnp.nanが含まれる記述子を取り除いて学習できるようにしたのでここにメモっておく。

環境

  • python 3.6
  • deepchem 2.2.1.dev54
  • rdkit 2019.03.3.0
  • morded 1.1.2

前回のソースの修正

まずは、前回のソースの修正として、MordredDescriptor.pyをエラーが発生した場合に0ではなくnumpyのnanを格納するよう修正する。

MordredDescriptor.py
from deepchem.feat import Featurizer
from mordred import Calculator, descriptors
import numpy as np

class MordredDescriptors(Featurizer):
    """
    Mordred descriptors.
    """
    name = 'descriptors'

    def __init__(self, ignore_3D=True):

        self.mordred_calculator = Calculator(descriptors, ignore_3D=ignore_3D)

        # 記述子名-計算関数の対応を保持
        self.descs = {}
        self.counter = 0

        for i, desc in enumerate(self.mordred_calculator.descriptors):
          self.descs[desc.__str__()] = desc

    def _featurize(self, mol):
      ret = []
      for desc in self.descs:
        try:
          ret.append(self.descs[desc](mol))
        except Exception as e:
          ret.append(np.nan)

      self.counter = self.counter + 1
      print(self.counter)

      return ret

Transformerの作成

準備は整ったので、欠損値を含む列を除去するTransformerを書いてみよう。
DeepChemのClippingTransformerや、NomalizationTransformerを参考にし、以下の通り作成した。
まず、コンストラクタでdatasetを受け取り、記述子データである"X"を取り出し、np.nanを含まない列かどうかのBoolean配列を取得し、private変数として保持する。
そして、tansoform_arrayメソッドで、そのBoolean配列の中でTrueをもつ列のみを記述子データを返却するようにする。

MissingValueElminatorTransformer.py
import numpy as np
from deepchem.trans.transformers import Transformer

#----------------------------------------------------
# #参考文献
# -[numpy配列からnanの列を除去する参考URL](https://note.nkmk.me/python-numpy-nan-remove/)
# -[Source code for deepchem.trans.transformers](https://deepchem.io/docs/_modules/deepchem/trans/transformers.html)
#----------------------------------------------------

class MissingValueElminateTransformer(Transformer):

    def __init__(self,
                 transform_X=False,
                 transform_y=False,
                 transform_w=False,
                 dataset=None,
                 transform_gradients=False):

        """Initialize normalization transformation."""

        if transform_X:
            X = dataset.X
            self.X_support = ~np.isnan(X).any(axis=0)

        super().__init__(
        transform_X=transform_X,
        transform_y=transform_y,
        transform_w=transform_w,
        dataset=dataset)


    def transform(self, dataset, parallel=False):
        return super().transform(dataset, parallel=parallel)


    def transform_array(self, X, y, w):

        X = X[:, self.X_support]

        return (X, y, w)


    def untransform(self, z):
        raise NotImplementedError(
            "Cannot untransform datasets with MissingValueElminateTransformer.")

使い方

MissingValueElminateTransformer(transform_X=True, dataset=train_dataset)のような感じで初期化してあげれれば、その後の使い方は他のTransformerと全く同様だ。例によってmetris以下は適当に書いているので各自修正してほしい。

import rdkit.Chem
from rdkit import Chem

import deepchem as dc
from deepchem.models.tensorgraph.models.graph_models import GraphConvModel
from deepchem.feat import RDKitDescriptors, ConvMolFeaturizer, CoulombMatrix, RdkitGridFeaturizer

from MordredDescriptors import MordredDescriptors
from MissingValueElminateTransformer import MissingValueElminateTransformer

# mordredのfeaturizerを定義
featurizer = MordredDescriptors()

# 学習データの読み込み
loader = dc.data.CSVLoader(tasks=["LogS"],
                               id_field="CompoundID",
                               smiles_field="smiles",
                               featurizer=featurizer)

dataset = loader.featurize("../ESOL/data/delaney-processed.csv")
splitter = dc.splits.RandomSplitter(dataset)

train_dataset, valid_dataset, test_dataset = splitter.train_valid_test_split(dataset, frac_train=0.8,
                                                                               frac_valid=0.1, frac_test=0.1)

# 欠損値除去するTrnasformerを追加
transformers = [
        MissingValueElminateTransformer(transform_X=True, dataset=train_dataset),
        dc.trans.NormalizationTransformer(transform_y=True, dataset=train_dataset)
    ]

for transformer in transformers:
    train_dataset = transformer.transform(train_dataset)
    valid_dataset = transformer.transform(valid_dataset)
    test_dataset = transformer.transform(test_dataset)

metric = dc.metrics.Metric(dc.metrics.r2_score)
optimizer = dc.hyper.HyperparamOpt(get_builder(), verbose=True)
params_dict = {"xxx:yyy"}
best_model, best_model_hyperparams, all_model_results = optimizer.hyperparam_search(params_dict, train_dataset, valid_dataset, transformers, metric=metric)

おわりに

DeepChemでここまで既存記述子の使用にこだわる必要があるのか?という気もするが、既存手法とGCN(Graph Convolution Network)をフェアに比較しようとした場合、DeepChemの上で既存手法を使えるにするのがよいと判断する。(と前向きに自分を奮い立たせてみる)

参考文献

1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
kimisyo
主にライフサイエンス分野向けサービス開発を行っています。これからはライフサイエンスの時代です。化学、AI(機械学習)を中心に、学んだこと、経験したことをシェアしていきます。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
1
Help us understand the problem. What is going on with this article?