LIBLINEARデータ読み込み中のエラー

LIBLINEAR使用時にデータ読み込み中にエラーで終了することがあります。
エラーメッセージに該当箇所の行番号は出るものの
原因が書いていないのでわかりにくい。

そこでエラーが起きたらデータがこんなことになっていないか確認しています。

  • 2値分類の場合、負例からはじまっていないか(データファイル1行目を正例にする)
  • 素性番号が昇順になっているか
  • 一例内に素性番号の重複がないか
  • 不正な文字が入っていないか
  • 空行が含まれていないか
  • 素性番号に0番のものがないか

Wikipediaのリダイレクト一覧を言い換えリスト化

Wikipediaデータベース日本語版jawiki-latest-stub-articles.xml.gz(pages-articles.xmlの本文を除いた版)から記事IDと記事タイトルを取得して, その情報をもとにjawiki-latest-redirect.sql.gz(リダイレクト先一覧)のリダイレクト元記事IDを記事タイトルに置換して読みやすくするスクリプトを書きました。
出力結果からゴミデータを除けば、同義語辞書、あるいは言い換えリストに加えることができるかもしれません。

# -*- coding: utf-8 -*-
 
# Wikipediaの記事id-titleペア情報を使ってリダイレクト一覧を見やすくする
# 
# jawiki-latest-stub-articles.xmlから記事id-titleペア情報を取得し,
# リダイレクト一覧のリダイレクト元記事idを記事titleに書き換える
 
import re
 
re_tag_extract = re.compile('>(.*)</')
re_parentheses_extract = re.compile("\(([0-9]+,[0-9]+,[^,]+,[^,]+,\'[^\']*\')\)")
 
# jawiki-latest-stub-articles.xmlから記事idとtitleの辞書を生成
"""
jawiki-latest-stub-articles.xmlの内容例
<page>
  <title>哲学</title>
  <id>110</id>
  <revision>
    <id>28432395</id>
    <timestamp>2009-10-11T11:11:19Z</timestamp>
    <contributor>
      <ip>202.95.44.163</ip>
    </contributor>
    <comment>/* 外部リンク */ [[Wikipedia:外部リンクの選び方]]参照</comment>
    <text id="28286198" />
  </revision>
</page>
"""
title_flag = False
id2title = {}
with open('jawiki-latest-stub-articles.xml','r') as wiki_stub_articles:
	for line in wiki_stub_articles:
		if '<title>' in line:
			title = ''.join(re_tag_extract.findall(line))
			title_flag = True
		elif '<id>' in line:
			if title_flag:
				wikiid = ''.join(re_tag_extract.findall(line))
				id2title[wikiid] = title
			title_flag = False
 
# jawiki-latest-redirect.sqlからデータを抽出
"""
jawiki-latest-redirect.sql内容例
(407868,0,'色空間','','')
"""
with open('jawiki-latest-redirect.sql','r') as wiki_redirect:
	redirects = re_parentheses_extract.findall(wiki_redirect.read())
 
# リダイレクトデータの記事idを記事タイトルに置き換える
"""
置換例
X.v.Color,0,'色空間','',''
"""
result = []
for redirect in redirects:
	columns = redirect.split(',')
	if id2title.has_key(columns[0]):
		columns[0] = id2title.pop(columns[0])
		result.append(','.join(columns))
 
# wikisynonym.csvに結果を書き込む
with open('wikisynonym.csv','w') as wikisynonym:
	wikisynonym.write('\n'.join(result))

複数のサイトから注目キーワードを取得

MeCabの辞書を自動で新語に対応させるにはどうすればいいかって問題にWebの注目キーワード(あるいは急上昇キーワード)を使ってみようと思ってスクリプトを書いてみました。

複数サイトから注目キーワードを取得する · GitHub

このスクリプトが出力するテキストファイルから全角半角を正規化して、MeCabの辞書に入っていないか判断したり不要な語をカットすればよさそう。


Buzzword API [話題の流行語や注目キーワード取得API] あれこれ (BuzzwordAPI - MemoWiki v2)を参考に書きました。

LIBLINEAR1.93のcross validationオプションでprecision/recallを出力する

というエントリを読んで便利そうだったので、LIBLINEAR1.93でもcross validationオプションでprecision/recall値を出力するようにしました。

