1. 導入:なぜ複合名詞の結合が必要なのか
PHPで自然言語処理を行う際、形態素解析ライブラリ(igo-phpなど)を利用することは一般的です。しかし、標準的な解析では「形態素解析」という単語が「形態素」と「解析」に分割されてしまいます。実務において検索エンジンの精度向上や要約ツールを開発する場合、このような分割はノイズとなります。本記事では、連続する名詞を結合し、人間にとって自然な「複合名詞」として扱うための実装手法を解説します。
2. 基礎知識:形態素解析と複合名詞
形態素解析とは、文章を文法的な最小単位(形態素)に分解する処理です。多くのエンジンは辞書に基づき最も確率の高い分割を行いますが、日本語特有の「漢字が並ぶ名詞」については、文脈次第で一塊として扱うべきケースが多々あります。
複合名詞とは、「実験」+「結果」=「実験結果」のように、複数の名詞が合わさって一つの意味を成す言葉のことです。プログラム上でこれを実現するには、解析結果の品詞タグを判定し、名詞が連続している間は文字列を連結し続けるというロジックが必要になります。
3. 実装/解決策
実装の基本方針は「状態保持」です。
1. 解析結果をループで回す。
2. 品詞が「名詞」であれば、一時変数に蓄積する。
3. 名詞以外の品詞が出現したタイミングで、蓄積していた名詞を確定させ、結果配列に格納する。
このシンプルなアルゴリズムにより、辞書に載っていない専門用語の組み合わせであっても、動的に一つの単語として抽出することが可能になります。
4. サンプルプログラム
以下は、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)) {
$words[] = $nounBuffer;
$nounBuffer = “”; // バッファをリセット
}
// 現在の単語(助詞や動詞など)を追加
$words[] = $value->surface;
}
}
// ループ終了後にバッファに残っている名詞があれば追加
if(mb_strlen($nounBuffer)) {
$words[] = $nounBuffer;
}
// 結果の確認
print_r($words);
?>
5. 応用・注意点
現場での実装においては、以下の点に注意してください。
細分化の制御
全ての連続名詞を結合すると、逆に意味が広がりすぎて検索精度が落ちる場合があります(例:「PHPの学習」と「PHP学習」を区別したい場合など)。品詞の細分類(「名詞,固有名詞」のみ結合するなど)を条件に加えることで、より精度を高めることができます。
メモリ管理
大量のテキストを一度に解析する場合、ループ内での文字列結合処理がメモリを消費します。mb_strlenなどのマルチバイト関数は負荷が高いため、大規模なバッチ処理を行う際は、イテレータパターンを活用するなどしてメモリ効率を最適化してください。
辞書の限界
複合名詞の結合はあくまで形態素解析の「後処理」です。辞書に存在しない未知語が多い場合は、形態素解析自体の辞書メンテナンスを優先することを推奨します。