astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

英文の自然言語処理におススメ!お手軽なPolyglotを使ってみた。

f:id:astamuse:20170719113042j:plain

こんにちは。白木(@YojiShiraki)です。デザイナーです。
今日はPythonで英文形態素解析をする上でお手軽便利なpolyglotについて紹介します。

背景

当社ではデータを分析・解析する機会がままありまして、こうしたときに自然言語解析の処理のツールを利用しています。特に最近では英語データが多く、このあたりのツールのニーズが高くなっています。

しかし、いざ英語の解析となると意外に情報がありません

例えば、日本語の解析ならMeCabChaSenKuromojiといったものはすぐ見つかります。しかし英文の自然言語解析ではTreeTaggerの情報は目につくもののイマイチまとまった情報がありません(このページこのページに他の選択肢がまとまっていますが)。

おそらくこの領域ではNLTKが王道なのかと思いますが、やや重厚感あります。

そこでもう少しライトなものをということでPolyglot*1をご案内します。

Polyglotとは?その特徴

Polyglotは様々な機能を持つPythonの自然言語解析モジュールです。対応している自然言語も幅広くインストールも非常に簡単です。サンプル実装のドキュメントも一通りそろっており、ちょっと真似すれば簡単に自然言語解析ができます。

まずはざっと特徴を見てみましょう(公式ままです)。

機能 機能(英語) 対応言語
分かち書き(トークン化) Tokenization 165 言語
言語判定 Language detection 196 言語
固有表現抽出 Named Entity Recognition 40 言語
品詞タグ付け Part of Speech Tagging 16 言語
センチメント分析・感情分析 Sentiment Analysis 136 言語
分散表現 Word Embeddings 137 言語
形態素解析 Morphological analysis 135 言語
翻字 Transliteration 69 言語

分かち書きの165言語対応もさることながら、言語判定196言語というのが凄まじいです。この辺りは後ほど一つずつ見ていきます。

またコマンドラインから直接叩けるのも魅力的です。例えば言語判定の機能をコマンドから呼ぶときは

polyglot detect --input testdata/cricket.txt

というコマンドによって、testdata/cricket.txtに記載されている言語の判定を行ってくれます。

ライセンス

PolyglotはGPLv3 licenseにて公開されています(2017年7月18日現在)。一般的なOSSのライセンスですね。商用利用可能です。

インストール方法

では早速インストールしてみましょう。 今回の開発環境は以下の通りです。

  • Ubuntu 14.04 @GCP
  • Python 3.4.3

なお、Polyglotは Python >=2.7 もしくは Python >=3.4. をサポートしています。

パッケージ・モジュールのインストール

ざっと以下のパッケージやモジュール等をインストールします。

公式ドキュメントにはnumpylibicu-devが必要とのことですが、それだけでは足りませんでした。経験的には以下のようにインストール進めれば問題ないと思います。

$ sudo apt-get update
$ sudo apt-get install libicu-dev
$ sudo apt-get install python3-pip
$ sudo -H pip3 install --upgrade pip
$ sudo -H pip3 install numpy
$ sudo -H pip3 install polyglot
$ sudo -H pip3 install pyicu
$ sudo -H pip3 install pycld2
$ sudo -H pip3 install morfessor

モデルのインストール

Polyglotは使う機能と対象とする自然言語に応じてモデルをダウンロードする必要があります。例えば英文に対して品詞抽出する場合は以下のようにembeddings2.enpos2.enをインストールします。

# 英語の品詞抽出用のモデルをDL
$ polyglot download embeddings2.en pos2.en

どの処理に対してどのモジュールをインストールすべきかは、エラーメッセージに書いてくれるのでそちらを参考にするのがよいです。例えば以下のようなエラーです。

ValueError: This resource is available in the index but not downloaded, yet. Try to run
polyglot download embeddings2.fr    # -> フランス語のモデルをダウンロードするように言われている

では引き続き個別の実装についてみていきます。

実装:言語判定

まずは言語判定からいきましょう。言語判定はモデルのダウロード不要です。インストールしたら即使えます。 ここでは試しにフランス語を判定させます。

# -*- coding:utf-8 -*-

from polyglot.detect import Detector

t = "Hé ! bonjour, Monsieur du Corbeau.Que vous êtes joli ! Que vous me semblez beau !"
detector = Detector(t)
print(detector)