--- train.c	2012-10-29 01:46:32.000000000 +0900
+++ train-new.c	2013-02-12 19:53:21.000000000 +0900
@@ -135,10 +135,14 @@
 void do_cross_validation()
 {
 	int i;
-	int total_correct = 0;
 	double total_error = 0;
 	double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0;
 	double *target = Malloc(double, prob.l);
+	//** To caluculate precision/recall for each class **/
+	int tp = 0;
+	int fp = 0;
+	int tn = 0;
+	int fn = 0;
 
 	cross_validation(&prob,&param,nr_fold,target);
 	if(param.solver_type == L2R_L2LOSS_SVR ||
@@ -164,10 +168,42 @@
 	}
 	else
 	{
-		for(i=0;i<prob.l;i++)
-			if(target[i] == prob.y[i])
-				++total_correct;
-		printf("Cross Validation Accuracy = %g%%\n",100.0*total_correct/prob.l);
+		for(i=0;i<prob.l; i++) {
+			if(prob.y[i] == 1) { // True label = +1
+				if(target[i] == prob.y[i]) {
+					tp++;
+				} else {
+					fp++;
+				}
+			} else { // True label = -1
+				if (target[i] == prob.y[i]) {
+					tn++;
+				} else {
+					fn++;
+				}
+			}
+		}
+
+		printf("Cross Validation Accuracy = %g%%\n",100.0 * ((double)(tp + tn) / (double)(tp + fp + tn + fn)) );
+ 
+		// Precision and recall
+		double pos_prec	 = ((double)tp/(double)(tp + fp));
+		double pos_rec		= ((double)tp/(double)(tp + fn));
+		double pos_f1		 = (2 * pos_prec * pos_rec) / (pos_prec + pos_rec);
+
+		double neg_prec	 = ((double)tn/(double)(tn + fn));
+		double neg_rec		= ((double)tn/(double)(tn + fp));
+		double neg_f1		 = (2 * neg_prec * neg_rec) / (neg_prec + neg_rec);
+			
+		printf("Positive (+1) class:\n");
+		printf("  precision = %g\n", pos_prec );
+		printf("     recall = %g\n", pos_rec );
+		printf("   F1 value = %g\n\n", pos_f1 );
+
+		printf("Negative (-1) class:\n");
+		printf("  precision = %g\n", neg_prec );
+		printf("     recall = %g\n", neg_rec );
+		printf("   F1 value = %g\n\n", neg_f1 );
 	}
 
 	free(target);
@@ -397,3 +433,4 @@
 
 	fclose(fp);
 }
+

MMDAgent関連のメモ

Vine6にmecab-python-0.993をインストール

$ sudo apt-get install python-devel
$ perl -pe 's/mecab-config/\/usr\/local\/bin\/mecab-config/g' < setup.py >temp
$ cat temp > setup.py
$ rm temp
$ python setup.py build
$ su
# python setup.py install
# echo /usr/local/lib >> /etc/ld.so.conf
# vim /etc/ld.so.conf
# ldconfig
# exit
$ python test.py
  • python-develを入れないとmecab-pythonをbuildできない
  • スーパーユーザ(su)は/usr/local/binにパスが通っていないのでsetup.pyを書き換える
  • so読み込みパスに/usr/local/libを追加する

Mozcの辞書をMeCabで使う

MozcとMeCabの辞書って似てるところあるなーって思ったので、Mozc辞書をMeCab辞書に変換するスクリプトを書きました。

https://github.com/ikegami-yukino/NLP/blob/master/dic/mozc2mecabdic.py

MozcはMeCabよりも文脈IDが細分化されていますが、そのままだと問題が起こりそうな気配がするので、MeCabと共通している文脈IDの単語だけを処理します。

変換結果はこんな感じです。

アクセス制御,1356,1356,5044,名詞,サ変接続,*,*,*,*,アクセス制御,アクセスセイギョ,アクセスセイギョ,MOZC
日本お笑い,1366,1366,5987,名詞,固有名詞,地域,国,*,*,日本お笑い,ニッポンオワライ,ニッポンオワライ,MOZC
終電時間,1358,1358,6131,名詞,一般,*,*,*,*,終電時間,シュウデンジカン,シュウデンジカン,MOZC
特定投資家,1356,1356,7433,名詞,サ変接続,*,*,*,*,特定投資家,トクテイトウシカ,トクテイトウシカ,MOZC
大街道店,1365,1365,7375,名詞,固有名詞,地域,一般,*,*,大街道店,オオカイドウテン,オオカイドウテン,MOZC
情報無けれ,1358,1358,6392,名詞,一般,*,*,*,*,情報無けれ,ジョウホウナケレ,ジョウホウナケレ,MOZC
強制捜査,1356,1356,5888,名詞,サ変接続,*,*,*,*,強制捜査,キョウセイソウサ,キョウセイソウサ,MOZC
10月あたり,1394,1394,4866,名詞,副詞可能,*,*,*,*,10月あたり,ジュウガツアタリ,ジュウガツアタリ,MOZC
十月あたり,1394,1394,4912,名詞,副詞可能,*,*,*,*,十月あたり,ジュウガツアタリ,ジュウガツアタリ,MOZC

元がかな漢字変換用の辞書のせいか、形態素解析で使うには微妙なものが混じってます。なんらかの形でふるいにかけると良さそうですね。

人名は割と使えるものが多そうです。