<jupyter_start><jupyter_text>プログラミング未経験者のためのデータ解析・機械学習 第 12 章　化学構造を扱う  Jupyter Notebook の有用なショートカットのまとめ- Esc: コマンドモードに移行（セルの枠が青）- Enter: 編集モードに移行（セルの枠が緑）- コマンドモードで M: Markdown セル (説明・メモを書く用) に変更- コマンドモードで Y: Code セル (Python コードを書く用) に変更- コマンドモードで H: ヘルプを表示- コマンドモードで A: ひとつ**上**に空のセルを挿入- コマンドモードで B: ひとつ**下**に空のセルを挿入- コマンドモードで DD: セルを削除- Ctrl+Enter: セルの内容を実行- Shift+Enter: セルの内容を実行して下へ わからないことがありましたら、関係する単語やエラーの文章などでウェブ検索してご自身で調べてみましょう。 下のセルを実行して、RDKit version: 2020.03.2 と表示されれば (バージョンは変わるかもしれません)、RDKit のインストールは成功です。「RDKit WARNING: …」というメッセージが出た場合も問題なくインストールは成功しています。<jupyter_code>from rdkit import rdBase
print('RDKit version: {0}'.format(rdBase.rdkitVersion))<jupyter_output><empty_output><jupyter_text>化学構造の表現方法  SMILES<jupyter_code>from rdkit import Chem<jupyter_output><empty_output><jupyter_text>分子の SMILES を直接書くことは普通はなく、基本的にはウェブサービスや構造式描画ソフトウェアで描画して、それを SMILES に変換することで SMILES を作成しますが、今回は簡単な化学構造を扱い SMILES を直接書いて、RDKit で扱える形式に変換します。<jupyter_code>alanine_from_smiles = Chem.MolFromSmiles('CC(N)C(=O)O') # アラニンの SMILES を読み込みます
type(alanine_from_smiles) # rdkit.Chem.rdchem.Mol と表示されます。Mol 型の変数です。<jupyter_output><empty_output><jupyter_text>Mol 型の変数を直接扱うことはなく RDKit の関数を介して扱います。<jupyter_code>Chem.MolToSmiles(alanine_from_smiles) # Mol 型の変数から SMILES の文字列に変換できます<jupyter_output><empty_output><jupyter_text>分子の描画<jupyter_code>from rdkit.Chem import Draw
Draw.MolToImage(alanine_from_smiles)<jupyter_output><empty_output><jupyter_text>水素原子が自動的に付加されています。  【練習】エタノール、ベンゼンについて、それぞれテキストにある SMILES を用いて分子として読み込み、描画してみましょう。コード例は一番下にあります。  MOL file<jupyter_code>alanine_from_molfile = Chem.MolFromMolFile('alanine.mol') # アラニンの MOL file を読み込みます
type(alanine_from_molfile) # rdkit.Chem.rdchem.Mol と表示されます。Mol 型の変数です
Chem.MolToSmiles(alanine_from_molfile) # Mol 型の変数から SMILES の文字列に変換できます<jupyter_output><empty_output><jupyter_text>分子の描画<jupyter_code>Chem.Draw.MolToImage(alanine_from_molfile)<jupyter_output><empty_output><jupyter_text>水素原子が自動的に付加されています。  【練習】エタノール、ベンゼンについて、MOL file を分子として読み込み、描画してみましょう。それぞれの MOL file は ethanol.mol、 benzene.mol です。コード例は一番下にあります。  化合物群の扱い SMILES に基づくデータベース  SMILES付き沸点のデータセット (molecules_with_boiling_point.csv)Hall and Story が収集した[沸点のデータセット](https://pubs.acs.org/doi/abs/10.1021/ci960375x)。294 個の化合物について、SMILES と測定された沸点 (Boiling Point) が格納された csv ファイルです。<jupyter_code>import pandas as pd
dataset = pd.read_csv('molecules_with_boiling_point.csv', index_col=0) # SMILES付き沸点のデータセットの読み込み
dataset # 念のため確認
y = dataset.iloc[:, 1]
y<jupyter_output><empty_output><jupyter_text>リスト型の変数 `molecules_from_smiles` に、SMILES から変換した分子を追加していきます。<jupyter_code>molecules_from_smiles = [] # 空のリスト型の変数
for smiles in dataset.iloc[:, 0]:
    molecules_from_smiles.append(Chem.MolFromSmiles(smiles))
