(同じ病気なのに、みんなバラバラな用語を使うと情報が共有できないよ。標準名を作るからこれを使ってね。)
最新版はICD10(2014年版)。どうやらアメリカでは未だICD9が一般的に普及されており、2014年10月1日から全国的にICD9を廃止し、ICD10に切り替えるそうだ。
ちなみに日本では厚生労働省の指示のもとICD10(2003年版)が利用されている。
オンラインでICD10を検索できるのは以下のサイト。
実際検索してみると、同意義語の検索が弱い。イライラするくらいヒットしない。
マニュアルでやる労力を惜しむため、WHOからデータを取得し、自前のデータベースを作ることにした。
1. Get ICD10 (2010) From WHO
ページ中ほどにある「Classification Download Area」をクリックし、アカウントを作成する。
アカウント登録では、データの使い道や目的を英語で記入する。(一行ぐらいで問題なし)
使用言語を英語に設定してダウンロード。
icd.102010.xmlの形式はこんな感じ。
赤字がタグ(tag)、青字が属性名(Attribute name)、緑字が属性値(Attribute value)。
要素(Element)は開始タグ、テキスト、終了タグの全てを指す。
まずはパッケージとXMLデータのインポート。
Classタグの属性を取得。
Class要素下のLabel要素に囲まれたテキストを取得。
Rubric要素下にFragment要素が存在しない場合は、Label要素のテキストを取得し、Fragment要素が存在する場合はFragment要素のテキストを取得するよう条件分岐した。
Class codeが"F90.0"であるClass要素の属性、Rubric要素の属性、LabelあるいはFragmentのテキストを取得。
辞書形式のリストにするとこんな感じ。
辞書のリストをcsv形式に書き出してみたところ、文字コードエラーが発生。
参考:How do I convert this list of dictionaries to a csv file? [Python]
もしテキストがunicodeだったらutf-8に変換することにした。
参考:PythonのUnicodeEncodeErrorを知る
Label要素下にPara要素が含まれるケースがあるため、条件分岐を3つに変更。
csv形式で問題なく書き出せた。
データベースにするとこんな感じ。
使用言語を英語に設定してダウンロード。
取得できるファイルは5つ。
- icd102010enMeta.zip
- blocks.txt
- chapters.txt
- codes.txt
- readme.txt
- icdClaML2010ens.zip
- icd102010en.xml
icd.102010.xmlの形式はこんな感じ。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ClaML SYSTEM "ClaML.dtd">
<ClaML version="2.0.0">
....
<Class code="U89.9" kind="category">
<Meta name="MortL4Code" value="UNDEF"/>
....
<Rubric id="D0020989" kind="preferred">
<Label xml:lang="en" xml:space="default">
Agent resistant to unspecified antibiotic
</Label>
</Rubric>
</Class>
</ClaML>
赤字がタグ(tag)、青字が属性名(Attribute name)、緑字が属性値(Attribute value)。
要素(Element)は開始タグ、テキスト、終了タグの全てを指す。
2. Pythonのxml.etree.ElementTreeを用いてテキストマイニング
参考- 19.7. xml.etree.ElementTree — The ElementTree XML API — Python v2.7.6 documentation
- 19.13. xml.etree.ElementTree - Python 2.7ja1 documentation
まずはパッケージとXMLデータのインポート。
from xml.etree import ElementTree
XMLFILE = "icd102010en.xml"
tree = ElementTree.parse(XMLFILE)
root = tree.getroot()
Classタグの属性を取得。
for e in root.findall('.//Class'):Classタグの属性名kindがcategoryの場合の属性を取得。
print e.attrib
# {'kind': 'category', 'code': 'U89.9'}
for e in root.findall(".//Class[@kind='category']"):Classタグの属性名codeの属性値を取得。
print e.attrib
# {'kind': 'category', 'code': 'U89.9'}
for e in root.findall('.//Class'):Class要素下のRubricタグの属性を取得。
print e.get('code')
# U89.9
for e in root.findall('.//Class'):
print e.findall('.//Rubric').attrib
# {'kind': 'preferred', 'id': 'D0020989'}
Class要素下のLabel要素に囲まれたテキストを取得。
for e in root.findall('.//Class'):
print e.findtext('.//Label')
# Agent resistant to unspecified antibiotic
for e in root.findall('.//Class'):
print e.findall('.//Label').text
# Agent resistant to unspecified antibiotic
3. 例外の確認
Class下に複数のRubricが存在し、RubricのLabel下にFragment要素が複数存在する場合。<Class code="F90.0" kind="category">
<Meta name="MortBCode" value="119"/>
...
<Rubric id="D0004728" kind="preferred">
<Label xml:lang="en" xml:space="default">Disturbance of activity and attention</Label>
</Rubric>
<Rubric id="D0005181" kind="inclusion">
<Label xml:lang="en" xml:space="default">
<Fragment type="list">Attention deficit:</Fragment>
<Fragment type="list">disorder with hyperactivity</Fragment>
</Label>
</Rubric>
<Rubric id="D0005182" kind="inclusion">
<Label xml:lang="en" xml:space="default">
<Fragment type="list">Attention deficit:</Fragment>
<Fragment type="list">hyperactivity disorder</Fragment>
</Label>
</Rubric>
<Rubric id="D0005183" kind="inclusion">
<Label xml:lang="en" xml:space="default">
<Fragment type="list">Attention deficit:</Fragment>
<Fragment type="list">syndrome with hyperactivity</Fragment>
</Label>
</Rubric>
<Rubric id="id-to-be-added-later-1210506823253-1946" kind="exclusion">
<Label xml:lang="en" xml:space="default">hyperkinetic disorder associated with conduct disorder<Reference class="in brackets">F90.1</Reference></Label>
</Rubric>
</Class>
Rubric要素下にFragment要素が存在しない場合は、Label要素のテキストを取得し、Fragment要素が存在する場合はFragment要素のテキストを取得するよう条件分岐した。
Class codeが"F90.0"であるClass要素の属性、Rubric要素の属性、LabelあるいはFragmentのテキストを取得。
for c in root.findall(".//Class[@code='F90.0']"):
code = c.get('code')
kind = c.get('kind')
for r in c.iter('Rubric'):
id = r.get('id')
rkind = r.get('kind')
fex = r.find('.//Fragment')
if fex is None:
for l in r.iter('Label'):
text = l.text
else:
text = ""
for f in r.iter('Fragment'):
text = text + ' ' + f.text
print code, kind, id, rkind, text
# F90.0 category D0004728 preferred Disturbance of activity and attention
# F90.0 category D0005181 inclusion Attention deficit: disorder with hyperactivity
# F90.0 category D0005182 inclusion Attention deficit: hyperactivity disorder
# F90.0 category D0005183 inclusion Attention deficit: syndrome with hyperactivity
# F90.0 category id-to-be-added-later-1210506823253-1946 exclusion hyperkinetic disorder associated with conduct disorder
辞書形式のリストにするとこんな感じ。
out = []
for c in root.findall(".//Class[@code='F90.0']"):
code = c.get('code')
kind = c.get('kind')
for r in c.iter('Rubric'):
id = r.get('id')
rkind = r.get('kind')
fex = r.find('.//Fragment')
if fex is None:
for l in r.iter('Label'):
text = l.text
else:
text = ""
for f in r.iter('Fragment'):
text = text + ' ' + f.text
out.append({
"ClassCode": code,
"ClassKind": kind,
"RubricID": id,
"RubricKind": rkind,
"Text": text
})
# out[1]
# {'Text': 'Disturbance of activity and attention', 'RubricKind': 'preferred', 'RubricID': 'D0004728', 'ClassCode': 'F90.0', 'ClassKind': 'category'}
辞書のリストをcsv形式に書き出してみたところ、文字コードエラーが発生。
参考:How do I convert this list of dictionaries to a csv file? [Python]
import csv
keys = ['ClassCode', 'ClassKind', 'RubricID', 'RubricKind', 'Text']
f = open('output.csv', 'wb')
dict_writer = csv.DictWriter(f, keys)
dict_writer.writer.writerow(keys)
dict_writer.writerows(out)
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# File "/usr/local/lib/python2.7/csv.py", line 154, in writerows
# return self.writer.writerows(rows)
# UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc' in position 15: ordinal not in range(128)
もしテキストがunicodeだったらutf-8に変換することにした。
参考:PythonのUnicodeEncodeErrorを知る
out = []
for c in root.findall(".//Class[@kind='category']"):
code = c.get('code')
kind = c.get('kind')
for r in c.iter('Rubric'):
id = r.get('id')
rkind = r.get('kind')
fex = r.find('.//Fragment')
if fex is None:
for l in r.iter('Label'):
if isinstance(l.text, unicode):
term = l.text.encode('utf-8')
else:
term = l.text
else:
term = ""
for f in r.iter('Fragment'):
if isinstance(f.text, unicode):
term = term + ' ' + f.text.encode('utf-8')
else:
term = term + ' ' + f.text
out.append({
"ClassCode": code,
"ClassKind": kind,
"RubricID": id,
"RubricKind": rkind,
"Text": term
})
Label要素下にPara要素が含まれるケースがあるため、条件分岐を3つに変更。
out = []
for c in root.findall(".//Class[@kind='category']"):
code = c.get('code')
kind = c.get('kind')
for r in c.iter('Rubric'):
id = r.get('id')
rkind = r.get('kind')
fex = r.find('.//Fragment')
pex = r.find('.//Para')
if fex is not None:
term = ""
for f in r.iter('Fragment'):
if isinstance(f.text, unicode):
term = term + ' ' + f.text.encode('utf-8')
else:
term = term + ' ' + f.text
elif pex is not None:
for p in r.iter('Para'):
if isinstance(p.text, unicode):
term = p.text.encode('utf-8')
else:
term = p.text
else:
for l in r.iter('Label'):
if isinstance(l.text, unicode):
term = l.text.encode('utf-8')
else:
term = l.text
out.append({
"ClassCode": code,
"ClassKind": kind,
"RubricID": id,
"RubricKind": rkind,
"Text": term
})
csv形式で問題なく書き出せた。
import csv
keys = ['ClassCode', 'ClassKind', 'RubricID', 'RubricKind', 'Text']
f = open('output.csv', 'wb')
dict_writer = csv.DictWriter(f, keys)
dict_writer.writer.writerow(keys)
dict_writer.writerows(out)
# cat output.csv | head -5
# ClassCode,ClassKind,RubricID,RubricKind,Text
# A00,category,D0000003,preferred,Cholera
# A00.0,category,D0000004,preferred,"Cholera due to Vibrio cholerae 01, biovar cholerae"
# A00.0,category,D0000934,inclusion,Classical cholera
# A00.1,category,D0000005,preferred,"Cholera due to Vibrio cholerae 01, biovar eltor"
データベースにするとこんな感じ。
ClassCode | ClassKind | RubricID | RubricKind | Text |
A00 | category | D0000003 | preferred | Cholera |
A00.0 | category | D0000004 | preferred | Cholera due to Vibrio cholerae 01, biovar cholerae |
A00.0 | category | D0000934 | inclusion | Classical cholera |
A00.1 | category | D0000005 | preferred | Cholera due to Vibrio cholerae 01, biovar eltor |
0 コメント:
コメントを投稿