maoring blog

このブログはセマンティックウェブ関連の技術的なあれこれを綴ったブログです。

希少疾病用医薬品・希少疾病用医療機器のデータをRDF化しよう。その4

もとのデータをきれいにしよう。

さて,前回までの日記であらかた書くべきデータが揃いました。今回は実装編です。まず,手持ちのデータを綺麗にします。もともとはエクセルファイルのこのようなデータなのですが,ここから,まずは英語版だけピックアップして整理し,プログラムで利用しやすい形式にします。 この整理には,OpenRefine (Google Refine)を利用します。ダウンロードはこちらからどうぞ。Create Projectからファイルをアップロードします。そうすると,表形式にデータを表示してくれますので,Project nameをつけ,Project作成です。

f:id:maoring:20130828123920p:plain

もし,ここで汚いデータ等ありましたら,Open Refineの機能で,綺麗にしていくことも出来るので,OpenRefineのページの動画等を参照にして取り組んでみてください。また,このOpenRefineでは,拡張を行うとRDFの出力を行うことできます。OpenRefineでのRDFの拡張と簡単な実装方法については,こちらのブログ - 週末京都 Google RefineによるRDFデータへの変換 をご参照ください。もとのデータ数が多くなかったり,1つの欄の中での分割が必要でない場合にはこちらでも,十分に対応できます。特に,既に汎用されている語(Predicate 後ほど説明します)が多い場合には,(RDFの拡張をした後)RDF▼→ RDF Schema Alignment → RDF Skeltonで列ごとにprefix(後ほど説明します)を利用してpredicateを付けることが出来るので,便利です。

f:id:maoring:20130828124945p:plain

今回の場合,1つの欄の中での分割が必要だったり,オリジナルのpredicateを使いたかったので,OpenRefineでのRDF化は採用しないことにしました。

JSONからRDFを作ろう。

OpenRefineによるJSONの出力

当初はtxtファイルかcsvファイルに落としこんで,プログラムによる処理をしようと思っていたのですが,空欄と欄内の改行のせいで,なかなかうまくいかなかったので,今回はJSONを採用します。 先ほどのOpenRefineのExport▼→ Templating からJSON形式のデータをダウンロードすることができます。

f:id:maoring:20130828125354p:plain

Exportして名前(例:OOOO.json)をつけ,保存します。

まずはprefix!

RDFを記述するためのフォーマットは幾つかあるのですが,今回はttl(Turtle形式)で実装したいと思います。

Turtle の書き方

RDFは三組でグラフを書いていくものですが,幾つかの記述方式(RDF/XML,N-Triples等)があります。その中でも,簡潔な書き方で人にも読みやすい書き方として汎用されているのが,このTurtle形式です。 Wikipediaの例)を用いて,みていくことにしましょう。

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix ex: <http://example.org/stuff/1.0/> .

<http://www.w3.org/TR/rdf-syntax-grammar>
  dc:title "RDF/XML Syntax Specification (Revised)" ;
  ex:editor [
    ex:fullname "Dave Beckett";
    ex:homePage <http://purl.org/net/dajobe/>
  ] .

このように,最初にprefix,つまり接頭辞を書いて,これからrdfと書くのは, http://www.w3.org/1999/02/22-rdf-syntax-ns#のことですよ, dcと書くのは,http://purl.org/dc/elements/1.1/のことですよ…,という宣言をします。 実際に,それらのサイトに行くと,用語体系がダウンロード出来たり,用語体系の説明が書かれていたりします(無いことも結構あるけど,本来はあるとよいもの)。何故,こんなことをするのかということですが,出来るだけ,統一された用語体系で書かれていたほうが,後々データを繋げたり,同じ意味のデータを取り出すのに便利だからです。 直感的に理解するなら,辞書,と考えてもらえると良いかもしれません。日本語とフランス語と英語が混在しているページがあって,しかも,超専門的な分野のことが書かれていたならば,これから使う語の意味は,英語の糖鎖生物学の辞書に載っているものです。と書かれていたならば,その辞書を参照すれば,明確な意味が分かる,というようなイメージです。(厳密には,それらの用語同士の関係性が集合論的に書かれていることもあるので,その限りではありません(^_^;))