結果はこちら。

Prediction is reliable: True
Language 1: name: French      code: fr       confidence:  98.0 read bytes:   811
Language 2: name: un          code: un       confidence:   0.0 read bytes:     0
Language 3: name: un          code: un       confidence:   0.0 read bytes:     0

フランス語が信頼度98.0で返ってきます。

特定の値だけ抽出したい場合は以下のように書きます。

print(detector.language.name)       # -> French
print(detector.language.code)       # -> fr
print(detector.language.confidence) # -> 98.0
print(detector.language.read_bytes) # -> 811

またdetecotr.languagesがイテレーターとなっているので

for lang in detector.languages:
    print(lang.name)

といった使い方もできます。

実装:分かち書き、品詞タグ付け

続いて分かち書きと品詞タグ付けです。先ほどのフランス語を対象にやってみます。 が、その前にフランス語を分かち書きするためにモデルをダウンロードします。

$ polyglot download embeddings2.fr pos2.fr

そのうえで、下記のコードを実行してみてください。

# -*- coding:utf-8 -*-

from polyglot.text import Text

t = "Hé ! bonjour, Monsieur du Corbeau.Que vous êtes joli ! Que vous me semblez beau !"
tokens = Text(t)
print(tokens.words)

結果としては

['Hé', '!', 'bonjour', ',', 'Monsieur', 'du', 'Corbeau.Que', 'vous', 'êtes', 'joli', '!', 'Que', 'vous', 'me', 'semblez', 'beau', '!']

が返ってきており分かち書きされていることが確認できます。 なお「なぜフランス語?」というツッコミは無しでお願いします(気づいたらそうなってただけです)。

引き続き品詞タグ付けします。

# -*- coding:utf-8 -*-

from polyglot.text import Text

t = "Hé ! bonjour, Monsieur du Corbeau.Que vous êtes joli ! Que vous me semblez beau !"
tokens = Text(t)
for token in tokens.pos_tags:
    print(token)

おそらくこのような結果が返ってきたかと思います。

('Hé', 'PROPN')
('!', 'PUNCT')
('bonjour', 'PROPN')
(',', 'PUNCT')
('Monsieur', 'PROPN')
('du', 'DET')
('Corbeau.Que', 'PUNCT')
('vous', 'PRON')
('êtes', 'VERB')
('joli', 'ADJ')
('!', 'PUNCT')
('Que', 'PRON')
('vous', 'PRON')
('me', 'PRON')
('semblez', 'VERB')
('beau', 'ADJ')
('!', 'PUNCT')

よさそうです。 単語と品詞を別々に取り出すにはこんな感じです。

# -*- coding:utf-8 -*-

from polyglot.text import Text

t = "Hé ! bonjour, Monsieur du Corbeau.Que vous êtes joli ! Que vous me semblez beau !"
tokens = Text(t)
for token in tokens.pos_tags:
    print("{0:20s}{1}".format(token[0], token[1]))

結果はこちら。

Hé                  PROPN
!                   PUNCT
bonjour             PROPN
,                   PUNCT
Monsieur            PROPN
du                  DET
Corbeau.Que         PUNCT
vous                PRON
êtes                VERB
joli                ADJ
!                   PUNCT
Que                 PRON
vous                PRON
me                  PRON
semblez             VERB
beau                ADJ
!                   PUNCT

ちなみに、分かち書きの際に言語判定も行っているのでこんな使い方もできます。

# -*- coding:utf-8 -*-

from polyglot.text import Text

t = "Hé ! bonjour, Monsieur du Corbeau.Que vous êtes joli ! Que vous me semblez beau !"
tokens = Text(t)
print(tokens.language)            # name: French   code: fr confidence:  98.0 read...
print(tokens.language.name)       # -> French
print(tokens.language.code)       # -> fr
print(tokens.language.confidence) # -> 98.0
print(tokens.language.read_bytes) # -> 811

実装:固有表現抽出

文章の中から固有表現の抽出を行います。これも実装は今までと大きく変わりません。 まずはモデルのダウンロード。今回は英文を対象に行うので英語用のモデルです。

$ polyglot download ner2.en

コードはこちら。文章はWikipediaの記事を一部利用しています(ref. New York)。

