解析エンジニアの自動化 blog

コツコツと自動化した方法を残す blog

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 から実行します。

図1 python コマンド実行方法

テストソースコード


#-*- 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()

エラーコード

テストソースコードを実行すると、コーデックエラーとなり、以下の様なエラーメッセージが表示されました。

〜 'utf-8' codec can't decode 〜



エラー回避

参考サイトによる 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 



結果

テストソースコード

図2 テストソースコード①結果


テストソースコード

図3 テストソースコード②結果


図3 は等幅フォントではないため、罫線がズレて表示されていて、よく分からないので、テキストエディタにコピペして、ツリー構造がハッキリ分かる画像を4 に示します。


テストソースコード

図4 テストソースコード②結果



コメント

Windows でも python を使い倒すことに貢献できたら幸いです。

長くなったので、感情分析はまた、別の記事にします。



以上