[[python/集合知3章]]

2009/02/08からのアクセス回数 &counter;

** はじめに [#hca3206d]
pythonを使っていて感じるのは、便利だけどパッケージがマシンに依存し過ぎている
ように思われます。

例えば、スクリプトを別のマシンで動かそうとしたときに、パッケージのインストールから
はじめなくてはならないときに痛烈に感じます。

そこで、ここではjythonとjavaを使ってpythonのマシン依存部分をjavaのクラスとjythonの
スクリプトでラップしてみようと思います。

** 日本語の分かち書き [#bcf63440]
[[python/集合知3章]]と同様に、ブログに対する日本語処理からはじめます。

*** senのインストール [#l6877481]
chasenと同様の機能を持つjavaのライブラリにSenがあります。
残念ながら、maven2のパッケージとして提供されていないので、[[java.netのsenのドキュメント&ファイルページ>https://sen.dev.java.net/servlets/ProjectDocumentList?folderID=755&expandFolder=755&folderID=0]]からsen-1.2.2.1.zipをダウンロードしてください。

- ZIPファイルの解凍

ここでは、
-- ダウンロードしたファイルは、~/Downloadedディレクトリ
-- 解凍先は、~/localディレクトリ

にあるものとして説明します。

-- unzipで解凍します

#pre{{
$ cd ~/local/
$ unzip ~/Downloaded/sen-1.2.2.1.zip
$ cd sen-1.2.2.1/
}}

- 辞書の作成
つぎにantを使って辞書を作成します。

-- 辞書の作成にはperlが必要です。ここでは/usr/bin/perlを使います。

#pre{{
$ cd dic
$ ant -Dperl.bin=/usr/bin/perl
}}

- jarファイルのmaven2への登録
最後にsen.jarファイルをmaven2で利用できるようにローカルディポジトリに登録します。

#pre{{
$ cd ../lib
$ mvn install:install-file -Dfile=./sen.jar -DgroupId=sen \
           -DartifactId=sen -Dversion=1.0 -Dpackaging=jar
}}

*** pythonlibの作成 [#t0a1c539]
作成したライブラリは1つのjarにまとめておくとjythonから利用するときに便利です。

ここでは、pythonlibというEclipseのプロジェクトをmaven2を使って作成します。

- プロジェクトの作成

最初にjythonlibのプロジェクトを作成します。
#pre{{
$ mvn archetype:create -DgroupId=jythonlib -DartifactId= jythonlib -Dversion=0.1
}}

- pom.xmlの編集

pom.xmlを編集して、sen.jar, common-logging.jarを使えるようにします。
以下の定義をdependenciesに追加
#pre{{
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1.1</version>
    </dependency>
    <dependency>
      <groupId>sen</groupId>
      <artifactId>sen</artifactId>
      <version>1.0</version>
    </dependency>
}}

次にbuildを追加し、javaのバージョン、UTF-8の設定、jarファイルの設定、依存ライブラリのコピーをセットします。

#pre{{
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>    
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
           <archive>
            <manifest>
              <mainClass>jythonlib.Sen</mainClass>
              <packageName>jythonlib</packageName>
              <addClasspath>true</addClasspath>
              <addExtensions>true</addExtensions>
              <classpathPrefix>./lib</classpathPrefix>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <id>copy-dependencies</id>
            <phase>package</phase>
            <goals>
              <goal>copy-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/lib</outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>  
  </build>
}}

この設定は、結構役に立ちますから、覚えておいた方がいいですよ。

- Eclipseプロジェクトに対応
以下のコマンドで、Eclipseの.projectと.classpthを作成します。

#pre{{
$ mvn eclipse:eclipse -DdownloadSources=true
}}

*** Senクラスの作成 [#z42e3be5]
senの形態素解析を実行し、jythonにその結果を返すクラスSen.javaを作成します。

変換部分は、
#pre{{
	private String[] parts = {"形容詞", "形容動詞", "副詞", "連体詞", "名詞", "動詞"};
	public List<String> sparse(String text) {
		List<String> list = new ArrayList<String>();
		try {			
			StringTagger tagger = StringTagger.getInstance();
			Token[] token = tagger.analyze(text);
			String	term = null;
			for (int i = 0; i < token.length; i++) {
				// 未知語、英語の単語
				if ((term = token[i].getTermInfo()) == null) {
					list.add(token[i].getSurface());
				}
				else {
					for (String part : parts) {
						if (term.startsWith(part)) {
							list.add(token[i].getBasicString());
							break;
						}						
					}
				}
			}

		} catch (Exception e) {
		}
		return (list);
	}
}}
と簡単です。

*** Jythonとjava間の日本語処理 [#x6518ada]

jythonとjavaとの日本語は、結構大変です。ここでは以下の方針で文字を渡すことに
します。

- jythonからjavaへは、UTF-8でエンコーディングされたバイト文字列を渡す
javaでの変換は以下のようになります。
#pre{{
jTxt = String(txt, "utf-8")
}}
- javaからjythonへは、unicodeにエンコーディングされた文字列を渡す
javaでの変換は以下のようになります。
#pre{{
uTxt = String(word.getBytes('utf-8'), 'iso-8859-1')
}}

sen用のsplitメソッドをsplit.pyに以下のように定義します。

#pre{{
# -*- coding: utf-8 -*-
import japanese
import codecs
import jarray
import jythonlib.Sen
import java.lang.String
from java.lang  import *

parts = ["形容詞", "形容動詞", "副詞", "連体詞", "名詞", "動詞"]
parts = jarray.array([String(part, "utf-8") for part in parts], java.lang.String)

def split(txt):   
    jTxt = String(txt, "utf-8")
    sen = jythonlib.Sen(parts)
    words = sen.sparse(jTxt)
    outList = []
    for i in range(len(words)):
        word = String(words.get(i))
        outList.append(String(word.getBytes('utf-8'), 'iso-8859-1'))
    return outList
}}

*** 動作確認 [#p94f14f0]
senを使った分かち書きのテストをします。

#pre{{
# -*- coding: utf-8 -*-
import japanese
import split

txt = "オリジナルのソースは、原書著者TobesのページからPCI_Code.zipと してダウンロードできます。"
print txt
words = split.split(txt)
for word in words:
    print word
}}

を実行すると、

#pre{{
オリジナルのソースは、原書著者TobesのページからPCI_Code.zipと してダウンロードできます。

オリジナル
ソース
原書
著者
Tobes
ページ
PCI
_
Code
.
zip
する
ダウンロード
できる
}}
と出力されます。

chasenと比べると英語の文字も正しく処理されること、「から」が名詞ではなく正しく助詞?
として認識されています。

** コメント [#tbf261fc]
この記事は、

#vote(おもしろかった,そうでもない,わかりずらい)

皆様のご意見、ご希望をお待ちしております。

#comment_kcaptcha

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
SmartDoc