LoginSignup
4
4

More than 3 years have passed since last update.

ChemDataExtractor:シンプルテキストから固有表現抽出(Named Entity Recognition; NER)を行ってみる

Last updated at Posted at 2020-08-19

概要

論文や特許文献から材料名,化合物名,そしてそれに紐づく物性値を自動的に取得したり抽出したりしてマイニングしたい.そのようなときに使われるのが,近年ではpythonライブラリのChemDataExtractorに勢いがあります.あまり日本語の解説サイトがないので,メモとして書き残しておきます.

テキスト

今回のテキスト解析はオープンジャーナルのNanomaterialsから,以下の有機ELの青色発光のTADF論文から例文を使います.

Nanomaterials 2019, 9(12), 1735; https://doi.org/10.3390/nano9121735
A Novel Design Strategy for Suppressing Efficiency Roll-Off of Blue Thermally Activated Delayed Fluorescence Molecules through Donor–Acceptor Interlocking by C–C Bonds
by Tae Hui Kwon 1,Soon Ok Jeon 2,Masaki Numata 3,Hasup Lee 2,Yeon Sook Chung 2,Jong Soo Kim 2,Soo-Ghang Ihn 2,Myungsun Sim 2,Sunghan Kim 2 and Byeong Moon Kim 1

この中からScheme1にある以下のテキストを取り上げることにします.

scheme1
Synthetic routes of BMK-T138 and BMK-T139: (a) iodobenzene, K3PO4, CuI, N,N’-diacetylcyclohexane-1,2-diamine, dioxane, 80 °C; 86%; (b) triisopropyl borate, lithium 2,2,6,6-tetramethylpiperidide, tetrahydrofuran (THF), −60 °C, then 1 N HCl, r.t.; (c) Pd(OAc)2, tri-o-tolyphosphine, H2O, THF, 80 °C, 36% yield from 2 steps; (d) Carbazole, tBuOK, N,N-dimethylformamide (DMF), 160 °C, 49%; (e) Carbazole, tBuOK, DMF, 160 °C, 85%.

Documentオブジェクト

まずはDocumentモジュールをimportします.

Documentは目的とするテキストや文章をインスタンス化し,そこから固有表現抽出(Named Entity Recognition; NER)ができるようになります.上記のscheme1の文章から文章に含まれる化学物質名を得る化学物質記述(chemical entity mention; CEM)の操作は次のようにします.

from chemdataextractor import Document

text = 'Scheme 1. Synthetic routes of BMK-T138 and BMK-T139: (a) iodobenzene, K3PO4, CuI, N,N’-diacetylcyclohexane-1,2-diamine, dioxane, 80 °C; 86%; (b) triisopropyl borate, lithium 2,2,6,6-tetramethylpiperidide, tetrahydrofuran (THF), −60 °C, then 1 N HCl, r.t.; (c) Pd(OAc)2, tri-o-tolyphosphine, H2O, THF, 80 °C, 36% yield from 2 steps; (d) Carbazole, tBuOK, N,N-dimethylformamide (DMF), 160 °C, 49%; (e) Carbazole, tBuOK, DMF, 160 °C, 85%.'
doc = Document(text)
doc.cems

すると,以下のような出力が得られます.

出力
[Span('DMF', 377, 380),
 Span('THF', 296, 299),
 Span('CuI', 77, 80),
 Span('Pd(OAc)2', 260, 268),
 Span('tri-o-tolyphosphine', 270, 289),
 Span('DMF', 418, 421),
 Span('K3PO4', 70, 75),
 Span('iodobenzene', 57, 68),
 Span('Carbazole', 336, 345),
 Span('Carbazole', 400, 409),
 Span('H2O', 291, 294),
 Span('lithium 2,2,6,6-tetramethylpiperidide', 166, 203),
 Span('THF', 222, 225),
 Span('N HCl', 243, 248),
 Span('dioxane', 120, 127),
 Span('triisopropyl borate', 145, 164),
 Span('N,N’-diacetylcyclohexane-1,2-diamine', 82, 118),
 Span('tetrahydrofuran', 205, 220),
 Span('tBuOK', 347, 352),
 Span('tBuOK', 411, 416),
 Span('N,N-dimethylformamide', 354, 375)]