さて,中身も見ていきましょう。 <http://www.w3.org/TR/rdf-syntax-grammar>はSubject,つまり主語にあたります。 これから言うのは,<http://www.w3.org/TR/rdf-syntax-grammar>についてです,ということを示しています。 次に dc:titleというのは,dcという用語体系の中でtitleであるのは,というPredicate,すなわち述語にあたり,"RDF/XML Syntax Specification (Revised)"はObject,すなわち目的語にあたります。日本語にすると <http://www.w3.org/TR/rdf-syntax-grammar> のタイトルは "RDF/XML Syntax Specification (Revised)"
といった感じです。まだ途中なので,";"で続けて(主語は<http://www.w3.org/TR/rdf-syntax-grammar> のまま。次は, ex:editorでexの用語の中の編集者をこれから書きますよという意味です。[ ex:fullname "Dave Beckett"; ex:homePage <http://purl.org/net/dajobe/> ] . []を使用することでまとめて記述していますが,編集者について,さらに説明していて ex:fullnamefullnameは"Dave Backett"で,homePageは”http://purl.org/net/dajobe/”であるということを示しています。以上をグラフにするとこのようになります。RDFグラフの視覚化 Turtle, Microdata, JSON-LDからグラフを書きました。

f:id:maoring:20130828162320p:plain

主語が<http://www.w3.org/TR/rdf-syntax-grammar>であり,そのタイトルと,編集者について書かれていることが,グラフによって示されていることがお分かりになるでしょうか。なお,薄青色のノード(楕円)は空白ノードといって,そこのノード自体には,意味は無いのですが,分岐がさらに続いたり,毎回predicateを書くことを省略したり,複雑なグラフを書く時に便利なので,よく用いられるものです。

手持ちのデータにもprefixをつけよう。

基本的には,使う用語のprefixだけで大丈夫です。そして,今回オレオレ(独自に)定義した語彙についてもprefixをつけました。こんな感じで最初に宣言をしていきます。

@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix eob: <http://pashworth.org/orangebook#> .
@prefix drgb: <http://bio2rdf.org/drugbank_vocabulary> .
@prefix drgn: <http://www.nibio.go.jp/drugVocabulary#> .
@prefix odrgn: <http://www.nibio.go.jp/orphanDrugVocabulary#> .

前々回探しだした語彙についても,@prefix eob: http://pashworth.org/orangebook# . @prefix drgb: http://bio2rdf.org/drugbank_vocabulary . として記述しています。本当は汎用的なprefix名があるはずなのですが,(その上の dc , rdfsなどと同様に)見つからなかったので,このような記述にしています。

また,ここで独自に定義する語彙についてですが,URIの設計上の注意があり,基本的には303リダイレクトを使う方法とハッシュURIを使う方法があるようなのですが(参考:Linked Data: Webをグローバルなデータ空間にする仕組み)ここでは,ハッシュ”#"を使い,http://www.nibio.go.jp/drugVocabulary#としています。また,predicateの記述の方法も幾つかあるのですが,ここでは,ローワーキャメルケース(複合語の先頭を小文字で書き始め,2個目以降の単語の先頭を大文字で書く)方法を採用しています。

RubyによるJSONの処理

今回は,OpenRefineでJSONで出力したので,JSONから処理していきます。今回はrubyを使って,JSONのパースを行っていきます。もとのJSONのデータはこんな感じです。

{
  "rows" : [
    {    
      "Column 1" : 1993,
      "Column 2" : "1993/11/15",
      "Column 3" : "1993/11/15",
      "Column 4" : "(5yaku A) No. 1",
      "Column 5" : 2, 
      "Column 6" : "Mixture of L-arginine and L-arginine hydrochloride granules; L-arginine hydrochloride injectable",
      "Column 7" : "The granule form improves the neurological symptoms due to hyperammonaemia, of vomiting, lethargy and abnormal electroencephalogram, and the other symp
      "Column 8" : "Roussel Morishita Company, Limited",
      "Column 9" : "<Granule>\nInhibition of rising blood level of ammonia in the following diseases: congenital urea cycle enzyme abnormalities - carbamyl phosphate synth
      "Column 10" : "Ajinomoto Co. Inc.",
      "Column 11" : "1999/9/22",
      "Column 12" : "1999/9/22",
      "Column 13" : "Argi-U Granule\nArgi-U Injection 20g",
      "Column 14" : "Argi-U_ Granule\nArgi-U_ Injection",
      "Column 15" : "L-Arginine Hydrochloride, L-Arginine\nL-Arginine Hydrochloride",
      "Column 16" : null,
      "Column 17" : null,
      "Column 18" : "Approved"
    },   
    {    
      "Column 1" : 1993,
      "Column 2" : "1993/11/15",
      "Column 3" : "1993/11/15",
      "Column 4" : "(5yaku B) No. 2",
      "Column 5" : null,
      "Column 6" : "Alglucerase",
      "Column 7" : "Improvement of the following symptoms in patients with Gaucher's disease type I: anaemia, thrombocytopenia, and hepatosplenomegaly.",
      "Column 8" : "Genzyme Japan K.K.",
      "Column 9" : "Improvement of the following symptoms in patients with Gaucher's disease type I: anaemia, thrombocytopenia, hepatosplenomegaly and other symptoms in bo
      "Column 10" : "Genzyme Japan K.K."
…
}
]
}

rubyの1.9以降には標準ライブラリにJSONのライブラリが入っているため,簡単にパースをしていくことができます。 例

require "json"
fp_json = []
open("originalOrphane.json",'r'){|fp|
 fp_json = JSON.parse(fp.read)
}
fp_json.each do |key,val|
    val.each_with_index do |column,i|
    puts column["Column 1"]
end
end

これだけで,先ほどのJSON形式のファイルにおけるColumn 1の年号がずらずらと出てきてくれます。

RDFを作っちゃうぞ。

ここまで出来てしまうと後は実は簡単です。prefixさんを上の方で宣言して,既に使用することを決めたpredicateさん達(前に書いた記事 や,こちらのGoogle Document をご参照ください)を当てはめて,書いていきます。そう,こんな感じに。

require "json"
fp_json = []
open("originalOrphane.json",'r'){|fp|
 fp_json = JSON.parse(fp.read)
}
puts "@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix eob: <http://pashworth.org/orangebook#> .
@prefix drgb: <http://bio2rdf.org/drugbank_vocabulary> .
@prefix drgn: <http://www.nibio.go.jp/drugVocabulary#> .
@prefix odrgn: <http://www.nibio.go.jp/orphanDrugVocabulary#> .
"
puts

fp_json.each do |key,val|
    val.each_with_index do |column,i|
        print "<http://www.nibio.go.jp/orphandrugTarget#"+ i.to_s + "> drgn:designationFiscalYear \""+ column["Column 1"].to_s + "\";\n"
        print " drgn:designationDateJapaneseEra \"" + column["Column 2"].to_s + "\";\n";
        print " drgn:designationDate \"" + column["Column 3"].to_s + "\";\n";
        print " drgn:number \"" + column["Column 4"] + "\";\n";
        print " drgn:grantPeriod \"" + column["Column 5"].to_s + "\";\n";
        print " drgb:name \"" + column["Column 6"] + "\";\n";
        print " dc:description \"" + column["Column 7"] + "\";\n";
        print " drgn:designationApplicant \"" + column["Column 8"] + "\";\n";
        print " drgb:pharmacology \"" + column["Column 9"] + "\";\n";
        print " drgb:manufacturer \"" + column["Column 10"].to_s + "\";\n";
        print " eob:approvalDateJ \"" + column["Column 11"].to_s + "\";\n";
        print " eob:approvalDate \"" + column["Column 12"].to_s + "\";\n";
        print " drgb:product \"" + column["Column 13"].to_s + "\";\n";
        print " drgb:brand \"" + column["Column 14"].to_s + "\";\n";
        print " drgn:approvedName \"" + column["Column 15"].to_s + "\";\n";
        print " rdfs:comment \"" + column["Column 16"].to_s + "\";\n";
        print " drgn:revocationDate \"" + column["Column 17"].to_s + "\";\n";
        print " drgn:status \"" + column["Column 18"].to_s + "\".\n";
#最後は” ; ”ではなく,” . ” で主語に区切りをつける。
        puts
     end 
end
出力結果

出力すると,こんな感じになります。

@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix eob: <http://pashworth.org/orangebook#> .
@prefix drgb: <http://bio2rdf.org/drugbank_vocabulary> .
@prefix drgn: <http://www.nibio.go.jp/drugVocabulary#> .
@prefix odrgn: <http://www.nibio.go.jp/orphanDrugVocabulary#> .

<http://www.nibio.go.jp/orphandrugTarget#1> drgn:designationFiscalYear "1993";
 drgn:designationDateJapaneseEra "1993/11/15";
 drgn:designationDate "1993/11/15";
 drgn:number "(5yaku B) No. 2";
 drgn:grantPeriod "";
 drgb:name "Alglucerase";
 dc:description "Improvement of the following symptoms in patients with Gaucher's disease type I: anaemia, thrombocytopenia, and hepatosplenomegaly.";
 drgn:designationApplicant "Genzyme Japan K.K.";
 drgb:pharmacology "Improvement of the following symptoms in patients with Gaucher's disease type I: anaemia, thrombocytopenia, hepatosplenomegaly and other symptoms in bo
 drgb:manufacturer "Genzyme Japan K.K.";
 eob:approvalDateJ "1996/7/10";
 eob:approvalDate "1996/7/10";
 drgb:product "Ceredase injection 50U
Ceredase injection 400U";
 drgb:brand "−"; 
 drgn:approvedName "−"; 
 rdfs:revocationDate "";
 drgn:comment "These two formulations are currently being supplied. Designation number “Drug 8 No. 81” is being supplied instead. ";
 drgn:status "Approved".

大分,いい感じになってきました。 これで,完成!と言いたいところですが,ちょっと手直しをしていきます。

分岐するデータを記述する。

ここで,RDF化しているデータは,もとはエクセル形式のデータのです。ただ,同じ希少疾病用医薬品であっても,商品化されているものは,2つあったり,ということがありえます。そんな時に,私の手持ちのデータでは,

Approved product name for manufacture and sale
Argi-U Granule¥n Argi-U Injection 20g

のように,改行があるデータがありました。こういうものがあるときは,グラフ化したデータの方が扱いやすくなるわけですが,プログラムで処理をしていきます。なんてもったいぶって書きましたが,実にシンプルです。

#一部を抜粋しています。
        if  column["Column 13"].nil? #nilだったら
            print " drgb:product \" \";\n" #データが無いことを示す。
        elsif 
            column["Column 13"].include?("\n") #改行があったら
            column13 = column["Column 13"].split("\n") #改行ごとに分割
            column13.each do |value| #1つずつ出力。
            print " drgb:product \"" + value + "\";\n";
            end 
        else
            print " drgb:product \"" + column["Column 13"].to_s + "\";\n";
        end 

出力結果(抜粋)

@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix eob: <http://pashworth.org/orangebook#> .
@prefix drgb: <http://bio2rdf.org/drugbank_vocabulary> .
@prefix drgn: <http://www.nibio.go.jp/drugVocabulary#> .
@prefix odrgn: <http://www.nibio.go.jp/orphanDrugVocabulary#> .

<http://www.nibio.go.jp/orphandrugTarget#1> drgn:designationFiscalYear "1993";
 drgn:designationDateJapaneseEra "1993/11/15";
 drgn:designationDate "1993/11/15";
 drgn:number "(5yaku B) No. 2";
 drgn:grantPeriod "";
 drgb:name "Alglucerase";
 dc:description "Improvement of the following symptoms in patients with Gaucher's disease type I: anaemia, thrombocytopenia, and hepatosplenomegaly.";
 drgn:designationApplicant "Genzyme Japan K.K.";
 drgb:pharmacology "Improvement of the following symptoms in patients with Gaucher's disease type I: anaemia, thrombocytopenia, hepatosplenomegaly and other symptoms in bones";
 drgb:manufacturer "Genzyme Japan K.K.";
 eob:approvalDateJ "1996/7/10";
 eob:approvalDate "1996/7/10";
 drgb:product "Ceredase injection 50U";
 drgb:product "Ceredase injection 400U";
 drgb:brand "−"; 
 drgn:approvedName "−"; 
 drgn:revocationDate "These two formulations are currently being supplied. Designation number “Drug 8 No. 81” is being supplied instead. ";
 rdfs:comment "";
 drgn:status "Approved".
正しいデータか確かめよう。

無事にデータが出来てきたところで,ちゃんと書けているかどうか,さっと確認します。 先ほどの神崎さんのツール(RDFグラフの視覚化 Turtle, Microdata, JSON-LD) を使い,出力データの一部をコピペして,グラフ化出来るか確認してみます。

f:id:maoring:20130829171855p:plain

うむ,(もう少しグラフであることを意識した記述のほうが良いかもしれないけれど)大丈夫そうです。先ほどのArgi-U Granule¥n Argi-U Injection 20gのようなデータもちゃんと別のObjectとして扱ってくれています。

もう一歩

ここから先は努力事項ですが,ライセンス事項についても書くと,後々のためになります。誰がそのデータを書いてそのライセンスがどうなのか,そのファイル自体に書かれていたら便利でしょ?長くなってしまったので,詳しくは後ほど。次回は,日本語のデータのRDF化についてのお話もしていきたいと思います。 ではでは,また,お会いしましょうっ☆(記事を書く日によってテンションが変わってしまうのを何とかしたい,maoringoでしたっ。)