# -*- coding:utf-8 -*-

from polyglot.text import Text

t = ("New York is a state in the northeastern United States. "
     "New York is bordered by New Jersey and Pennsylvania to the south and Connecticut, Massachusetts, and Vermont to the east. "
     "The state has a maritime border in the Atlantic Ocean with Rhode Island, east of Long Island, "
     "as well as an international border with the Canadian provinces of Quebec to the north and Ontario to the northwest. "
     "New York was one of the original Thirteen Colonies that formed the United States. "
     "The state of New York, with an estimated 19.8 million residents in 2015,[9] is also referred to as New York State to distinguish it from New York City, "
     "the state's most populous city and its economic hub.")

tokens = Text(t)
for entity in tokens.entities:
    print(entity.tag, entity)

結果。

I-LOC ['York']
I-LOC ['United', 'States', '.', 'New', 'York']
I-LOC ['New', 'Jersey']
I-LOC ['Pennsylvania']
I-LOC ['Connecticut', ',', 'Massachusetts']
I-LOC ['Vermont']
I-LOC ['Rhode']
I-LOC ['Long']
I-LOC ['Canadian']
I-LOC ['Quebec']
I-LOC ['Ontario']
I-LOC ['.', 'New', 'York']
I-LOC ['United', 'States']
I-LOC ['New', 'York']
I-LOC ['New']
I-ORG ['New', 'York']
I-LOC ['New', 'York', 'State']
I-LOC ['New', 'York', 'City']

I-LOCと出ているのは場所の固有表現を表しています。ソースを見るとI-LOC以外にも組織を表すI-ORGや人物名を表すI-PERがあります。

その他

その他にも幾つか機能があります。特に面白いのは「センチメント分析・感情分析」と「分散表現」あたりですが、今回は時間の都合上割愛させてください(ソース読みきれませんでした・・)。後日、余力に応じて本稿に書き足します。

終わりに

いかがだったでしょうか、英文に限らず複数言語の自然言語に対応したPolyglot。

実は今回はgensimを使った英文のトピックモデルの実装(といってもコピペレベルですが)について書こうと思っていました。しかし英文自然言語解析の処理を書いてる時に「ライトで使いやすい自然言語解析ツール」の情報(日本語)が意外になく、「これ困っている人いるんじゃないか?」と思いテーマを変更したという経緯があります。

そういう意味では、この投稿をみて助かってくれる人が出てきたらいいな、と思います。そして英文の自然言語解析の世界が少しでも身近に感じてもらえれば嬉しいです。

なお、gensimからのLDAネタは今行っている実験うまくいったら書きます(フラグ)。

では、本日も最後までお読みいただきありがとうございました。

例によって当社では一緒に開発してくれるメンバーを募集しております。カジュアル面談も随時行っておりますので、「ちょっと話聞きたい」という方は、このブログのサイドバー下にあるアドレスか@YojiShirakiあたりにDMいただければと思います。

*1:Polyglotというと多言語プログラミング的なイメージが強いかもしれませんが、それとは別です。

そろそろネタがないのでテストに関しての雑談です

どうもえいやです。

最近の業務ではオンプレサーバからのGCP移行とか、負荷試験の対応とか、JVMのチューニングとか、観葉植物の手入れとか色々あるんですが、その辺は当たり前にやることをやってるだけで、ネタにできるほどのことも、書く時間もないので、今回はとてもいい加減な感じでテストの話をしようと思います。

雑談とか、日記とかポエムとかそういう類のものです。コード例もありません。内容の推敲も、事実の確認もないです。

普段ふわっと思ってることを書きます。

「テストは重要」と分かっている人は、それ以上の内容はないので読む必要はありません。最後の1行まで飛ばしてください。

以下、いつもの通りですが、なにもかもがいい加減なので、可能な限りスルーしてください。

さて、「テストを書きましょう」と、プロジェクトで話が出るとき、一体いつのフェーズからそれを言い出して、書き始めるのはいつなのか。また、言い出した理由はなんでしょうか。

もちろん、プロジェクト、チームによって違います。

弊社で僕が担当しているプロジェクト(のサーバサイド限定)で言えば、まず言い出す時期について、多くの場合かなり遅めの段階で出ます。