上記の出力のうち「N HCl」がおかしいですね.scheme1の本文をみると,「1 N HCl」(1規定の塩酸)を誤って認識してしまっていることがわかりますが,それ以外は概ね正確に抜き出しています.このように認識率は100%ではありませんが,低分子化合物であれば高い認識率で化学物質記述を得ることができそうです.

またTHFやDMFの略称はabbreviation_definitionsから得ることができます.

doc.abbreviation_definitions
出力
[(['THF'], ['tetrahydrofuran'], 'CM'),
 (['DMF'], ['N,N-dimethylformamide'], 'CM')]

重複表示をなくし,化合物の固有情報(化合物名や略称)を一つにまとめるには,以下のrecordsから得ることができます.

doc.records.serialize()
出力
[{'names': ['iodobenzene']},
 {'names': ['K3PO4']},
 {'names': ['CuI']},
 {'names': ['N,N’-diacetylcyclohexane-1,2-diamine']},
 {'names': ['dioxane']},
 {'names': ['triisopropyl borate']},
 {'names': ['lithium 2,2,6,6-tetramethylpiperidide']},
 {'names': ['N HCl']},
 {'names': ['Pd(OAc)2']},
 {'names': ['tri-o-tolyphosphine']},
 {'names': ['H2O']},
 {'names': ['Carbazole']},
 {'names': ['tBuOK']},
 {'names': ['tetrahydrofuran', 'THF']},
 {'names': ['N,N-dimethylformamide', 'DMF']}]

namesという属性で化合物名がまとめられていることがわかりますね.THFやDMFは略称と化合物名がnamesで一緒に表記されていることがわかります.

そのほかには,どのような属性があるのでしょうか.key-valueの関係から見てみると,

doc.records[0].keys()
出力
['names',
 'labels',
 'roles',
 'nmr_spectra',
 'ir_spectra',
 'uvvis_spectra',
 'melting_points',
 'glass_transitions',
 'quantum_yields',
 'fluorescence_lifetimes',
 'electrochemical_potentials']

このように属性にはnamesのほかにもNMRやIRなどのスペクトル値や融点,ガラス転移点といった基本特性が含みうるようになっていることがわかります.keys()に対応するvalues()をみると,names以外は空欄ですが属性がネスト構造で格納できるようになっていることがわかりますね.

doc.records[0].values()
出力
[['iodobenzene'], [], [], [], [], [], [], [], [], [], []]

では,実際にそれらの属性に値が格納されるのかを別のテキストで見てみることにしましょう.
Supplementary informationのpdfにある2-(4,6-Diphenyl-1,3,5-triazin-2-yl)-9-phenyl-9H-3,9'-bicarbazole (BMK-T138) の合成手順とNMRによる同定が述べられているMethodをtext2へ入力し,そのNERをみてみることにします.

