BH11.11/山本作業記録

提供:TogoWiki

移動: 案内, 検索

BH11.11/ヒト・環境メタゲノムメタデータのオントロジー整備とRDF化」関連の作業記録

目次

文字列マッチ

今回の処理対象データの特徴として、数値が意味をなさない場合が多く、アルファベット部分の類似度に重きを置くことが有効であった。 そこで、Apache Commonsライブラリに含まれているDoubleMetaphoneアルゴリズムを利用している。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.regex.Pattern;

import org.apache.commons.codec.language.DoubleMetaphone;

public class getDoubleMetaphone {

     public static void main(String[] args) {
             DoubleMetaphone dmp = new DoubleMetaphone();
         try{
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
             String str;
             while ((str = in.readLine()) != null) {
                     String[] parts = str.split("\t");
                     System.out.println(str+'\t'+dmp.doubleMetaphone(parts[1],false));
             }
         } catch (IOException e){
             System.exit(0);
         }
     }
}

オントロジーマッチ

関連オントロジーを、所与の文字列にマッチさせる。

オントロジー

マッチさせるオントロジーは以下の通り

ID-ターム対応ファイル生成

OBISはダウンロードが単純ではなく、取得は見送り。残りの5つについて、それぞれのファイル形式は下記の通りなので、各形式について対応。

オントロジー ファイル形式
EnvO obo
FMA MySQLダンプ
Plant Ontology obo
OGR owl
Gazetteer obo

OBO形式

EnvO、Plant Ontology、GazetteerはOBOフォーマットが取得出来るので、PerlプログラムでTermとIDの組を取得。

use warnings;
use strict;

my $skipflag = 0;
my $termid = "";
while(<>){
   chomp;
   if(/^$/){
       $skipflag = 0;
       next;
   }
   next if $skipflag;
   if(index($_, "[") == 0){
       $termid = "";
       my ($cat) = $_ =~ m/^\[(\w+)\]/;
       if($cat ne "Term"){
           $skipflag = 1;
           next;
       }
   }
   if(index($_, "id: ") == 0){
       substr($_, 0, 4, "");
       $termid = $_;
   }
   next unless index($_, "name: ") == 0;
   substr($_, 0, 6, "");
   print join("\t", ($termid, $_)), "\n";
}

MySQLダンプ形式

FMAはMySQLのダンプが取得出来るので、これをそのままロードする。

+-------------+----------------+------+-----+---------+-------+
| Field       | Type           | Null | Key | Default | Extra |
+-------------+----------------+------+-----+---------+-------+
| frame       | varbinary(500) | NO   | MUL | NULL    |       | 
| frame_type  | smallint(6)    | NO   |     | NULL    |       | 
| slot        | varbinary(500) | NO   | MUL | NULL    |       | 
| facet       | varbinary(500) | NO   |     | NULL    |       | 
| is_template | bit(1)         | NO   |     | NULL    |       | 
| value_index | int(11)        | NO   |     | NULL    |       | 
| value_type  | smallint(6)    | NO   |     | NULL    |       | 
| short_value | varchar(500)   | YES  | MUL | NULL    |       | 
| long_value  | mediumtext     | YES  |     | NULL    |       | 
+-------------+----------------+------+-----+---------+-------+
'SELECT frame,slot,short_value FROM fma WHERE slot="name" OR slot="FMAID"'

`frame`をキーとした構造になっているので、上記のクエリを発行して取得し、PerlスクリプトでTermとIDの組を生成。 一部のターム (3字未満、数値のみ、数値の後にアルファベット一文字、大文字一文字に続いて数値) は予めフィルタして出力。

use warnings;
use strict;

my (%fmaids, %terms);

while(<>){
   chomp;
   my ($frame, $slot, $short) = split /\t/;
   if($slot eq 'FMAID'){
       $fmaids{$frame} = $short;
   }elsif($slot eq 'name'){
       $terms{$frame} = $short;
   }
}

while(my ($frame, $fmid) = each %fmaids){
   next unless $terms{$frame};
   my $term = $terms{$frame};
   next if length($term) < 3 || $term =~ /\d+$/ || $term =~ /\d+[A-Za-z]$/ || $term =~ /^[A-Z]+\d+ /;
   print join("\t", ($fmid, $term)), "\n";
}

その他

OGRはowl形式のみ取得可能だが、rdfs:label属性が無く、文字列そのものをIDとし、rdfs:comment属性値にMeSHの地理情報に関する(Z01木)IDが書かれているのみなので、これとは別に予めDBCLSで取得しているMeSH2011 (mtrees2011.bin) を対象としてZ01部分を抽出。

grep ';Z0' mtrees2011.bin | perl -pe 's/;/\t/'

文字列マッチ

上記の処理を行うことで、全てIDと実際のタームがタブ区切りで一行一エントリの形式になる。 つづいて、文字列マッチを行うため、ACアルゴリズムに基づくマッチを行うPerlモジュールText::Scanを利用したプログラムを用意。

辞書生成プログラム

use warnings;
use strict;
use Text::Scan;

my %files = (
   'OGR', 'GeographicRegion.txt',
   'EnvO', 'envo.txt',
   'FMA', 'fma_terms.txt',
   'Gaz', 'gaz.txt',
   'PO', 'plant_ontology.txt',
   );

my $dict = new Text::Scan;
$dict->ignorecase();
$dict->squeezeblanks;
$dict->ignore("\n\r<>()[]");

for my $dname ( qw/OGR EnvO FMA Gaz PO/ ){
   open(my $fh1, $files{$dname}) or die "$files{$dname}:$!\n";
   while(<$fh1>){
       chomp;
       my ($id, $term) = split /\t/;
       if($dname eq 'OGR'){
               my $tmp = $id;
               $id = $term;
               $term = $tmp;
       }
       $term =~ s|[-,.:;/]| |g;
       my $dcname = ;
       if($dname eq 'EnvO' || $dname eq 'Gaz' || $dname eq 'PO'){
       }else{
               $dcname = $dname.':';
       }
       $dict->insert($term, $dcname.$id);
       print join("\t", ($term, $dcname.$id)), "\n";
   }
   close($fh1);
}

$dict->serialize("bh11jpDict");

文字列マッチプログラム

use warnings;
use strict;
use Text::Scan;

my $dict = new Text::Scan;
$dict->restore("bh11jpDict");
$dict->squeezeblanks;
$dict->charclass("[]<>().:;,?");
$dict->boundary("'\"[]<>():;,/-.? ");

open(my $fh, "merged.txt") or die $!;
while(<$fh>){
   chomp;
   my @result = $dict->multiscan(' '.$_.' ');
   for my $r ( @result ){
       print join("\t", ($_, $r->[0], $r->[2])), "\n";
   }
}
close($fh);