ファイル形式(MOL,SDF)
コンピュータで画像を保存する場合、jpeg,png,gifなどの特定の形式でファイルにデータを保存すると思います。
それと同じように、化合物の構造を保存する場合にも、特定の形式でファイルに保存することができます。
(ここでは、化合物の構造とは3次元の構造を想定していますが、2次元の場合もあります。)
画像データに様々な形式があるように、化合物の構造データの場合にもいくつかの形式があります。 この記事では、その中でも多くの場合で用いられるMOL形式(.mol)1、SDF形式(.sdf)について、Python + RDKit2で扱う方法を説明します。 また、最後にファイル形式そのものについても少し説明します。
動作確認環境
- Ubuntu 16.04 (VirtualBox + Vagrant)
- Python 3.5.2
- RDKit 2017.03.2
見出し
MOL形式とSDF形式
まず初めに、MOL形式やSDF(Structure Data File)形式がどういうものかということについて軽く説明します。
これらはいずれも分子内の原子の座標を記録したものであり、行列表記法とも呼ばれます。
また、この2つといくつかの派生した形式を総称してCTfileという名前がつけられています。
MOL形式とSDF形式の最も大きな違いは、1ファイルにつき1化合物か複数化合物かということです。
実は、SDF形式の中で実際に構造を表す部分はMOL形式がそのまま使われています。
SDF形式ではそれに加えて物性値など、構造以外の情報も保存することができます。
MOLファイルの読み書き
それでは、MOLファイルを扱う方法を説明していきます。
例として、molecule.mol
という名前のMOLファイルを扱うとします。
まずは使用するRDKitのモジュールをインポートしておきます。
from rdkit import Chem
以下では常にこのようにインポートされているとします。
読み込み
MOLファイルを読み込む場合は以下のようにします。
mol=Chem.MolFromMolFile('molecule.mol')
... (分子に対する操作)
たいていの場合はこれでよいのですが、このままでは水素原子の情報は読み込まれません。
というのも、分子の骨格が分かれば水素原子がどこにあるべきかが分かり、画像にする場合も水素原子は表示しないことが多いからです。
水素原子の情報も必要なら、キーワード引数で以下のように指定できます。
mol=Chem.MolFromMolFile('molecule.mol',removeHs=False)
書き込み
mol
という変数に読み込んである情報をファイルに保存したい場合は、次のようにします。
Chem.MolToMolFile(mol,'molecule.mol')
多くのファイル形式はこのようにMolFrom{形式名}
,MolTo{形式名}
のような関数で読み書きすることができます。
SDFファイルの読み書き
次にSDFファイル3の場合を見ていきます。
読み込み
SDFファイルの読み込みをする方法は、MOLファイルで説明した方法とは異なります。
例として、molecules.sdf
という名前のSDFファイルから水素原子を含めて読み込む場合は次のようにします。
sup=Chem.ForwardSDMolSupplier('molecules.sdf',removeHs=False)
for mol in sup:
...
データが多くファイルサイズが大きい場合、SDFファイルがgzip形式で圧縮されていることもありますが、解凍せずとも読み込むことができます。
import gzip
sdf_gz=gzip.open('molecules.sdf.gz')
sup=Chem.ForwardSDMolSupplier(sdf_gz,removeHs=False)
for mol in sup:
...
RDKitには、ForwardSDMolSupplier
というクラスの他にSDMolSupplier
というクラスもあり、基本的には同じように使えます。
こちらは、gzip.open()
などでファイルを開いてからファイルオブジェクトとして与えることはできなくなりますが、sup[3]
などのようにインデックスで要素にアクセスをすることが可能になります。
ただし、SDFファイル中にRDKitで正しく読み込めない分子があった場合、そこにはNoneが入るため、そのチェックをしなければならないことが多いです。
具体的にはforループの中で
if mol is None: continue
というような記述をするか、インデックスでアクセスしたい場合は内包表現を利用し、
mols=[mol for mol in Chem.SDMolSupplier(‘molecules.sdf’) if mol is not None]
として(Forward版でもよいです)、分子を全て読み込んでNoneを除いたリストを作ることもできます。
プロパティの読み込み
SDFファイルには構造以外の情報も保存でき、プロパティと呼ばれます。
例えば、prop_name
という名前のプロパティの値を得たい場合は、次のいずれかを利用します。
# mol はSDFから読み込んだ分子
prop=mol.GetProp('prop_name') # => str型
prop=mol.GetIntProp('prop_name') # => 可能であれば int型
prop=mol.GetUnsignedProp('prop_name') # => 可能であれば int型 (非負)
prop=mol.GetDoubleProp('prop_name') # => 可能であれば float型
prop=mol.GetBoolProp('prop_name') # => 可能であれば bool型
値をどの型で受け取りたいかによって使う関数が変わりますが、それぞれの型に変換できない可能性がある場合はstr型で受け取っておくと安全です。
どのような名前のプロパティがあるか分からない場合は、設定されているプロパティの名前一覧を得ることができます。
names=list(mol.GetPropNames())
全てのプロパティを一度に得たい場合は、プロパティ名をkeyとした辞書型で得ることもできます。
props=mol.GetPropAsDict()
書き込み
分子データのリストmol_list
からSDFファイルを作成する場合は以下のようにします。
writer=Chem.SDWriter('molecules.sdf')
for mol in mol_list:
writer.write(mol)
writer.close()
プロパティの書き込み
プロパティを設定したい場合、まず各分子に対して値を設定します。
mol
に対して、prop_name
という名前のプロパティをprop_val
という値に設定する場合。
mol.SetProp('prop_name',prop_val) # str型
mol.SetIntProp('prop_name',prop_val) # int型
mol.SetUnsignedProp('prop_name',prop_val) # int型 (非負)
mol.SetDoubleProp('prop_name',prop_val) # float型
mol.SetBoolProp('prop_name',prop_val) # bool型
そして、names
をSDFファイルに記入するプロパティ名のリストまたはタプルとして、
writer=SDWriter('molecules.sdf')
writer.SetProps(names)
for mol in mol_list:
writer.write(mol)
writer.close()
とすることで、プロパティを含めてSDFとして保存することができます。
※確認した環境ではbool型のプロパティをファイルに書き込むと、Trueは1、Falseは0と書き込まれました。
このようにbool型はファイルに直接記述できないため、あまり用いない方が良いと思われます。
具体的なファイル形式
ここまでファイルの扱い方を見てきましたが、そのファイルの中身についてはほとんど触れませんでした。
これらのファイルの拡張子は.molや.sdfになっていますが、中身はテキストデータなので一般的なエディタで開き、読むことができます。
ここからは、具体的にファイルの中身がどうなっているのかを見ていきたいと思います。
MOLファイルフォーマット
MOLファイルを開いてみると、以下のようになっていると思います。 以下はPubChemデータベースから得たエタノールのデータです。
702
-OEChem-11201721003D
9 8 0 0 0 0 0 0 0999 V2000
-1.1712 0.2997 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
-0.0463 -0.5665 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1.2175 0.2668 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.0958 -1.2120 0.8819 H 0 0 0 0 0 0 0 0 0 0 0 0
-0.0952 -1.1938 -0.8946 H 0 0 0 0 0 0 0 0 0 0 0 0
2.1050 -0.3720 -0.0177 H 0 0 0 0 0 0 0 0 0 0 0 0
1.2426 0.9307 -0.8704 H 0 0 0 0 0 0 0 0 0 0 0 0
1.2616 0.9052 0.8886 H 0 0 0 0 0 0 0 0 0 0 0 0
-1.1291 0.8364 0.8099 H 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
1 9 1 0 0 0 0
2 3 1 0 0 0 0
2 4 1 0 0 0 0
2 5 1 0 0 0 0
3 6 1 0 0 0 0
3 7 1 0 0 0 0
3 8 1 0 0 0 0
M END
これは、次のような構成になっています。
行 | 内容 |
---|---|
1行目 | 分子の名前やID(702) |
2行目 | プログラム名(-OEChem-)、作成日時(11/20/17 21:00)、次元(3D)など |
3行目 | コメント |
4行目 | 原子数(9)、結合数(8)、… |
(原子数)行 | Atomブロック x座標、y座標、z座標、元素記号、… |
(結合数)行 | Bondブロック 原子1、原子2、結合次数、… |
残り | Propertiesブロック |
最終行 | M END |
…と書いた部分は、意味を持つ部分もありますが、あまり重要ではないため省略しています。
また、ファイル全体を通して細かい指定がいくつもありますが、もし必要ならばCTfileフォーマットの仕様書を参照してください。
1行目、3行目は書いた通りの意味で、特に無ければ空行となります。
2行目は、データを作成したプログラム名、作成日時、座標の次元(2D or 3D)などが記入されます。
(ここまでの情報の中でRDKitで読み込まれるのは分子名と次元だけです。)
4行目は、原子数、結合本数などを表し、ここの値がこの後のAtomブロック、Bondブロックの行数になります。
Atomブロックは、各行が各原子の情報を表し、何の原子がどこにあるかを表します。
同様に、Bondブロックは各行が各結合を表し、どの原子とどの原子が何次で結合しているかを表します。
ここでの番号は、Atomブロックの何番目の原子かという意味です。
Propertiesブロックは、構造に関する補足の情報を表します。
この例では何もありませんが、イオンやラジカルとなっている原子がある場合などは、その情報が書き込まれます。
SDFファイルフォーマット
次にSDFファイルを見てみましょう。
SDFファイルは、複数分子の情報を保存でき、加えて任意の情報をプロパティとして保存できるものでした。
構造を表す部分はMOLファイルそのものなので、プロパティの部分を説明します。
以下に先ほどと同じ分子のSDFファイルの内容を示します。
702
-OEChem-11201721003D
...(MOLファイル)
M END
> <PUBCHEM_COMPOUND_CID>
702
> <PUBCHEM_CONFORMER_RMSD>
0.4
> <PUBCHEM_CONFORMER_DIVERSEORDER>
1
> <PUBCHEM_MMFF94_PARTIAL_CHARGES>
3
1 -0.68
2 0.28
9 0.4
...(中略)
> <PUBCHEM_SHAPE_VOLUME>
41.5
> <PUBCHEM_COORDINATE_TYPE>
2
5
10
$$$$
こちらは次のような構成になっています。
行 | 内容 |
---|---|
M END まで |
MOLファイル |
(M END から)1行目 |
> <プロパティ名> |
2行目〜 | プロパティの値 |
空行 | |
(上3つをプロパティ数だけ繰り返す) | |
最終行 | $$$$ |
例から分かるように、プロパティの値部分では、複数行に渡って記述することができます。
複数分子の情報を持ったSDFファイルの場合は、上の例のようなブロックが分子の数だけ繰り返されています。
まとめ
この記事では化合物の構造を保持するMOL形式、SDF形式について、PythonとRDKitを用いて扱う方法と、ファイル形式についての説明をしてきました。
これで化合物データをPythonで扱えるようになったので、機械学習を行う最も基礎となる部分ができたことになります。
また、今回使用したRDKitには多くの関数、クラスが定義されており、画像として表示することから、立体配座の生成など、それ単体でも様々なことを行うことができます。
是非こちらも様々な機能を利用してみてください。
(文責: @rkat0)