2017.12.15 Friday
スポンサーサイト
一定期間更新がないため広告を表示しています
| スポンサードリンク | - | | - | - |
関口宏司のLuceneブログOSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
2012.08.11 Saturday
CaboChaとKNBコーパスで固有表現抽出を行う
さらにCaboChaの評価は続く。今回はKNBコーパスを使って固有表現抽出の交差検定(5分割)を行った。
今回はprecisionやrecallをカウントする評価ツールも自作した。実際にどのようにカウントするかをフィクションのデータを例にした下表を使って説明する:
以上から、このフィクションのデータの例では: precision = tp / (tp + fp) = 2 / (2 + 2) = 0.5 recall = tp / (tp + fn) = 2 / (2 + 2) = 0.5 F = 2PR / (P + R) = 2 * 0.5 * 0.5 / (0.5 + 0.5) = 0.5 (ここで、P:precision, R:recall) 結果 結果は予想していた通りF値で40から60ポイント程度と低い値となった。原因としては、KNBコーパスはデータ量が多くないがその中でも固有表現タグはさらに数が限定されるためと考えられる。また、モデルファイルのとりかたによって固有表現タグの出現に濃淡があり、そのため正解率にばらつきがある。固有表現タグの種類(ORGANIZATIONやLOCATIONなど)にも数の多い少ないがあり(詳細はKNBコーパスの論文を参照)、これらも影響している可能性があるだろう。さらに、学習データを作成する際に、複数のNEタグ候補があるOPTIONALタグをそのままOPTIONALタグとして出力した。複数候補をCaboChaに学習させる方法がわからなかったためだが、これも学習データの量を減少させ、正解率を落とした原因といえる(このため、評価ツールでは正解データがOPTIONALの場合、fnをカウントしないこととした)。いずれにしてもデータ量が少ないのが残念だ。
今回作成したプログラム KNBコーパスをNEタグ付きのCaboCha形式に変更するプログラム knbc2cabocha_ne.rb と 評価プログラム eval_ne.rb を作成したので掲載する: knbc2cabocha_ne.rb このプログラムでは、OPTIONALタグはそのままOPTIONALタグとして出力した。しかし、(おそらくは)CaboChaではOPTIONALタグはスキップしており(?)、OPTIONALの実際の候補であるLOCATIONやORGANIZATIONなどを出力すべきであると考えられる。そのため、次の評価プログラムでは正解データがOPTIONALの場合は、fnはカウントしないようにした。 KNBC_DIR = ARGV[0] CATEGORIES = ["Keitai", "Kyoto", "Gourmet", "Sports"] def ne(terms) ne_m = / eval_ne.rb def next_term_ne(file) while line = file.gets next if /¥A¥*/ =~ line return "EOS", nil if /¥AEOS/ =~ line terms = line.split return terms[0], terms[-1] end return nil, nil end def no_ne(ne_a) return true if ne_a.length == 1 && ne_a[0] == nil ne_a.each{ |ne| return false unless ne == "O" } true end def print_terms(ans_str_a, ans_ne_a, out_str_a, out_ne_a) if ans_str_a != out_str_a || ans_ne_a != out_ne_a puts "#{ans_str_a.join("/")}(#{ans_ne_a.join(",")}) #{out_str_a.join("/")}(#{out_ne_a.join(",")})" end end def num_ne(ne_a) return 0 if ne_a.length == 1 && ne_a[0] == nil num = 0 ne_a.each{ |ne| num += 1 unless ne == "O" } num end def check(ans_str_a, ans_ne_a, out_str_a, out_ne_a, tp, fp, fn) if !no_ne(ans_ne_a) print_terms(ans_str_a, ans_ne_a, out_str_a, out_ne_a) if !no_ne(out_ne_a) i = 0 while true ans_ne_c = i < ans_ne_a.length ? ans_ne_a[i] : "" out_ne_c = i < out_ne_a.length ? out_ne_a[i] : "" break if ans_ne_c == "" && out_ne_c == "" if ans_ne_c != "O" && out_ne_c != "O" if ans_ne_c == out_ne_c tp += 1 else fn += 1 if ans_ne_c != "O" && ans_ne_c != "" && ans_ne_c.index("OPTIONAL") != nil fp += 1 if out_ne_c != "O" && out_ne_c != "" end end i += 1 end else fn += num_ne(ans_ne_a) end elsif !no_ne(out_ne_a) fp += num_ne(out_ne_a) print_terms(ans_str_a, ans_ne_a, out_str_a, out_ne_a) end return tp, fp, fn end ans_file = File.open(ARGV[0]) out_file = File.open(ARGV[1]) tp = fp = fn = 0 while true ans_str_a = [] ans_ne_a = [] out_str_a = [] out_ne_a = [] ans_term, ans_ne = next_term_ne(ans_file) ans_str_a << ans_term ans_ne_a << ans_ne out_term, out_ne = next_term_ne(out_file) out_str_a << out_term out_ne_a << out_ne break if ans_term == nil || out_term == nil while out_str_a.join("").length != ans_str_a.join("").length if out_str_a.join("").length > ans_str_a.join("").length ans_term, ans_ne = next_term_ne(ans_file) ans_str_a << ans_term ans_ne_a << ans_ne elsif out_str_a.join("").length < ans_str_a.join("").length out_term, out_ne = next_term_ne(out_file) out_str_a << out_term out_ne_a << out_ne end end tp, fp, fn = check(ans_str_a, ans_ne_a, out_str_a, out_ne_a, tp, fp, fn) end ans_file.close out_file.close printf("tp = %d, fp = %d, fn = %d¥n", tp, fp, fn) precision = tp.to_f / (tp.to_f + fp.to_f) recall = tp.to_f / (tp.to_f + fn.to_f) f = 2.0 * precision * recall / (precision + recall) printf("precision = %f, recall = %f, F = %f¥n", precision, recall, f) オペレーションメモ # KNBコーパスをNEタグ付きCaboCha形式に変更。 $ ruby knbc2cabocha_ne.rb ../KNBC_v1.0_090925/corpus1 # NEタグ付きCaboCha形式のデータをマージしながら同程度の5つに分割。 $ ruby rearrange.rb 4 837 Keitai.dat Kyoto.dat Gourmet.dat Sports.dat # モデルのソースを生成。 $ cat G0402.dat G0403.dat G0404.dat G0405.dat > model.source.ne.1 $ cat G0401.dat G0403.dat G0404.dat G0405.dat > model.source.ne.2 $ cat G0401.dat G0402.dat G0404.dat G0405.dat > model.source.ne.3 $ cat G0401.dat G0402.dat G0403.dat G0405.dat > model.source.ne.4 $ cat G0401.dat G0402.dat G0403.dat G0404.dat > model.source.ne.5 # NEを学習。 $ /usr/local/libexec/cabocha/cabocha-learn -e ne -P JUMAN model.source.ne.1 ne.juman.1 $ /usr/local/libexec/cabocha/cabocha-learn -e ne -P JUMAN model.source.ne.2 ne.juman.2 $ /usr/local/libexec/cabocha/cabocha-learn -e ne -P JUMAN model.source.ne.3 ne.juman.3 $ /usr/local/libexec/cabocha/cabocha-learn -e ne -P JUMAN model.source.ne.4 ne.juman.4 $ /usr/local/libexec/cabocha/cabocha-learn -e ne -P JUMAN model.source.ne.5 ne.juman.5 # CaboCha形式のデータから原文テキストを逆再生。 $ ruby make_source.rb 0401 $ ruby make_source.rb 0402 $ ruby make_source.rb 0403 $ ruby make_source.rb 0404 $ ruby make_source.rb 0405 # cabocha -e ne で固有表現抽出。 $ cat S0401-01.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.1 -O1 -f1 -n1 > O0401.txt $ cat S0401-02.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.1 -O1 -f1 -n1 >> O0401.txt $ cat S0401-03.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.1 -O1 -f1 -n1 >> O0401.txt $ cat S0402-01.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.2 -O1 -f1 -n1 > O0402.txt $ cat S0402-02.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.2 -O1 -f1 -n1 >> O0402.txt $ cat S0402-03.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.2 -O1 -f1 -n1 >> O0402.txt $ cat S0403-01.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.3 -O1 -f1 -n1 > O0403.txt $ cat S0403-02.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.3 -O1 -f1 -n1 >> O0403.txt $ cat S0403-03.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.3 -O1 -f1 -n1 >> O0403.txt $ cat S0404-01.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.4 -O1 -f1 -n1 > O0404.txt $ cat S0404-02.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.4 -O1 -f1 -n1 >> O0404.txt $ cat S0404-03.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.4 -O1 -f1 -n1 >> O0404.txt $ cat S0405-01.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.5 -O1 -f1 -n1 > O0405.txt $ cat S0405-02.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.5 -O1 -f1 -n1 >> O0405.txt $ cat S0405-03.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./ne.juman.5 -O1 -f1 -n1 >> O0405.txt # 正解データと比較。 $ ruby eval_ne.rb G0401.dat O0401.txt $ ruby eval_ne.rb G0402.dat O0402.txt $ ruby eval_ne.rb G0403.dat O0403.txt $ ruby eval_ne.rb G0404.dat O0404.txt $ ruby eval_ne.rb G0405.dat O0405.txt 2012.08.10 Friday
CaboChaでKNBコーパスを使う
またまたCaboChaの続きで、今回は京都コーパスではなくKNBコーパス(KNBC)を使う。KNBコーパスは京都コーパスと異なり、タグ情報だけでなく本文情報も含まれているので、この記事の通りのオペレーションを行えば、(途中までは)毎日新聞データを持たない読者も実際にCaboChaの学習や評価を試すことができる。
KNBコーパスにはさまざまな特徴があるが、ここで注目するのは京都コーパスと比較しての下記の点である:
KNBコーパスは4つのカテゴリ「携帯電話」「京都観光」「グルメ」「スポーツ」のどれかについて書かれたブログ記事に文境界、形態素、係り受け、格・省略・照応、固有表現、評価表現の各種アノテーションを付加した解析済みコーパスである。毎日新聞の記事データにアノテーションを付加した京都コーパスに比べデータ量が約一桁少ない(京都コーパス38400文に対し、KNBコーパスは4184文)。また、ブログ記事ということで新聞記事と比べて「文境界があいまい」「構文構造の解析を困難にする括弧表現」「誤字、方言、顔文字などの多様な形態素」というCGM的な特徴を有する。 このような特徴を踏まえ、今回は次のような評価を行った:
1.はKNBコーパス内部の学習・評価を行うものである。ここでは簡単に522文からなるスポーツカテゴリを評価用に残し、それ以外のカテゴリである携帯電話、京都観光、グルメの全合計3662文を学習することにした。量的には前の記事で作成した chunk.juman.10.1 モデルファイルでのテスト(3200文;エラー率0.2116)に近い量である。 2.と3.はブログ記事と新聞記事のクロス的・相互的な学習・評価のテストであり、ブログ記事を学習してモデルファイルを作成し新聞記事を解析した場合やその逆を行ってみて、解析性能がどの程度になるか見るものである。 結果 前の記事と比較のため、また、自作したツール類が再利用できることなどから、同様にCaboChaのchunkを対象に評価を行った。結果は下表の通り:
KNBC-KNBCテストでは、ブログ記事の3662文を学習したモデルが、量的にはそれよりも少ない京都コーパス3200文を学習したモデルよりもエラー率が高くなった。 KNBC-KCテストは全ブログ記事のコーパスを学習したモデルで新聞記事を解析するテストだが、やはりエラー率はさらに上がった。 KC-KNBCテストはKNBC-KCテストとは逆に、新聞記事である京都コーパスを学習したモデルでブログ記事を解析するテストであるが、同様にエラー率は高かった。 今回作成したプログラム KNBコーパスのcorpus1ディレクトリを第一引数に指定するとコーパスデータをCaboCha形式のKeitai.dat, Kyoto.dat, Gourmet.dat, Sports.datのデータに出力する knbc2cabocha_chunk.rb というプログラムを作成した: KNBC_DIR = ARGV[0] CATEGORIES = ["Keitai", "Kyoto", "Gourmet", "Sports"] CATEGORIES.each{|category| File.open("#{category}.dat", "w"){|ofile| Dir.glob(KNBC_DIR+"/KN???_#{category}_*").sort!.each{|article_dir_path| File.open("#{article_dir_path}/fileinfos"){|info_file| while info_line = info_file.gets File.open("#{article_dir_path}/#{info_line.split[1].split(/:/)[1]}"){|ifile| chunk_num = 0 while line = ifile.gets next if /¥A# S-ID:/ =~ line # skip the comment line terms = line.split if terms[0] == "*" # ofile.puts "* #{chunk_num} #{terms[1]}" ofile.puts "* #{chunk_num} -1D" chunk_num += 1 elsif terms[0] == "+" next elsif terms[0] == "EOS" ofile.puts "EOS" else ofile.puts "#{terms[0]}¥t#{terms[3]},#{terms[5]},*,*,#{terms[2]},#{terms[1]},*" end end } end } } } } オペレーションメモ # KNBコーパスをCaboCha形式に変形しつつ、4つのカテゴリごとのファイルに分ける。 $ ruby knbc2cabocha_chunk.rb ../KNBC_v1.0_090925/corpus1 # 前の記事の習慣に合わせリネーム。 $ mv Keitai.dat G41.dat $ mv Kyoto.dat G42.dat $ mv Gourmet.dat G43.dat $ mv Sports.dat G44.dat # [KNBC-KNBC] モデルのソースを作成。 $ cat G4[1-3].dat > model.source.knbc-knbc # [KNBC-KNBC] 学習。 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.knbc-knbc chunk.juman.knbc-knbc # [KNBC-KNBC] CaboCha形式の学習データG44.datから原文テキストファイルS44-x.txtを逆再生 $ ruby make_source.rb 44 # [KNBC-KNBC] cabochaの実行。 $ cat S44-01.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.knbc-knbc -O2 -f1 -n0 > O44.txt $ cat S44-02.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.knbc-knbc -O2 -f1 -n0 >> O44.txt # [KNBC-KNBC] 正解データとcabochaの出力を比較用に正規化。 $ ruby norm_chunk.rb G44.dat > G44-norm.dat $ ruby norm_chunk.rb O44.txt > O44-norm.txt # [KNBC-KNBC] エラー率の表示。 $ ruby diff_chunk.rb G44-norm.dat O44-norm.txt error = 0.2989 (156/522) # ----------- # [KNBC-KC] モデルのソースを作成。 $ cat G4[1-4].dat > model.source.knbc-kc # [KNBC-KC] 学習。 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.knbc-kc chunk.juman.knbc-kc # [KNBC-KC] cabochaの実行。 $ cat S1011-01.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.knbc-kc -O2 -f1 -n0 > O1011.txt $ cat S1011-02.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.knbc-kc -O2 -f1 -n0 >> O1011.txt : $ cat S1011-16.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.knbc-kc -O2 -f1 -n0 >> O1011.txt # [KNBC-KC] cabochaの出力を比較用に正規化。 $ ruby norm_chunk.rb O1011.txt > O1011-norm.txt # [KNBC-KC] エラー率の表示。 $ ruby diff_chunk.rb G1011-norm.dat O1011-norm.txt error = 0.3214 (2057/6400) # ----------- # [KC-KNBC] cabochaの実行。 $ cat S44-01.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.10.10 -O2 -f1 -n0 > O1044.txt $ cat S44-02.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.10.10 -O2 -f1 -n0 >> O1044.txt # [KC-KNBC] cabochaの出力を比較用に正規化。 $ ruby norm_chunk.rb O1044.txt > O1044-norm.txt # [KC-KNBC] エラー率の表示。 $ ruby diff_chunk.rb G44-norm.dat O1044-norm.txt error = 0.2969 (155/522) 2012.08.08 Wednesday
モデルとなる京都コーパスの量を変えたときのCaboChaの性能を見る
CaboCha+京都コーパスの続きである。
前の記事ではdat/syn/ ディレクトリにある拡張子が.KNPのファイル28個を上から6個、6個、6個、5個、5個ずつまとめて交差検定を行った。すると、学習データの量に偏りが出たせいか、エラー率は12%から18%とばらつきがあった。 そこで今度は学習データのファイルを文の個数で正確に分割し、学習データの量とchunkの正解率の変化を見てみることにした。具体的には、データが38400文あったのでこれを12分割(すると38400/12=3200となる)し、最後の2つ分、6400文を正解データと固定して、残りの10個分をモデルファイルのソースとし、これを1つ分、2つ分、... と増やしていったときのエラー率に注目する。 結果は期待通り、データ量が増えるにしたがいエラー率が下がった:
ここで、chunk.juman.10.1は3200文、chunk.juman.10.2は6400文と学習データ量が増えていき、chunk.juman.10.10は32000文である。グラフ化すると次の通り: 今回作成したプログラム G5[1-5].datという5つのファイルから同じ数の文に再整理して出力する rearrange.rb というプログラムを作成した。 rearrange.rb TARGET_NUM = ARGV[0].to_i SENTENCE_NUM = ARGV[1].to_i def target_file_name(num) sprintf("G%02d%02d.dat", TARGET_NUM, num) end $ai = 1 $ifile = nil $end_of_sources = false def next_source $ifile.close if $ifile $ai = $ai + 1 return nil if $ai >= ARGV.length puts "reading #{ARGV[$ai]} ..." $ifile = File.open(ARGV[$ai]) end def read_sentence sentence = Array.new while true do while line = $ifile.gets do sentence << line return sentence if /¥AEOS/ =~ line end unless next_source $end_of_sources = true return [] end end end return nil if $ai >= ARGV.length puts "reading #{ARGV[$ai]} ..." $ifile = File.open(ARGV[$ai]) end def read_sentence sentence = Array.new while true do while line = $ifile.gets do sentence << line return sentence if /¥AEOS/ =~ line end unless next_source $end_of_sources = true return [] end end end # create target files - for model files next_source TARGET_NUM.times {|tnum| snum = 0 File.open(target_file_name(tnum+1), "w"){|ofile| while snum < SENTENCE_NUM read_sentence.each{|line| ofile.puts line } snum = snum + 1 end } } # also create a target file - for evaluation File.open(target_file_name(TARGET_NUM+1), "w"){|ofile| until $end_of_sources do read_sentence.each{|line| ofile.puts line } end } オペレーションメモ # 学習データと評価用データの再作成 # 第1引数: ターゲット学習データの個数 # 第2引数: 1個あたりのターゲット学習データ内の文の個数 # 第3引数以降: CaboCha形式ソースデータファイル $ ruby rearrange.rb 10 3200 G5?.dat # モデルのソースを生成 $ cat G100[1].dat > model.source.10.1 $ cat G100[1-2].dat > model.source.10.2 $ cat G100[1-3].dat > model.source.10.3 $ cat G100[1-4].dat > model.source.10.4 $ cat G100[1-5].dat > model.source.10.5 $ cat G100[1-6].dat > model.source.10.6 $ cat G100[1-7].dat > model.source.10.7 $ cat G100[1-8].dat > model.source.10.8 $ cat G100[1-9].dat > model.source.10.9 $ cat G100[1-9].dat G1010.dat > model.source.10.10 # 学習。規模に応じてだんだん時間がかかる(20秒〜150秒程度) $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.10.1 chunk.juman.10.1 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.10.2 chunk.juman.10.2 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.10.3 chunk.juman.10.3 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.10.4 chunk.juman.10.4 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.10.5 chunk.juman.10.5 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.10.6 chunk.juman.10.6 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.10.7 chunk.juman.10.7 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.10.8 chunk.juman.10.8 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.10.9 chunk.juman.10.9 $ /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN model.source.10.10 chunk.juman.10.10 # CaboCha形式の学習データG1011.datから原文テキストファイルS1011-x.txtを逆再生 $ ruby make_source.rb 1011 # 各モデルファイルを使い原文テキストS1011-x.datに対してcabochaを実行 $ cat S1011-01.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.10.1 -O2 -f1 -n0 > O10A01.txt $ cat S1011-02.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.10.1 -O2 -f1 -n0 >> O10A01.txt : $ cat S1011-01.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.10.2 -O2 -f1 -n0 > O10A02.txt $ cat S1011-02.txt | cabocha -d /usr/local/lib/mecab/dic/jumandic -M ./chunk.juman.10.2 -O2 -f1 -n0 >> O10A02.txt : # 正解データの正規化 $ ruby norm_chunk.rb G1011.dat > G1011-norm.dat # cabochaの出力を正規化 $ ruby norm_chunk.rb O10A01.txt > O10A01-norm.txt $ ruby norm_chunk.rb O10A02.txt > O10A02-norm.txt : $ ruby norm_chunk.rb O10A10.txt > O10A10-norm.txt # モデルファイル量ごとの評価(エラー率の表示) $ ruby diff_chunk.rb G1011-norm.dat O10A01-norm.txt error = 0.2116 (1354/6400) $ ruby diff_chunk.rb G1011-norm.dat O10A02-norm.txt error = 0.1861 (1191/6400) $ ruby diff_chunk.rb G1011-norm.dat O10A03-norm.txt error = 0.1708 (1093/6400) $ ruby diff_chunk.rb G1011-norm.dat O10A04-norm.txt error = 0.1598 (1023/6400) $ ruby diff_chunk.rb G1011-norm.dat O10A05-norm.txt error = 0.1509 (966/6400) $ ruby .diff_chunk.rb G1011-norm.dat O10A06-norm.txt error = 0.1448 (927/6400) $ ruby diff_chunk.rb G1011-norm.dat O10A07-norm.txt error = 0.1383 (885/6400) $ ruby diff_chunk.rb G1011-norm.dat O10A08-norm.txt error = 0.1341 (858/6400) $ ruby diff_chunk.rb G1011-norm.dat O10A09-norm.txt error = 0.1272 (814/6400) $ ruby diff_chunk.rb G1011-norm.dat O10A10-norm.txt error = 0.1259 (806/6400) |
+ Solrによるブログ内検索
+ PROFILE
+ LINKS
+ Lucene&Solrデモ
+ ThinkIT記事
+ RECOMMEND
+ RECOMMEND
Lucene in Action (JUGEMレビュー »)
Erik Hatcher,Otis Gospodnetic,Mike McCandless FastVectorHighlighterについて解説記事を寄稿しました。
+ RECOMMEND
+ SELECTED ENTRIES
+ RECENT COMMENTS
+ RECENT TRACKBACK
+ CATEGORIES
+ ARCHIVES
+ MOBILE
+ SPONSORED LINKS
|
(C) 2024 ブログ JUGEM Some Rights Reserved.
|
PAGE TOP |