text2 = "2-(4,6-Diphenyl-1,3,5-triazin-2-yl)-9-phenyl-9H-3,9'-bicarbazole (BMK-T138) : To a solution of carbazole 5a (2.98 g, 6.05 mmol) in DMF (18 mL) was added carbazole (6.07 g, 36.3 mmol) and tertBuOK (3.4 g, 30.3 mmol) at r.t.. The reaction mixture was stirred at 170 oC for 18 hours. The resulting mixture was cooled and filtered using MeOH. The filter cake was dried in reduced pressure at 60 oC for 4 hours. The resulting residue was purified by using flash column chromatography on silica-gel (Hex:CH2Cl2=1:1) to afford BMK-T138 (13.65 g, 49%). 1H-NMR (400 MHz, CDCl3, ppm) δ 8.06 (d, J = 7.6 Hz, 1H), 8.05 (d, J = 8.0 Hz, 2H), 7.94 (d, J = 7.2 Hz, 4H), 7.68-7.76 (m, 4H), 7.52-7.57 (m, 4H), 7.42 (t, J = 7.2 Hz, 2H), 7.28-7.38 (m, 6H), 7.19-7.26 (m, 5H). 13C-NMR (100 MHz, CDCl3, ppm) δ 172.7, 171.1, 142.6, 142.5, 140.3, 137.2, 135.6, 133.8, 132.1, 130.1, 128.8, 128.7, 128.2, 128.1, 127.6, 127.2, 126.3, 125.8, 123.2, 122.6, 122.5, 121.2, 120.8, 120.2, 119.2, 113.9, 110.4, 109.7. MALDI-MS Calcd: 639.24, Found: 639.26"
doc2 = Document(text2)
doc2.records.serialize()
出力
[{'names': ["2-(4,6-Diphenyl-1,3,5-triazin-2-yl)-9-phenyl-9H-3,9'-bicarbazole"]},
 {'names': ['carbazole']},
 {'names': ['DMF']},
 {'names': ['MeOH']},
 {'names': ['silica']},
 {'names': ['Hex']},
 {'names': ['CH2Cl2']},
 {'names': ['1H']},
 {'names': ['2H']},
 {'nmr_spectra': [{'frequency': '400',
    'frequency_units': 'MHz',
    'nucleus': '1H',
    'peaks': [{'coupling': '7.6',
      'coupling_units': 'Hz',
      'multiplicity': 'd',
      'number': '1H',
      'shift': '8.06'},
     {'coupling': '8.0',
      'coupling_units': 'Hz',
      'multiplicity': 'd',
      'number': '2H',
      'shift': '8.05'},
     {'coupling': '7.2',
      'coupling_units': 'Hz',
      'multiplicity': 'd',
      'number': '4H',
      'shift': '7.94'},
     {'multiplicity': 'm', 'number': '4H', 'shift': '7.68-7.76'},
     {'multiplicity': 'm', 'number': '4H', 'shift': '7.52-7.57'},
     {'coupling': '7.2',
      'coupling_units': 'Hz',
      'multiplicity': 't',
      'number': '2H',
      'shift': '7.42'},
     {'multiplicity': 'm', 'number': '6H', 'shift': '7.28-7.38'},
     {'multiplicity': 'm', 'number': '5H', 'shift': '7.19-7.26'}],
    'solvent': 'CDCl3'}]},
 {'names': ['13C']},
 {'nmr_spectra': [{'frequency': '100',
    'frequency_units': 'MHz',
    'nucleus': '13C',
    'peaks': [{'shift': '172.7'},
     {'shift': '171.1'},
     {'shift': '142.6'},
     {'shift': '142.5'},
     {'shift': '140.3'},
     {'shift': '137.2'},
     {'shift': '135.6'},
     {'shift': '133.8'},
     {'shift': '132.1'},
     {'shift': '130.1'},
     {'shift': '128.8'},
     {'shift': '128.7'},
     {'shift': '128.2'},
     {'shift': '128.1'},
     {'shift': '127.6'},
     {'shift': '127.2'},
     {'shift': '126.3'},
     {'shift': '125.8'},
     {'shift': '123.2'},
     {'shift': '122.6'},
     {'shift': '122.5'},
     {'shift': '121.2'},
     {'shift': '120.8'},
     {'shift': '120.2'},
     {'shift': '119.2'},
     {'shift': '113.9'},
     {'shift': '110.4'},
     {'shift': '109.7'}],
    'solvent': 'CDCl3'}]},
 {'names': ['CDCl3']}]

NMRについてはケミカルシフトが1Hおよび13Cともキレイに格納されていますね.

参考までに,1H-NMRはrecords[9]に格納されており,さらにネスト構造でfrequency,frequency_units,nucleus,peaksの属性が階層になっています.最も低磁場側のケミカルシフトを得るには,peaks[0]のリストから以下のように取り出すことができます.

doc2.records[9].nmr_spectra[0].peaks[0].values()
出力
['8.06', None, 'd', '7.6', 'Hz', '1H', None]

合成結果のデータベースも,これらの情報から組み上げることができそうな予感がしますね.

以上,シンプルテキストによる固有表現抽出でした.

参照

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4