モノが出来上がって、リリースして、稼働して、バグがちらほら出始めてから、くらいですかね。言い始めるのは僕で、言わないと永遠にテストが書かれることはないでしょう。言っても書かれるとは限らないけど。

ただし、その時点までにテストが全くないわけではなく、実装者が不安を感じるシーンではテストが書かれている部分もあります。その前提として、プロジェクトのコードが書かれ始める前に、テストフレームワークの選定や、多少個々人の趣味によりますが、テストの手法の検討も大体済んでいます(いるよね?)。

テストの話をすると、かなりガミガミ言ってくる人も多いので、TDDでやらなきゃとかテストファースト当然とか思う人も多いと思います。それらの手法にメリットがあることも事実で、デメリットなどない、と豪語する人もいるでしょう。

では、「テストを書きましょう」と本格的な指示が出るのが遅いことを以て、このプロジェクトはダメなプロジェクトでしょうか。

そのこと判断するまえに、「テストを書きましょう」と言い出す理由について考えてみましょう。

もちろん、限られたリソースを割いて「テストを書きましょう」というからには、テストの効果に期待しているわけです。

テストの効果は一般的に言われていることでは、1)「バグを検出し、品質を高める」ということが主なところでしょう。テストを実行可能なコードとしておくことで、変更都度の確認も楽にできます。

さらに、BDD形式のテストコードについてよく言われることでですが、2)「仕様のコード化」という効果もあります。仕様書やコメントは簡単に嘘をつきますが、実行可能な形式のテストコードは、少なくとも動作については嘘をつきません。

それに加えて、これは一般的にどう言われているのかわかりませんが、個人的には実装者に対しての3)「実装コードへの理解度を高める」学習効果もテストを書く上での重要な効果だと考えています。

この学習効果には、実装者が頭の中やサンドボックス、実コードへの試しの実装など、実装の途中で大体行っているような「一旦書いてみる」コードの正確度を高め。試行錯誤の回数を減らし、ひいては生産性を向上させる効果があります。

また、学習効果は品質にも影響があると想定されますが、学習進度が高い実装者であってもバグを組み込むことが往々にして存在するという経験則から、学習効果と品質の相関はこの際無視します。

学習効果の性質として、学習効果による生産性の向上は、あるプロジェクトの中で必要十分となる内容に限定すると、一定で頭打ちになります。

翻って、上述のテストの時期が遅いプロジェクトにおいて、1~3の効果がどれほど期待できるのかについて考えることで「テストを書きましょう」の指示が遅すぎるのかを判断してみましょう。

情報の後出しになりますが、このプロジェクトの性質として、次のようなことが言えます。

  • 品質と密接な関係があるプログラムの複雑度について、初期リリース時点では可能な限り低く抑えた設計を行っている。仕様が複雑であっても、サーバサイドのプログラムの複雑度に寄与しない。
  • リリース初期段階では、仮に停止していたとしても、売り上げ的な意味での機会損失につながらず、利用者もほとんどいない非クリティカルなサービス。かつ、全て自社サービス。
  • 仕様について、リリース後に見直されることがなく消失したり、同じ名前で呼ぶ全く違う存在になったりすることがほとんど。
  • 十分に学習済みのフレームワークを用いて、学習済みの手法を用いて、学習済みのチームメンバーのみで初期リリースまで行う。

以上の点で、

  • 1)について、高品質がまるで求められてない。
  • 2)について、リリース初期段階の仕様を見直すことはほどんどない。
  • 3)について、メンバーの学習進度は頭打ちになっているため、テストコードによる学習が生産性の向上につながりにくい。

のがプロジェクトの初期の段階です。なので、この段階でリソースを割いてテストを積極的に記述しようという号令をしたところで効果が低いのです。こういうプロジェクト、わりとどこにでもあるんじゃないでしょうか。

もちろん、利用者が増えることでプロジェクトが長期化したり仕様が安定化してきたりしてきて、コードに手を入れる必要が出てきたりすれば、要所から順にテストが導入されていきます(理想的には)。

利用者が存在しない限りバグが見つかることはほぼないので、前述の「バグがちらほら」がその合図だったりします。また、この時点以降でテストの保証するコードの範囲がある一定を下回ると、プロジェクトは紛れもなくダメになります(現に下回ってしまうことも常態化しているんだけど)。

