Windows で JUMAN と KNP と pyknp を使う
こんにちは。
仕事の自動化にやりがいと達成感を感じるガッくんです。
この記事の目次
背景・目的
自然言語処理で感情分析やりたいと思っています。
感情分析の前処理として、ちょっと調べてみると、
JUMAN という形態素解析器
KNP という構文解析器
pyknp という Python バインディング
を使うのが良さそうでした。
しかし、 Windows 、 python3 という組み合わせでは JUMAN/KNP が shift-jis で python3 が utf-8 なので、 コーデックエラーが出ます。
このエラー回避にかなりハマったので、とりあえず、インストールして、形態素解析までたどり着いた方法をまとめます。
動作環境
・Windows 7
・winpython 64bit 3.7.2.0
・JUMAN 7.0
・KNP 4.11
・pyknp 0.22
事前に winpython はインストールされていることを前提とします。
winpython のインストールディレクトリは下記とします。
インストールディレクトリ:C:\WPy64-3720
プログラム
インストール
インストールについては以下のサイトを参考にしました。Windows 7 64bit に JUMAN/KNP(構文解析器)を導入しました - Qiita
リンクのサイト通りにやると特になんの問題も無く下記がインストール出来ました。
• KNP Ver.4.11 (Windows 64bit版)
• Juman Ver 7.0 (Windows 64bit版)
• pyknp(pyknp-0.22.tar.gz)
なお、 KNP と Juman のインストールフォルダは全てデフォルトにしています。
この後、エラー回避で対象となるフォルダ、ファイルを示していますが、デフォルトインストールした場合のフォルダ、ファイルになりますので、ご了承下さい。
【参考サイトの補足】
python コマンドは WinPython Command Prompt から実行します。
テストソースコード①
#-*- encoding: utf-8 -*-
from pyknp import Juman
juman = Juman(jumanpp=False)
result = juman.analysis("最近、痛ましい事件や事故のニュースが多い。")
for mrph in result.mrph_list():
print (mrph.midasi)
テストソースコード②
# -*- coding: utf-8 -*-
import pyknp
knp = pyknp.KNP()
line = '最近、痛ましい事件や事故のニュースが多い。'
result = knp.parse(line)
result.draw_tag_tree()
エラーコード
テストソースコードを実行すると、コーデックエラーとなり、以下の様なエラーメッセージが表示されました。
エラー回避
参考サイトによる pyknp のエラー回避
インターネットに参考になるサイトがありました。サイトの内容とエラーが合っているので、やってみました。
PyKNPをWindows10にインストールする(お土産付き) - Qiita
ディレクトリ:C:\Program Files\pyknp\pyknp-0.22.tar\dist\pyknp-0.22\pyknp-0.22\pyknp\juman
ファイル:juman.py
52行目
変更前
self.process = subprocess.Popen('bash -c "%s"' % command, env=env,
変更後
self.process = subprocess.Popen('"%s"' % command, env=env,
ディレクトリ:C:\Program Files\pyknp\pyknp-0.22.tar\dist\pyknp-0.22\pyknp-0.22\pyknp\juman
ファイル:juman.py
66行目
変更前
def query(self, sentence, pattern):
assert(isinstance(sentence, six.text_type))
self.process.stdin.write(sentence.encode('utf-8')+six.b('\n'))
self.process.stdin.flush()
result = ""
while True:
line = self.stdouterr.readline()[:-1].decode('utf-8')
if re.search(pattern, line):
break
result = "%s%s\n" % (result, line)
return result
変更後
def query(self, sentence, pattern, encoding="ms932"):
assert(isinstance(sentence, six.text_type))
self.process.stdin.write(sentence.encode(encoding)+six.b('\n'))
self.process.stdin.flush()
result = ""
while True:
line = self.stdouterr.readline()[:-1].decode(encoding)
if re.search(pattern, line):
break
result = "%s%s\n" % (result, line)
return result
このエラー回避でエラーメッセージに変化が現れた。
juman が見つからないといったエラーになった。
そして、独自にエラー回避を行った。
独自のエラー回避①
エラーメッセージで knp.py の処理が表示されていた。KNP のコンストラクタで jumanpp を強制的に使用する初期化だった。
jumanpp はそもそもインストールしていないので、コンストラクタを juman を使用する初期化に書き換えた。
ディレクトリ:C:\WPy64-3720\python-3.7.2.amd64\Lib\site-packages\pyknp\knp
ファイル:knp.py
30行目
変更前
def __init__(self, command='knp', server=None, port=31000, timeout=60,
option='-tab', rcfile='', pattern=r'EOS',
jumancommand='jumanpp', jumanrcfile='', jumanpp=True):
self.command = command
self.server = server
self.port = port
self.timeout = timeout
self.option = option.split()
self.rcfile = rcfile
self.pattern = pattern
self.socket = None
self.subprocess = None
self.jumanpp = jumanpp
変更後
def __init__(self, command='knp', server=None, port=31000, timeout=60,
option='-tab', rcfile='', pattern=r'EOS',
jumancommand='jumanpp', jumanrcfile='', jumanpp=False):
self.command = command
self.server = server
self.port = port
self.timeout = timeout
self.option = option.split()
self.rcfile = rcfile
self.pattern = pattern
self.socket = None
self.subprocess = None
self.jumanpp = jumanpp
ここで、またエラーとなった。
コーデックを utf-8 で行う処理が残っていた。
そこで、独自のエラー回避②を行った。
独自のエラー回避②
参考サイトによる pyknp のエラー回避とやっている事は同じです。
ディレクトリ:C:\WPy64-3720\python-3.7.2.amd64\Lib\site-packages\pyknp\juman
ファイル:process.py
64行目
変更前
def query(self, sentence, pattern):
assert(isinstance(sentence, six.text_type))
self.process.stdin.write(sentence.encode('uft-8')+six.b('\n'))
self.process.stdin.flush()
result = ""
while True:
line = self.stdouterr.readline().rstrip().decode('uft-8')
if re.search(pattern, line):
break
result = "%s%s\n" % (result, line)
return result
変更後
def query(self, sentence, pattern, encoding="ms932"):
assert(isinstance(sentence, six.text_type))
self.process.stdin.write(sentence.encode(encoding)+six.b('\n'))
self.process.stdin.flush()
result = ""
while True:
line = self.stdouterr.readline().rstrip().decode(encoding)
if re.search(pattern, line):
break
result = "%s%s\n" % (result, line)
return result
結果
テストソースコード①
テストソースコード②
図3 は等幅フォントではないため、罫線がズレて表示されていて、よく分からないので、テキストエディタにコピペして、ツリー構造がハッキリ分かる画像を4 に示します。
テストソースコード②
以上