USPTOの中身の反応が見たいんじゃ
USPTO
Daniel Loweさんが公開してくれている、オリジナルのデータが以下
Reactions extracted by text-mining from United States patents published between 1976 and September 2016.
米国の特許のテキストデータから化学反応を抽出してきたヤツです。テキストマイニング自体が完璧ではないので、普通に間違っている反応や重複した反応がたくさんあります。
全部ダウンロードすると重いので、2001_Sep2016_USPTOapplications_smiles.7z (83.54 MB)だけダウンロードして解凍しましょう。このファイルの中身はreaction SMILES なので、拡張子がrsmiになっています。
ipynbで反応を表示
このデータと同じディレクトリにipynbを作ります。
ipynbでファイルを読み込み、上からてきとうに見る
with open('./2001_Sep2016_USPTOapplications_smiles.rsmi', 'r') as f:
lines = f.read().splitlines()
lines[:5]
['ReactionSmiles\tPatentNumber\tParagraphNum\tYear\tTextMinedYield\tCalculatedYield',
'[C:1]([C:5]1[CH:10]=[CH:9][C:8]([OH:11])=[CH:7][CH:6]=1)([CH3:4])([CH3:3])[CH3:2]>[Ni]>[C:1]([CH:5]1[CH2:6][CH2:7][CH:8]([OH:11])[CH2:9][CH2:10]1)([CH3:4])([CH3:2])[CH3:3]\tUS20010000035A1\t0007\t2001\t\t',
'[Cl-].[Al+3].[Cl-].[Cl-].[Cl:5][CH2:6][CH2:7][CH2:8][C:9](Cl)=[O:10].[C:12]1([CH:18]([CH3:20])[CH3:19])[CH:17]=[CH:16][CH:15]=[CH:14][CH:13]=1>C(Cl)Cl>[Cl:5][CH2:6][CH2:7][CH2:8][C:9]([C:15]1[CH:16]=[CH:17][C:12]([CH:18]([CH3:20])[CH3:19])=[CH:13][CH:14]=1)=[O:10] |f:0.1.2.3|\tUS20010000038A1\t0256\t2001\t86%\t86.9%',
'[Al+3].[Cl-].[Cl-].[Cl-].[Cl:5][CH2:6][CH2:7][CH2:8][C:9](Cl)=[O:10].[C:12]1([CH3:18])[CH:17]=[CH:16][CH:15]=[CH:14][CH:13]=1>>[Cl:5][CH2:6][CH2:7][CH2:8][C:9]([C:15]1[CH:16]=[CH:17][C:12]([CH3:18])=[CH:13][CH:14]=1)=[O:10] |f:0.1.2.3|\tUS20010000038A1\t0259\t2001\t95%\t',
'[Cl:1][CH2:2][CH2:3][CH2:4][C:5]([C:7]1[CH:12]=[CH:11][C:10]([CH:13]([CH3:15])[CH3:14])=[CH:9][CH:8]=1)=[O:6].[Br:16]N1C(=O)CCC1=O.C(OOC(=O)C1C=CC=CC=1)(=O)C1C=CC=CC=1>C(Cl)(Cl)(Cl)Cl>[Br:16][C:13]([C:10]1[CH:9]=[CH:8][C:7]([C:5](=[O:6])[CH2:4][CH2:3][CH2:2][Cl:1])=[CH:12][CH:11]=1)([CH3:15])[CH3:14]\tUS20010000038A1\t0285\t2001\t\t']
ReactionSmiles, PatentNumber, ..., Yieldがタブで区切られています
ReactionSmilesは'原料と試薬>触媒・溶媒>生成物'の形で反応式が入っています。このデータセットでは、反応前後で対応する原子に番号が振られています(Atom Mapping)。原料や生成物に化合物が2つ以上存在する場合はピリオドで区切られています。
Atom MappingはChemAxon社が提供しているツールをフリーのアカデミックライセンスで使えるのでやってみてください。
1行目のデータの説明は飛ばして、上から10個見てみます。
ReactionSmiles以外はいらないので、str.find('\t')でタブの位置のindexを取得し、このindexより後ろの文字は捨てます。
from rdkit.Chem import rdChemReactions as Reactions
from rdkit.Chem import Draw
data = lines[1:11]
rxns = []
for rxn in data:
rxn = rxn[:rxn.find('\t')]
rxns.append(Reactions.ReactionFromSmarts(rxn, useSmiles=True))
Reactions.RectionFromSmartsの中に反応のstrを入れてやれば、反応のデータに変換してくれます。これでrxnsリストの中に10個の反応が入っていることになります。Drawで表示します。
Draw.ReactionToImage(rxns[0])
Niで芳香環が還元されています。Reaction SMILESでは水素を明示的に扱わないので、矢印の左側に3H2が隠れている感じですかね。。原子の番号は回転しちゃってますが、合っています。
indexをずらして見ていきます。
Draw.ReactionToImage(rxns[1])
表記がrdkitのキショスタイルですが我慢しましょう。
またindexをずらします。
Draw.ReactionToImage(rxns[2])
rxns[1]の基質違い、かつ溶媒のジクロロメタンが消えているだけです。こんな感じで反応を見ることができました。
反応を大量に見ていくと分かるのですが、1段階の反応が多いです。中にはワンポットでできそうな2段階くらいの反応が一つの矢印にまとまっているものもあります。テキストマイニングなのでその辺はご愛嬌です。ケモインフォの論文では、USPTOに入っているmultistep reactionsガーと書いている人がいますが、私が見ていった限りでは10段階の反応が一つの矢印にまとまっていたりするようなことは無いです。ただし重複した反応はたくさん含まれています。
USPTO_MIT
このDaniel Loweさんのデータセットは、1976年〜2016年のデータを合わせると180万反応ほどあります(今回ダウンロードしたのは2001年〜2016年のモノ)。180万反応もあるとかスゲ〜と思っちゃいますが、テキストマイニングなので間違ったデータが含まれていたり、重複したデータが多いというのは冒頭で書いた通りです。これをキレイにしてくれた人たちがいます。
GitHubはコチラ
このキレイにしてくれたデータセットは全部で48万反応くらいになっていて、大体みんなtrain 41万、valid 3万、test 4万にして使っているようです。他の論文でもUSPTO_MIT datasetとしてめちゃめちゃ使われていてめちゃめちゃ引用されています。
nips17-rexgen/USPTO/data.zip がデータセットなので、ダウンロードして見てみます。手順は同じです。
with open('./data/train.txt', 'r') as f:
lines = f.read().splitlines()
lines[:5]
['[CH2:15]([CH:16]([CH3:17])[CH3:18])[Mg+:19].[CH2:20]1[O:21][CH2:22][CH2:23][CH2:24]1.[Cl-:14].[OH:1][c:2]1[n:3][cH:4][c:5]([C:6](=[O:7])[N:8]([O:9][CH3:10])[CH3:11])[cH:12][cH:13]1>>[OH:1][c:2]1[n:3][cH:4][c:5]([C:6](=[O:7])[CH2:15][CH:16]([CH3:17])[CH3:18])[cH:12][cH:13]1 15-19;6-15;6-8',
'[CH3:14][NH2:15].[N+:1](=[O:2])([O-:3])[c:4]1[cH:5][c:6]([C:7](=[O:8])[OH:9])[cH:10][cH:11][c:12]1[Cl:13].[OH2:16]>>[N+:1](=[O:2])([O-:3])[c:4]1[cH:5][c:6]([C:7](=[O:8])[OH:9])[cH:10][cH:11][c:12]1[NH:15][CH3:14] 12-13;12-15',
'[CH2:1]([CH3:2])[n:3]1[cH:4][c:5]([C:22](=[O:23])[OH:24])[c:6](=[O:21])[c:7]2[cH:8][c:9]([F:20])[c:10](-[c:13]3[cH:14][cH:15][c:16]([NH2:19])[cH:17][cH:18]3)[cH:11][c:12]12.[CH:25](=[O:26])[OH:27]>>[CH2:1]([CH3:2])[n:3]1[cH:4][c:5]([C:22](=[O:23])[OH:24])[c:6](=[O:21])[c:7]2[cH:8][c:9]([F:20])[c:10](-[c:13]3[cH:14][cH:15][c:16]([NH:19][CH:25]=[O:26])[cH:17][cH:18]3)[cH:11][c:12]12 19-25;25-27',
'[Cl:1][C:2]([N:3]([CH3:4])[CH3:5])=[C:6]([CH3:7])[CH3:8].[Cl:51][CH2:52][Cl:53].[N:9]1([C:13](=[O:14])[c:15]2[n:16][cH:17][c:18]([O:21][c:22]3[cH:23][c:24]([C:25](=[O:26])[OH:27])[cH:28][c:29]([O:31][CH:32]([CH2:33][O:34][CH3:35])[CH3:36])[cH:30]3)[n:19][cH:20]2)[CH2:10][CH2:11][CH2:12]1.[NH2:37][c:38]1[n:39][cH:40][c:41]([CH3:44])[n:42][cH:43]1.[cH:45]1[cH:46][cH:47][n:48][cH:49][cH:50]1>>[N:9]1([C:13](=[O:14])[c:15]2[n:16][cH:17][c:18]([O:21][c:22]3[cH:23][c:24]([C:25](=[O:27])[NH:37][c:38]4[n:39][cH:40][c:41]([CH3:44])[n:42][cH:43]4)[cH:28][c:29]([O:31][CH:32]([CH2:33][O:34][CH3:35])[CH3:36])[cH:30]3)[n:19][cH:20]2)[CH2:10][CH2:11][CH2:12]1 25-26;25-37;25-27',
'[Cl:11][c:12]1[c:13]2[c:14]([n:15][c:16](-[c:18]3[cH:19][cH:20][n:21][cH:22][cH:23]3)[n:17]1)[s:24][c:25]([Cl:27])[cH:26]2.[Cl:1][c:2]1[cH:3][c:4]([CH2:5][NH2:6])[cH:7][cH:8][c:9]1[Cl:10]>>[Cl:1][c:2]1[cH:3][c:4]([CH2:5][NH:6][c:12]2[c:13]3[c:14]([n:15][c:16](-[c:18]4[cH:19][cH:20][n:21][cH:22][cH:23]4)[n:17]2)[s:24][c:25]([Cl:27])[cH:26]3)[cH:7][cH:8][c:9]1[Cl:10] 6-12;11-12']
この論文では、反応物において切断される結合と新しく接続される結合の情報を渡してモデルにreaction centerを学習させるので、結合の切断・接続位置がReaction SMILESの後ろに入っています。反応を表示するだけなら不要なので、' 'より後ろの文字を捨てて表示します。
data = lines[0:10]
rxns = []
for rxn in data:
rxn = rxn[:rxn.find(' ')]
rxns.append(Reactions.ReactionFromSmarts(rxn, useSmiles=True))
Draw.ReactionToImage(rxns[0])
生のテキストに書いてあった 15-19;6-15;6-8 という数字は、それぞれ切断されるグリニャーのC-Mg, 新しく結合ができるC-C, 窒素側が脱離して切断されるC-Nに対応していることが分かります。
反応を一気に表示
私の環境では以下のコードで複数の反応を表示できます。昔macbookでやった時にうまくいかなかったことがあるので動くかわかりませんがやってみてくだサイ
with open('./data/train.txt', 'r') as f:
rxns = f.read().splitlines()
f.close()
for i, rxn in enumerate(rxns):
rxn = Reactions.ReactionFromSmarts(rxn,useSmiles=True)
display(rxn)
これをipynbでやっちゃうと数万個の画像が出力されてカーネルが落ちてしまうので、
for i, rxn in enumerate(rxns):
rxn = Reactions.ReactionFromSmarts(rxn,useSmiles=True)
display(rxn)
if i == 50:
break
とかにしておくと良いと思います。以上