文章を単語に解析して数を数えるのは簡単そうに思えますが、日本語には助詞や助動詞、複合語など特有の言語構造のため、どこからどこまでが単語なのかを分割するのが困難です。
この記事では、「Kuromoji」という JavaScriptライブラリを使用した【形態素解析】という技術を用いて日本語の文章を単語単位に解析し、特定の単語を抽出、集計する方法をサンプルコードを用いて紹介します。
※Kuromojiは、商用利用や再配布、改変が許可された「Apache License 2.0」ライセンスとなっており、ユーザ辞書を追加することで特定の分野に特化した解析ができるようになります。
【形態素解析】とは
自然言語処理において、文章を構成する最小単位である形態素に分解し、それぞれの形態素の品詞や意味を解析する技術です。
形態素とは、言語の意味を持つ最小の単位であり、単語や語幹、接辞などが含まれます。
実際に次の文章を例に【形態素解析】してみると下記表のようになります。
「私は、この『スイミー』が好きです。魚の話が面白いからです。」
| 単語 | 品詞 | 品詞細分類1 | 品詞細分類2 | 品詞細分類3 | 活用形 | 活用型 |
|---|---|---|---|---|---|---|
| 私 | 名詞 | 代名詞 | 一般 | |||
| は | 助詞 | 係助詞 | ||||
| 、 | 記号 | 読点 | ||||
| この | 連体詞 | |||||
| 『 | 記号 | 括弧開 | ||||
| スイミー | 名詞 | 固有名詞 | 一般 | |||
| 』 | 記号 | 括弧閉 | ||||
| が | 助詞 | 格助詞 | 一般 | |||
| 好き | 名詞 | 形容動詞語幹 | ||||
| です | 助動詞 | 連用形 | デス | |||
| 。 | 記号 | 句点 | ||||
| 魚 | 名詞 | 一般 | ||||
| の | 助詞 | 連体化 | ||||
| 話 | 名詞 | 一般 | ||||
| が | 助詞 | 格助詞 | 一般 | |||
| 面白い | 形容詞 | 自立 | 基本形 | |||
| から | 助詞 | 接続助詞 | ||||
| です | 助動詞 | 連用形 | デス | |||
| 。 | 記号 | 句点 |
解析した結果から特定の単語を抽出するには
解析結果には、上記表のように助詞や句読点などが含まれますので、目的に応じた種類の単語を抽出する必要があります。
たとえば、文章の中でより意味のある単語(キーワード)の使用頻度の集計を目的とした場合、多くの文章に含まれそうな「私」などの代名詞や、「この」「あの」といった連体詞は集計には含めたくないので抽出する単語(キーワード)から下記の品詞を除外するなどの対応が必要になります。
- 代名詞
- 連体詞
サンプルコード
このサンプルは、TypeScriptで「Kuromoji」を使用して【形態素解析】を行い、前述の品詞を除外した上で名詞を抽出し、単語単位にカウントした結果を出力します。
※最終的に名詞を抽出するので、連体詞の除外は不要ではありますが、参考までに記述しています
import * as kuromoji from 'kuromoji';
// 解析対象文章
const texts: string[] = [
'私は、この『スイミー』が好きです。魚の話が面白いからです。',
'その『ぐりとぐら』が好きです。あなたの動物の話が楽しいからです。',
'あの『おおきなかぶ』が好きです。かぶの話がとても面白いからです。'];
let tokenizer: kuromoji.Tokenizer | null = null;
// 必要な辞書を取り込んで初期化
const builder: kuromoji.TokenizerBuilder = kuromoji.builder({
dicPath: 'saved/dictionary'
});
builder.build((err, _tokenizer) => {
if (err) {
console.error(err);
return;
}
tokenizer = _tokenizer;
});
const countMap: { [key: string]: number } = {};
for (const text of texts) {
// 解析
const tokens: kuromoji.IpadicFeatures[] = tokenizer.tokenize(text);
// 対象の品詞を抽出して集計
for (const token of tokens) {
// 連体詞と代名詞を除外
if(token.pos === '連体詞' ||
token.pos === '名詞' && token.pos_detail_1 === '代名詞'){
continue;
}
// 名詞を抽出
if (token.pos === '名詞') {
if (countMap[token.surface_form]) {
countMap[token.surface_form]++;
} else {
countMap[token.surface_form] = 1;
}
}
}
}
// 出力
console.log(countMap);
出力結果(出力結果は抽出数の多い順にソートしています)
{
"好き": 3, ※[品詞]:名詞、[品詞細分類]:形容動詞語幹
"話": 3,
"おおきなかぶ": 1,
"かぶ": 1,
"ぐりとぐら": 1,
"スイミー": 1,
"動物": 1,
"魚": 1
}
エンジンにもよると思いますが、AIで日本語の【形態素解析】をしてみると、同じ文章を指定しても異なる結果となることがあり、日本語の言語構造が複雑であることが分かります。
一方、今回紹介した処理では結果が変わることがないので、抽出条件さえ決めることができればAIよりも高い精度で特定の単語を抽出することができると思います

