導入
PHPで自然言語処理を行う際、igo-phpのような形態素解析エンジンは非常に強力なツールです。しかし、デフォルトの設定で解析を行うと、「形態素解析」といった複合名詞が「形態素」と「解析」に分断されてしまうことがよくあります。検索エンジンの最適化や文章の要約、重要キーワードの抽出を行う現場において、この「分断」は精度を大きく下げる原因となります。今回は、連続する名詞を一つの「複合名詞」として正しく結合するための実装テクニックを解説します。
基礎知識
形態素解析とは、文章を文法的に最小単位(形態素)に分割し、それぞれの品詞を判別するプロセスです。igo-phpなどのエンジンは、辞書データに基づいて「これは」「形態素」「解析」のように分割します。今回の課題である「複合名詞」とは、複数の名詞が連続して一つの単語として機能する状態(例:「実験」+「結果」=「実験結果」)を指します。これをプログラムで解決するには、解析結果をループ処理する際に「直前の品詞が名詞だったか」という状態を保持するロジックが必要です。
実装/解決策
解決策はシンプルです。解析結果を順番に走査し、現在の単語が「名詞」であれば変数に連結して保持し続けます。名詞以外の品詞が現れた瞬間に、溜めていた名詞を確定させ、結果リストに追加します。この処理を挟むことで、形態素解析エンジンが個別に分割した単語を、文脈に合わせて再構築することが可能になります。
サンプルプログラム
以下のコードは、igo-phpを使用して名詞の連続を結合する実用的なサンプルです。
parse($str);
$nounBuffer = “”; // 名詞を一時保存するためのバッファ
$words = array(); // 最終的な単語リスト
foreach($result as $value){
// 形態素の情報をカンマ区切りで取得
$feature = explode(“,”, $value->feature);
// 品詞が「名詞」であるか判定
if($feature[0] === “名詞”){
// 名詞の場合はバッファに追加
$nounBuffer .= $value->surface;
} else {
// 名詞以外が現れた場合、バッファに名詞が溜まっていれば確定させる
if(mb_strlen($nounBuffer) > 0) {
$words[] = $nounBuffer;
$nounBuffer = “”; // バッファをリセット
}
// 現在の単語(名詞以外)を追加
$words[] = $value->surface;
}
}
// 最後に名詞がバッファに残っている場合の処理
if(mb_strlen($nounBuffer) > 0) {
$words[] = $nounBuffer;
}
// 結果の出力
print_r($words);
?>
応用・注意点
この手法を用いる上で注意すべき点は、「すべての連続名詞を結合すべきか」という判断です。例えば、「東京特許許可局」は一つにまとめるべきですが、文脈によっては「東京」と「特許許可局」に分けたほうが良いケースもあります。また、辞書の精度やバージョンによって品詞の定義が異なる場合があるため、本番環境に投入する前に、対象とする辞書(ipadicなど)の品詞体系を必ず確認してください。さらに、大規模なテキストを処理する場合は、メモリ消費を抑えるためにジェネレータを用いた処理を検討するなど、パフォーマンス面での最適化もあわせて行うことを推奨します。