以上の点を踏まえて、このプロジェクトはダメなプロジェクトでしょうか。ということを判断すると、たぶん「どちらとも言えない」か「どちらとも言える」ということだと思います。

個人的には、後からテストによって保証されたであろう品質や仕様のコード化がリカバリされる仕組みがない限りはダメだろうなぁと思っています。

ダメじゃない、と言いそうな感じで話を進めてきてなんですが、まぁダメですね。

単純にリソースの増加と無駄なリソースの投資を削減することなどが必要なんですが、まともなやる気に溢れるテストエンジニアかクオリティエンジニアの出現が求められます。

そういうわけで、プロジェクト進行と品質設計がちゃんとできるエンジニアを募集しています。

astamuse.comのcssが崩壊した日(2017/07/14改訂)

2017/07/14更新

主に「抽象的な」と言っている箇所の削除・修正を行いました。

前々回くらいに「cssアーキテクチャのtips」とか偉そうなブログ書いた者ですが、 今回自分のcssを崩壊させてしまいました。まったく笑えない、由々しき事態です。

失敗事例をこういうとこで書くべきなのか悩みましたが、反省と自責の意味を込めて書かせていただきます。

astamuse.comのcssアーキテクチャ

2013年に大幅リニューアルしたastamuse.comのcssアーキテクチャは6つの層で成り立っています。

f:id:astamuse:20170704201421p:plain

※この「widgets」という層ですが、atomicデザインでいう「modules」のようなもので、オレオレ概念です。こいつが後々首絞めます。

例としてデザインを見ていきます。

f:id:astamuse:20170704200020p:plain

このデザインをastamuse.comのcssアーキテクチャで分解していくと、下記のようになります。

f:id:astamuse:20170704200023p:plain

componentsのラベル・ボタン・widgetsの見出し・リストらを、modulesで実装してます。

何ら違和感はないように思えますよね。

少なくとも、このcssアーキテクチャで2013年~2017年まで維持できたという点では「間違いではなかった」はずです。

何が起こったか

本年度より、徐々にastamuse.comのモバイル対応を行っております。

【注釈】astamuse.comの「モバイル対応」方針について

astamuse.comはAsta4Dを使っており、特定のUIをモバイル用UIでオーバーライドすることも容易にできますので、モバイル用cssで「モバイル対応」に取り組んでいます。

.wdg-list-vline は横並びli間に「|」を装飾するwidgets。 f:id:astamuse:20170704200023p:plain

だがしかし!

f:id:astamuse:20170704200025p:plain

モバイルだと上記のようなデザインになり、「vline」という単語が意味不明になってしまいました。utilitiesも同じような事態(.line-bottom, .al-center, etc.. )に・・・。

最悪です。抽象的な概念を取り入れすぎた結果がこれです。

[改訂]「構造と見た目の分離」というcssの基本を軽視した結果がこれです。

反省と今後に向けて

今回反省すべきは

  • astamuse.comプロジェクト(サイトデザイン・制作メンバー含め)に適したアーキテクチャではなく、自分が好きなアーキテクチャを選択してしまったこと
  • 抽象的なclass名をhtmlに書きすぎたこと
  • [改訂] 「構造と見た目の分離」を軽視したこと

の2点です。

このアーキテクチャは、widjets,modulesによって新規・追加コンテンツを作るスピードは確かに上がるのですが、

[改訂]この方法は直感的にwidjets,modulesを組み合わせていくことができるので、新規・追加コンテンツを作るスピードは確かに上がるのですが、

中長期で見たときのスピード(削除・リデザイン)を考えると、本プロジェクトには向いてませんでした。


今後に向けてですが、下図のようなアーキテクチャでリデザインしていこうと思います。 各pageの独立性を持たせており、今度のコンテンツ拡充・削除・変更にも耐えていける設計になるはずです。 (Enduring CSSに近しい思想があるかもしれません。)

f:id:astamuse:20170704213009p:plain

完了時期がいつになるかまだスケジュールをたててませんが、近いうちにまたここで発表できればなと思います。

最後になりますが、astamuse.comの大規模リファクタリングを一緒にやっていただける方や、私のcssうんちく話を聞いてくれる方を切に、切にお待ちしております。

Copyright © astamuse company, ltd. all rights reserved.