len(molecules_from_smiles)<jupyter_output><empty_output><jupyter_text>MOL file に基づくデータベース  沸点のデータセットの sdf ファイル (molecules_with_boiling_point.sdf)Hall and Story が収集した[沸点のデータセット](https://pubs.acs.org/doi/abs/10.1021/ci960375x)。294 個の化合物の化学構造情報と沸点 (Boiling Point) が一緒に格納された sdf ファイルです。<jupyter_code>sdf = Chem.SDMolSupplier('molecules_with_boiling_point.sdf')<jupyter_output><empty_output><jupyter_text>化合物ごとに、リスト型の変数 `y_from_sdf` に物性値を、リスト型の変数 `molecules_from_sdf` に Mol 型の化学構造情報を追加していきます。<jupyter_code>y_from_sdf = []
molecules_from_sdf = []
for molecule in sdf:
    y_from_sdf.append(float(molecule.GetProp('BoilingPoint')))
    molecules_from_sdf.append(molecule)
len(molecules_from_sdf) # 念のため確認
y_from_sdf = pd.DataFrame(y_from_sdf) # DataFrame 型に変換
y_from_sdf.columns = ['BoilingPoint']
y_from_sdf # 念のため確認<jupyter_output><empty_output><jupyter_text>化学構造の数値化<jupyter_code>from rdkit.Chem import Descriptors
from rdkit.ML.Descriptors import MoleculeDescriptors
Descriptors.descList<jupyter_output><empty_output><jupyter_text>記述子の名前を取得します。リスト型の変数 `descriptor_names` に記述子の名前を追加していきます。<jupyter_code>descriptor_names = []
for descriptor_information in Descriptors.descList:
    descriptor_names.append(descriptor_information[0])
descriptor_names # 念のため確認
len(descriptor_names)
descriptor_calculator = MoleculeDescriptors.MolecularDescriptorCalculator(descriptor_names)<jupyter_output><empty_output><jupyter_text>記述子を計算します。計算終了まで少し時間がかかります。<jupyter_code>descriptors = []
smiles = []
for molecule in molecules_from_smiles:
    descriptors.append(descriptor_calculator.CalcDescriptors(molecule))
    smiles.append(Chem.MolToSmiles(molecule))
descriptors = pd.DataFrame(descriptors) # DataFrame 型に変換
descriptors.columns = descriptor_names # 列名を記述子名に
descriptors.index = smiles # 行名を SMILES に
descriptors # 念のため確認
descriptors.to_csv('descriptors.csv') # csv ファイルに保存。同じ名前のファイルがあるときは上書きされますので注意してください<jupyter_output><empty_output><jupyter_text>`descriptors` をこれまでの連載における `x` とすることで、化学構造のデータセットでもデータの可視化・クラスタリング・クラス分類・回帰分析などができるようになります。  化学構造のデータセットを扱うときの注意点およびデータセットの前処理 データセットのトレーニングデータとテストデータへの分割<jupyter_code>from sklearn.model_selection import train_test_split
# ランダムにトレーニングデータとテストデータとに分割。random_state に数字を与えることで、別のときに同じ数字を使えば、ランダムとはいえ同じ結果にすることができます
x_train, x_test, y_train, y_test = train_test_split(descriptors, y, test_size=94, shuffle=True, random_state=99)
x_train.std()<jupyter_output><empty_output><jupyter_text>標準偏差が 0 の記述子があることを確認しましょう。標準偏差が 0 では、変数の標準化 (オートスケーリング) のときに 0 で割ることになってしまいます。標準偏差が 0 の記述子を削除します。<jupyter_code>x_train.std() == 0 # 標準偏差が 0 の記述子だけ True
x_train.columns[x_train.std() == 0] # 標準偏差が 0 の記述子
len(x_train.columns[x_train.std() == 0]) # 標準偏差が 0 の記述子の数
x_train_new = x_train.drop(x_train.columns[x_train.std() == 0], axis=1) # トレーニングデータから標準偏差が 0 の記述子を削除
x_train_new.shape # 大きさを確認
x_test_new = x_test.drop(x_train.columns[x_train.std() == 0], axis=1) # テストデータから標準偏差が 0 の記述子を削除
x_test_new.shape # 大きさを確認<jupyter_output><empty_output><jupyter_text>記述子の標準化 (オートスケーリング)<jupyter_code>autoscaled_x_train = (x_train_new - x_train_new.mean()) / x_train_new.std() # トレーニングデータの説明変数の標準化。x_train の代わりに x_train_new を用います
autoscaled_x_test = (x_test_new - x_train_new.mean()) / x_train_new.std() # テストデータの説明変数の標準化。x_train の代わりに x_train_new を、x_test の代わりに x_test_new を用います
autoscaled_y_train = (y_train - y_train.mean()) / y_train.std() # トレーニングデータの目的変数の標準化<jupyter_output><empty_output><jupyter_text>【練習】molecules_with_logS.csv, molecules_with_logS.sdf それぞれについて、データセットを読み込み、化学構造に対して記述子を計算しましょう。さらに、サンプル全体の 3 割をテストデータにしたときに、トレーニングデータにおいて標準偏差が 0 になる記述子を、トレーニングデータ・テストデータそれぞれで削除して、オートスケーリングしましょう。コード例は一番下にあります。  SMILES付き水溶解度のデータセット (molecules_with_logS.csv)Hou et al. が収集した[水溶解度のデータセット](https://pubs.acs.org/doi/abs/10.1021/ci034184n)。1290 個の化合物について、SMILESと水溶解度の対数値 logS が格納された csv ファイルです。  水溶解度のデータセットの sdf ファイル (molecules_with_logS.sdf)Hou et al. が収集した[水溶解度のデータセット](https://pubs.acs.org/doi/abs/10.1021/ci034184n)。1290 個の化合物の化学構造情報と水溶解度の対数値 logS が一緒に格納された sdf ファイルです。  【コード例】エタノール、ベンゼンについて、それぞれテキストにある SMILES を用いて分子として読み込み、描画してみましょう。<jupyter_code>ethanol_from_smiles = Chem.MolFromSmiles('CCO') # エタノール
Draw.MolToImage(ethanol_from_smiles)
benzene_from_smiles = Chem.MolFromSmiles('c1ccccc1') # ベンゼン
Draw.MolToImage(benzene_from_smiles)<jupyter_output><empty_output><jupyter_text>【コード例】エタノール、ベンゼンについて、mol ファイルを分子として読み込み、描画してみましょう。それぞれの MOL file は ethanol.mol、 benzene.mol です。<jupyter_code>ethanol_from_molfile = Chem.MolFromMolFile('ethanol.mol') # エタノール
Draw.MolToImage(ethanol_from_molfile)
benzene_from_molfile = Chem.MolFromMolFile('benzene.mol') # ベンゼン
Draw.MolToImage(benzene_from_molfile)<jupyter_output><empty_output><jupyter_text>【コード例】molecules_with_logS_smiles.csv, molecules_with_logS.sdf それぞれについて、データセットを読み込み、化学構造に対して記述子を計算しましょう。さらに、サンプル全体の 3 割をテストデータにしたときに、トレーニングデータにおいて標準偏差が 0 になる記述子を、トレーニングデータ・テストデータそれぞれで削除して、オートスケーリングしましょう。 SMILES に基づくデータベースの場合<jupyter_code>import pandas as pd
from rdkit import Chem
from rdkit.Chem import Descriptors
from rdkit.ML.Descriptors import MoleculeDescriptors
dataset = pd.read_csv('molecules_with_logS.csv', index_col=0) # SMILES付き水溶解度のデータセットの読み込み
dataset # 念のため確認
y = dataset.iloc[:, 1]
y<jupyter_output><empty_output><jupyter_text>リスト型の変数 `molecules_from_smiles` に SMILES から変換した分子を追加していきます。<jupyter_code>molecules_from_smiles = [] # 空のリスト型の変数
for smiles in dataset.iloc[:, 0]:
    molecules_from_smiles.append(Chem.MolFromSmiles(smiles))
len(molecules_from_smiles)<jupyter_output><empty_output><jupyter_text>記述子の名前を取得します。リスト型の変数 `descriptor_names` に記述子の名前を追加していきます。<jupyter_code>descriptor_names = []
for descriptor_information in Descriptors.descList:
    descriptor_names.append(descriptor_information[0])
descriptor_names # 念のため確認
len(descriptor_names)<jupyter_output><empty_output><jupyter_text>記述子を計算します。<jupyter_code>descriptor_calculator = MoleculeDescriptors.MolecularDescriptorCalculator(descriptor_names)
descriptors = []
smiles = []
for molecule in molecules_from_smiles:
    descriptors.append(descriptor_calculator.CalcDescriptors(molecule))
    smiles.append(Chem.MolToSmiles(molecule))
descriptors = pd.DataFrame(descriptors) # DataFrame 型に変換
descriptors.columns = descriptor_names # 列名を記述子名に
descriptors.index = smiles # 行名を SMILES に
descriptors # 念のため確認
descriptors.to_csv('descriptors.csv') # csv ファイルに保存。同じ名前のファイルがあるときは上書きされますので注意してください<jupyter_output><empty_output><jupyter_text>`descriptors` をこれまでの連載における `x` とすることで、化学構造のデータセットでもデータの可視化・クラスタリング・クラス分類・回帰分析などができるようになります。 データセットのトレーニングデータとテストデータへの分割<jupyter_code>from sklearn.model_selection import train_test_split
# ランダムにトレーニングデータとテストデータとに分割。random_state に数字を与えることで、別のときに同じ数字を使えば、ランダムとはいえ同じ結果にすることができます
x_train, x_test, y_train, y_test = train_test_split(descriptors, y, test_size=387, shuffle=True, random_state=99)
x_train.std() == 0 # 標準偏差が 0 の記述子だけ True
x_train.columns[x_train.std() == 0] # 標準偏差が 0 の記述子
len(x_train.columns[x_train.std() == 0]) # 標準偏差が 0 の記述子の数
x_train_new = x_train.drop(x_train.columns[x_train.std() == 0], axis=1) # トレーニングデータから標準偏差が 0 の記述子を削除
x_train_new.shape # 大きさを確認
x_test_new = x_test.drop(x_train.columns[x_train.std() == 0], axis=1) # テストデータから標準偏差が 0 の記述子を削除
x_test_new.shape # 大きさを確認<jupyter_output><empty_output><jupyter_text>記述子の標準化 (オートスケーリング)<jupyter_code>autoscaled_x_train = (x_train_new - x_train_new.mean()) / x_train_new.std() # トレーニングデータの説明変数の標準化。x_train の代わりに x_train_new を用います
autoscaled_x_test = (x_test_new - x_train_new.mean()) / x_train_new.std() # テストデータの説明変数の標準化。x_train の代わりに x_train_new を、x_test の代わりに x_test_new を用います
autoscaled_y_train = (y_train - y_train.mean()) / y_train.std() # トレーニングデータの目的変数の標準化<jupyter_output><empty_output><jupyter_text>SDF の場合<jupyter_code>import pandas as pd
from rdkit import Chem
from rdkit.Chem import Descriptors
from rdkit.ML.Descriptors import MoleculeDescriptors
sdf = Chem.SDMolSupplier('molecules_with_logS.sdf')<jupyter_output><empty_output><jupyter_text>化合物ごとに、リスト型の変数 `y` に物性値を、リスト型の変数 `molecules_from_sdf` に Mol 型の化学構造情報を追加していきます。<jupyter_code>y = []
molecules_from_sdf = []
for molecule in sdf:
    # y.append(molecule.GetProp('logS'))
    y.append(float(molecule.GetProp('logS')))
    molecules_from_sdf.append(molecule)
len(molecules_from_sdf) # 念のため確認
y = pd.DataFrame(y) # DataFrame 型に変換
y.columns = ['logS']
y # 念のため確認<jupyter_output><empty_output><jupyter_text>記述子の名前を取得します。リスト型の変数 `descriptor_names` に記述子の名前を追加していきます。<jupyter_code>descriptor_names = []
for descriptor_information in Descriptors.descList:
    descriptor_names.append(descriptor_information[0])
descriptor_names # 念のため確認
len(descriptor_names)<jupyter_output><empty_output><jupyter_text>記述子を計算します。<jupyter_code>descriptor_calculator = MoleculeDescriptors.MolecularDescriptorCalculator(descriptor_names)
descriptors = []
smiles = []
for molecule in molecules_from_sdf:
    descriptors.append(descriptor_calculator.CalcDescriptors(molecule))
    smiles.append(Chem.MolToSmiles(molecule))
descriptors = pd.DataFrame(descriptors) # DataFrame 型に変換
descriptors.columns = descriptor_names # 列名を記述子名に
descriptors.index = smiles # 行名を SMILES に
descriptors # 念のため確認
descriptors.to_csv('descriptors.csv') # csv ファイルに保存。同じ名前のファイルがあるときは上書きされますので注意してください<jupyter_output><empty_output><jupyter_text>`descriptors` をこれまでの連載における `x` とすることで、化学構造のデータセットでもデータの可視化・クラスタリング・クラス分類・回帰分析などができるようになります。 データセットのトレーニングデータとテストデータへの分割<jupyter_code>from sklearn.model_selection import train_test_split
# ランダムにトレーニングデータとテストデータとに分割。random_state に数字を与えることで、別のときに同じ数字を使えば、ランダムとはいえ同じ結果にすることができます
x_train, x_test, y_train, y_test = train_test_split(descriptors, y, test_size=387, shuffle=True, random_state=99)
x_train.std() == 0 # 標準偏差が 0 の記述子だけ True
x_train.columns[x_train.std() == 0] # 標準偏差が 0 の記述子
len(x_train.columns[x_train.std() == 0]) # 標準偏差が 0 の記述子の数
x_train_new = x_train.drop(x_train.columns[x_train.std() == 0], axis=1) # トレーニングデータから標準偏差が 0 の記述子を削除
x_train_new.shape # 大きさを確認
x_test_new = x_test.drop(x_train.columns[x_train.std() == 0], axis=1) # テストデータから標準偏差が 0 の記述子を削除
x_test_new.shape # 大きさを確認<jupyter_output><empty_output><jupyter_text>記述子の標準化 (オートスケーリング)<jupyter_code>autoscaled_x_train = (x_train_new - x_train_new.mean()) / x_train_new.std() # トレーニングデータの説明変数の標準化。x_train の代わりに x_train_new を用います
autoscaled_x_test = (x_test_new - x_train_new.mean()) / x_train_new.std() # テストデータの説明変数の標準化。x_train の代わりに x_train_new を、x_test の代わりに x_test_new を用います
autoscaled_y_train = (y_train - y_train.mean()) / y_train.std() # トレーニングデータの目的変数の標準化<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10155952833777102, 'fraction_numerical': 0.010726511981742107, 'mean_word_length': 10.056349873843565, 'pattern_counts': {'":': 0, '<': 125, '<?xml version=': 0, '>': 125, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '31', 'dir': 'jupyter-structured-clean-dedup', 'id': '314819', 'license': 'MIT', 'n_tokens_mistral': 7630, 'n_tokens_neox': 7369, 'n_words': 688, 'path': 'sample_program_12.ipynb', 'repo_name': 'sansyo/python_chem_chem_eng', 'size': '13145'}