言語処理するのにPythonでいいの?
PyData.Tokyoオーガナイザーの池内(@iktakahiro)です。
自然言語処理のツールとしてPythonを用いる場合、どのような方法があるでしょうか。単純な形態素解析であれば、mebabのPythonバインディングが利用できます。トークナイズやステミングなど、さまざまな自然言語処理を行えるNLTK(Natural Language Toolkit)や、トピックモデルを扱えるgensimがしばしば用いられます。
上に挙げたように、Pythonには自然言語処理を行うためのパッケージがいくつか用意されており、解決したい問題にこれらのパッケージが適応できないかを検討するのが妥当と考えられます。しかし、今回の講演タイトルにある通り、「そもそもPythonでよいのか」ということを検討することも必要でしょう。
2つ目の講演はサイボウズ・ラボ株式会社の中谷秀洋(@shuyo)さんによる「言語処理するのにPythonでいいの?」です。
中谷さんは、有名な言語判定のJavaライブラリlanguage-detectionの作者であり、技術評論社の連載記事「機械学習 はじめよう」や書籍『PRMLガール―文芸部のマネージャーが「パターン認識と機械学習」を読んだら』の執筆など、幅広く活躍されているデータ分析エキスパートです。
今回の講演は、複数のプログラミング言語で自然言語処理の実装を行った中谷さんならではの示唆に富んだ内容となりました。
動いてはじめて価値がある
PythonコミュニティであるPyData.Tokyoとしては「言語処理するのにPythonでいいの?」というタイトルへの答えが非常に気になるところでしたが、スライドの最後に「安心してPythonを選ぼう」という言葉が登場し、運営一同も一安心(?)でした。
しかし、中谷さんの主張はあくまで「動くことが重要」であり、Java、C++、Pythonなどの中から、プログラミング言語の特性や、自分が十分に扱えるかといったことを考慮した上で言語の選択をすればよいというものでした。
また、「何を目的としているか」や「環境要件」が言語選択の大きな理由になるという説明もありました。素早くプロトタイピングをつくりたい場合はRubyやPython、速度を求める場合はC++ を選択する、というのが目的に応じた言語選択と言えます。環境や外部要因が言語を決定する要因となることは一般的な開発プロジェクトでもままあることですが、Apache Solrに組み込みたかったためにlanguage-detectをJavaで実装したという中谷さんのエピソードは言語選択の成功例として興味深いものでした。
各言語のメリット・デメリット/Python編
自然言語処理の実装という観点から、選択の手助けとなりうる各言語の特徴をみていきます。
Pythonのメリット
- 実行の容易性や可読性
- エラー内容が分かりやすい
- ライブラリが豊富
Pythonのデメリット
- 実行速度が遅い
Pythonのデメリットを補うための選択肢として、ボトルネックとなり得る部分を多言語で実装する、CythonやNumba、pypyを用いた高速化プラクティスを導入する、などがあります。
>>> def content_fraction(text): ... stopwords = nltk.corpus.stopwords.words('english') ... content = [w for w in text if w.lower() not in stopwords] ... return len(content) / len(text)
主旨とは少しそれますが、これまでの連載では、C言語で実装したモジュールをPythonから利用する方法は解説してこなかったので、今回簡単な例を記載します。『どこまで速くできる? 達人に学ぶPython超高速データ分析~PyData.Tokyo Meetup #4イベントレポート』でも登場した単純なCのコードを少し変更したものをPythonから実行します。
PythonからC言語のモジュールを呼び出す方法はいくつか存在します。今回はctypesを利用します。
C言語で実行するモジュール「my_calc.c」のコードは下記のとおりです。
int calc() { int i; double s=0; for (i=1; i<=100000000; i++) s+=i; return i; }
my_calc.c をコンパイルします。
gcc -c my_mod.c gcc -shared -o my_mod.dll my_mod.o;
Pythonのコードは下記のとおりです。
>>> from ctypes import CDLL >>> my_mod = CDLL('./my_mod.dll') >>> my_mod.calc() 100000001
このコードは、おおむね200msで実行されることから、C言語で実装した恩恵が受けられていると言えます。
CythonやNumbaを利用した高速化については『どこまで速くできる? 達人に学ぶPython超高速データ分析~PyData.Tokyo Meetup #4イベントレポート』で詳しく解説しているので参照してください。
ライブラリの種類については冒頭で紹介した通りです。ごく最近のトピックとして、Pure Pythonで実装された形態素解析器(Janome)が公開されています。
各言語のメリット・デメリット/C++編
C++のメリット
- 実行速度が速い
- メモリ効率がよく大規模データを取り扱える
C++のデメリット
- メリットはあくまでしっかりした実装ができる場合に限って有効であること
中谷さんは、Twitterのようなショートテキストでの言語判定を想定して実装されたライブラリ ldigのプロトタイピングにおいて、ベースをPythonで実装し、処理性能が重要になる素性(feature)の抽出部分をC++ライブラリに委ねるという方法を採りました。前述のPythonの弱みをC++の強みで補う解決方法です。
メリット・デメリットともにデータ処理全般における話題ではありますが、総当たりや組み合わせの計算を行うこともある自然言語処理において、実行速度やメモリ効率の重要度は高いと言えます。
C++の自然言語処理関連ライブラリの一つにFreeLingがあります。自然言語処理に限らず、Octaveのような数値計算用のライブラリは実装の手助けになるでしょう。機械学習全般の領域では Vowpal Wabbitが注目を集めています。
各言語のメリット・デメリット/Java編
Javaのメリット
- Java自体の経験者が多い
- Apache Solrに組み込める、Apache Hadoopを活用した実装が行いやすい
Javaのデメリット
- コードが冗長になりやすい
Javaの最大のメリットは、全文検索エンジンのApache Solrや分散処理フレームワークApache Hadoopなどの既存のプロダクトを利用しやすい点と言えます。中谷さんがApache Solrに組み込むためにJavaを選択したのは前述のとおりです(中谷さんはメリットというよりも「環境要件」であると表現しています)。
Javaの自然言語処理関連ライブラリとしてはOpenNLPやWekaが著名です。
まとめ/言語選択時に考慮すること
ここまでで、Python、C++、Javaの3つの言語の、自然言語処理実装視点でのメリット・デメリットを見てきました。まとめると、言語を選択する際は下記のように考えるとよいでしょう。
- 環境要件がある場合は、環境を優先し言語を選択する
- プロトタイピングや試行錯誤しながらコードを頻繁に書き換える場合は、コーディング速度を保てるPythonなどを選択する
- 大規模データを扱う、処理性能が重要になる場合は、C++などを選択する
ただし、重要な点として、プログラミング言語の学習コストは無視できないということです。各々にメリット・デメリットがあるからといって、いくつもの言語を学習する時間が確保できるとは限りません。冒頭で述べたように、動作することこそが重要であるため、すでに習熟度の高い言語や、学びやすいとされている言語を選択することの重要性も念頭に置いておくと良いでしょう。学びやすい言語の一つとして、Pythonという選択肢はお薦めできるものです。