第四回 | MeCab

# 目的

今までの記事では、エンティティの感情分析と商品の特徴カテゴリーの提案とカテゴライズの説明を行いました。今回は、商品レビュー分析に先立つ重要な、「カテゴライズする際の前処理」と「商品レビューに頻出する単語の抽出」について説明します。 
* **カテゴライズする際の前処理**  
  主に単語の原型化を行います。原型化とは、言葉の形を基本形に戻すプロセスを指します。これは、活用や派生などによって単語が変形した形を、基本形に戻すことです。例えば、「食べます」「食べた」を「食べる」のように単語の原型に戻します。単語の原型化を行う理由としては単語をカテゴリ分類する際には、全ての単語のパターンを把握することが難しいためです。例えば、「強い」という単語をカテゴリ分類したい場合、「強い」「強く」「強」といった変化形も同じ意味で扱いたいでしょう。しかし、全ての変化形を把握し設定するのは困難です。そのため、単語の原型化を行うことで、カテゴライズするパターンを統一し、簡略化することができます。

<br> 

* **商品レビューに頻出する単語の抽出**  
  頻出する単語の抽出はマーケティング戦略の立案にとても役立ちます。頻出する単語は、顧客の関心やニーズを反映しており、重要な指標となります。具体的な重要性に関しては後ほど説明します。

これらの処理を行うために、MeCabという形態素解析ツールを使用しました。


# MeCabとは
MeCab（めかぶ）は、日本語の形態素解析エンジンです。形態素解析とは、自然言語処理の一環として行われるテキスト解析の手法の一つです。日本語の文章などを構成する単位である「形態素」に分割し、それぞれの形態素の品詞や読みなどの情報を付与する作業を指します。この解析を行うことで、文章中の単語や文節の構造を把握し、文の意味や構文解析、さらには機械翻訳や情報検索などの応用が可能となります。

MeCabは、効率的で高速な形態素解析を行うためのオープンソースのツールであり、日本語のテキスト処理や自然言語処理の研究や開発で広く利用されています。MeCabはC++で実装されており、コマンドラインツールとしても使用することができます。

MeCabの特徴：

* **高速な解析**:
  * MeCabは高速な形態素解析エンジンであり、大規模なテキストデータを効率的に処理することができます。
* **カスタマイズ可能**:
  * MeCabは辞書や解析オプションのカスタマイズが可能であり、特定のニーズや要件に合わせてカスタマイズすることができます。
* **豊富な言語モデル**:
  * MeCabは豊富な言語モデルを提供しており、様々な用途に応じた形態素解析が可能です。
* **オープンソース**:
  * MeCabはオープンソースであり、無料で利用することができます。

MeCabは、テキストマイニングや情報検索、機械学習などのさまざまな分野で活用されており、日本語の自然言語処理の基礎として広く使われています。

# インストール手順
### 開発環境
- **OS**: macOS
- **Docker環境**:25.0.3

### 使用したツールのバージョン

- **Python**: 3.10.12
- **MeCab**: 0.996

以下のDockerファイルを使用して環境構築を実施しています。
<details><summary>Dockerfile</summary>

```Dockerfile
FROM python:3.10.12-slim-bullseye

# 環境変数の設定
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1

# 必要なパッケージのインストール
RUN apt-get update && apt-get install -y \
    git \
    curl \
    wget \
    nano \
    sudo \
    libzbar-dev \
    vim \
    build-essential \
    mecab \
    libmecab-dev \
    mecab-ipadic-utf8 \
    fonts-ipaexfont \
    && rm -rf /var/lib/apt/lists/*

# gitの設定
RUN git config --global core.autocrlf false

# Pythonパッケージのインストール
RUN pip install --upgrade pip \
    && pip install \
    jupyter==1.0.0 \
    requests==2.31.0 \
    pymongo==4.5.0 \
    pandas==2.1.2 \
    mecab-python3==1.0.8 \
    ipadic==1.0.0 \
    matplotlib==3.8.0 \
    japanize-matplotlib==1.1.3 \
    seaborn==0.13.0 \
    networkx==3.1 \
    scipy==1.11.3 \
    mojimoji==0.0.12 \
    neologdn==0.5.2 \
    google==3.0.0 \
    google-cloud==0.34.0 \
    google-cloud-vision==3.4.4 \
    google-cloud-language==2.11.1 \
    google-cloud-storage==2.12.0 \
    google-api-python-client==2.103.0 \
    openpyxl==3.1.2 \
    xlrd==2.0.1 \
    XlsxWriter==3.1.8 \
    scikit-learn==1.2.2 \
    joblib==1.3.2 \
    openai==0.28.1

# MeCab IPADIC Neologdのダウンロードと設定
RUN git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git && \
    cd mecab-ipadic-neologd && \
    ./bin/install-mecab-ipadic-neologd -n -y && \
    echo dicdir = `mecab-config --dicdir`"/mecab-ipadic-neologd">/etc/mecabrc && \
    sudo cp /etc/mecabrc /usr/local/etc
```

</details>

Dockerfileの中で、主なポイントは以下２点です。

#### 1. MeCabのインストール:
以下は今回MeCabを使用するにあたってインストールしたツールとライブラリです。

- ツール
  - mecab : 日本語の形態素解析エンジン
  - libmecab-dev : mecabを利用したプログラムの開発やカスタマイズを行う
  - mecab-ipadic-utf8 : 日本語の形態素解析辞書
- ライブラリ
  - mecab-python3 : PythonからMeCabを利用するためのインターフェースの提供

#### 2. MeCab IPADIC Neologdのダウンロードと設定:
MeCab IPADIC Neologdは、MeCabの辞書データの一つであり、新語や固有名詞などの追加情報を含んでいます。辞書に関するより詳しい説明は後ほど説明します。
   
```bash
git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
cd mecab-ipadic-neologd 
./bin/install-mecab-ipadic-neologd -n -y
# mecab-ipadic-neologdを指定します
echo dicdir = `mecab-config --dicdir` "/mecab-ipadic-neologd" >/etc/mecabrc 
sudo cp /etc/mecabrc /usr/local/etc 
```

### 参考サイト
* [参考サイト](https://qiita.com/kado_u/items/e736600f8d295afb8bd9)  
* [公式ドキュメント](https://github.com/neologd/mecab-ipadic-neologd/blob/master/README.ja.md#mecab-ipadic-neologd-%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%BA%96%E5%82%99)


# MeCabで行うこと

* 形態素解析による品詞の解析、原型化
* 頻出キーワードの抽出
* 共起キーワードの抽出


# 形態素解析による品詞の解析・原型化
### 目的

今回形態素解析による品詞の解析・原型化を行う目的は主に二つあります。  
* 頻出キーワード集計の準備
  * 同じ単語の異なる変化形や活用形を統一し、単語の出現頻度を正確に集計します。
* 特徴カテゴリへのカテゴライズの準備
  * [前回の記事](https://github.com/venect/review_analysis_renewal/blob/main/Qiita_document_ChatGPT.md#%E8%A8%80%E5%8F%8A%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3%E3%82%92%E7%89%B9%E5%BE%B4%E3%82%AB%E3%83%86%E3%82%B4%E3%83%AA%E3%83%BC%E3%81%AB%E5%88%86%E9%A1%9E)では、単語の感情分析と単語のカテゴライズ方法について説明しました。今回は、カテゴライズの準備として、単語の原形化を行います。例えば、前回の記事で述べたように、キーワードを以下のようにカテゴライズします。しかし、「強い」「強く」「強」などの「強い」に関する単語の全てのパターンを羅列し「風量・風力」にカテゴライズするのは煩雑です。そこで、単語の原形化を用いて、カテゴライズを簡略化します。


```python
entity_categories = {
    '風量・風力': ['風', '強い', '風量', '弱い'],
    '操作性・機能性': ['簡単', 'ボタン'],
    'デザイン・サイズ': ['大きい', '大きさ', '小さい'],
}
```

## サンプルコード
### 形態素解析

初めに単語の原型化を行うために重要な形態素解析を行います。以下の文章を形態素解析してみます。



```
このサイズ感が素晴らしいです。
```

以下が形態素解析を行うコードです。

```python
review_document = 'このサイズ感が素晴らしいです。'
ochasen_tagger = MeCab.Tagger("-Ochasen -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd")
node = ochasen_tagger.parse(review_document)
```


#### パラメータの説明

* -Ochasen
  * MeCabの解析結果の出力モード
  * ChaSen互換
* -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd
  * 辞書の場所の指定
  * インストールした形態素解析辞書
  * mecab-ipadic-neologdとは
    * MeCabの辞書データの一つで、新語や固有名詞など幅広い単語が収録されている辞書
    * 単語の「表層型」「品詞」「読み」「原型」等の情報が格納されている
    * より詳しい説明は[公式ドキュメント](https://github.com/neologd/mecab-ipadic-neologd/blob/master/README.ja.md)


#### 出力結果
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2598043/09ebe4e8-70bf-8ad0-96be-2447f6599b37.png" width="100%">


#### 形態素解析の構成
出力結果は左から以下のような構成となっています。
| 形態素 | 読み方 | 原型（基本形） | 品詞情報1 | 品詞情報2 | 品詞情報3 |
|--------|--------|--------------|----------|----------|----------|



### 原型化
```python
def lemmatize_entities(entity_list):
    ochasen_tagger = MeCab.Tagger("-Ochasen -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd")
    for i, entity in enumerate(entity_list):
        node = ochasen_tagger.parse(entity)
        lines = node.split("\n")
        for line in lines[:-2]:
            fields = line.split("\t")
            print(fields)
            entity_list[i] = fields[2]
    return entity_list
```
まずはキーワード毎に形態素解析を行います。そして```fields```には解析情報が格納されています。また[解析情報の構成](#形態素解析の構成)から原型が格納されているインデックス番号2を指定します。



<details><summary>入力と出力結果の例</summary>

#### 入力
```python
entity_list = ['強い','強く','強']
```

#### 出力
```python
['強い','強い','強い']
```
上記のような結果が得られることで、キーワードのカテゴライズ時に抜け目なく行うことができます。

</details>

<br>


# 頻出キーワードの抽出
### 目的

商品レビュー分析を行う上で、言及されるキーワードは非常に重要です。重要な例は次の通りです：

- **消費者のニーズと嗜好の理解**:
  - 頻出キーワードから、消費者がどのような機能や特性を重視しているかを理解することができます。これにより、消費者のニーズに合った製品を提供するための改善点を特定できます。

- **製品の強みと弱みの特定**:
  - 頻出キーワードから、製品の優れた点や課題点を把握することができます。

- **競合製品の比較**:
  - 競合する製品のレビューから頻出キーワードを抽出することで、競合製品との比較が可能になります。これにより、自社製品の優位性や競合製品との差異を把握し、マーケティング戦略を立てることができます。

**マーケティング戦略の構築**:
消費者のニーズと嗜好を理解し、消費者が関心を持っている特定の機能や利点を強調し、効果的な広告や販促活動を展開することができます。

<br>

## サンプルコード
### 特定の品詞の抽出
先ほどの[形態素解析](#形態素解析)を単語毎に行います。その後、特定の品詞を抽出しています。具体的には、「名詞-一般」や「名詞-固有名詞」などを対象としています。その理由は、「は」や「が」といった「助詞」は頻繁に出現することがありますが、商品レビュー分析においては重要ではないからです。

```python
review_document = 'このサイズ感が素晴らしいです。'
review_keywords_list = []
ochasen_tagger = MeCab.Tagger("-Ochasen -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd")
node = ochasen_tagger.parse(review_document)
lines = node.split("\n")
fields = line.split("\t")
if len(fields) == 6:
    if (
        ("名詞-一般" in fields[3])
        or ("名詞-固有名詞" in fields[3])
        or ("名詞-サ変接続" in fields[3])
        or ("形容詞-非自立" in fields[3])
        or ("形容詞-自立" in fields[3])
        or ("動詞-自立" in fields[3])
        or ("名詞-形容" in fields[3])
    ):
        review_keywords_list.append(fields[0])
```

1.review_documentに対して形態素解析を行います。
2. 形態素情報が格納されているnode文字列に対して改行文字(`"\n"`)で分割して、各行を要素とするリスト`lines`を生成します。
3. 形態素情報のリストの長さが6であるか確認することで正しく解析したかを判断します。
4. 次に特定の品詞を指定し、それが`fields`リストの3番目の要素に含まれているかどうかを確認します。
    - もし特定の品詞であれば、その形態素を`review_keywords_list`リストに追加します。

### キーワードの言及数

以下のコードにより、特定の品詞が格納されたリストから単語の言及数をカウントし、そのカウント結果を降順でソートしています。

```python
keyword_counts = collections.Counter(reviews_keywords_list)
ranked_keywords = keyword_counts.most_common()
```

#### 処理のステップ:
1. **collections.Counter()**  
  リスト内の各単語の出現回数をカウント
2. **most_common()**  
  出現回数の多い順に単語をソート

<details><summary>コード全体</summary>
  
```python
ochasen_tagger = MeCab.Tagger("-Ochasen -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd")
frequent_keywords_compe_by_product_dic = {}
review_keywords_list = []
for demographic, review in reviews.items():
    product_name = demographic[self.product_name_index]
    if product_name not in frequent_keywords_compe_by_product_dic:
        frequent_keywords_compe_by_product_dic[product_name] = []

    node = ochasen_tagger.parse(review)
    lines = node.split("\n")
    fields = line.split("\t")
    if len(fields) == 6:
        if (
            ("名詞-一般" in fields[3])
            or ("名詞-固有名詞" in fields[3])
            or ("名詞-サ変接続" in fields[3])
            or ("形容詞-非自立" in fields[3])
            or ("形容詞-自立" in fields[3])
            or ("動詞-自立" in fields[3])
            or ("名詞-形容" in fields[3])
        ):
            review_keywords_list.append(fields[0])
            frequent_keywords_compe_by_product_dic[product_name].append(fields[0])

    reviews_keywords_list.extend(review_keywords_list)
keyword_counts = collections.Counter(reviews_keywords_list)
ranked_keywords = keyword_counts.most_common()

for product, keyword_part_of_speech in frequent_keywords_compe_by_product_dic.items():
    keyword_part_of_speech_counts = collections.Counter(keyword_part_of_speech)
    ranked_keywords_part_of_speech = keyword_part_of_speech_counts.most_common()
    frequent_keywords_compe_by_product_dic[product] = ranked_keywords_part_of_speech
```

#### 処理解説:

1. **MeCabの準備**  
  MeCabのTaggerを設定し、形態素解析器を初期化します。辞書としてmecab-ipadic-neologdを使用します。
2. **レビューキーワードの抽出**  
  各商品のレビューに対して、形態素解析を実行し、特定の品詞を持つ単語を抽出します。抽出された単語は、frequent_keywords_compe_by_product_dicという辞書に商品ごとに保存されます。
3. **レビューキーワードの全体リスト作成**  
  全ての商品レビューから抽出されたキーワードを一つのリストにまとめます。このリストは、レビューキーワードの出現頻度を数えるために使用されます。
4. **キーワードの出現頻度を数える**  
  全てのレビューキーワードのリストから、キーワードの出現頻度を数えます。これにより、各キーワードの重要度を判断します。
5. **商品ごとの重要キーワードの品詞別ランキングを作成**  
  各商品ごとに、特定の品詞を持つキーワードの出現頻度を数え、ランキング付けします。これにより、各商品の競合他社との比較や特定のニーズに合ったマーケティング戦略を立案するための情報が得られます。

<br>

```python
reviews = {('商品A','A太郎'):'この商品は...',('商品A','B太郎'):'とても使いやすく...',...,('商品B','A子'):'大きさが...'}
```
<br>

reviewsは上記のようにkeyを投稿者の情報、valueが商品レビューの辞書型です。
</details>

<br>



# 共起キーワードの抽出

### 共起キーワードとは
自然言語処理の中でよく使われる手法の一つです。この手法は、レビュー内で同時に出現する単語の組み合わせを数えることで、単語間の関連性や意味の類似性を評価するために使用されます。共起とは「一緒に現れること」を意味し、共起カウントはそのような関係性を分析するための有用な手法です。


### 目的

商品レビュー分析を行う上で、共起キーワードは重要です。重要な例は次の通りです：

- **関連性の発見**:
  - 共起キーワードを抽出することで、消費者の興味や嗜好、ニーズを理解しやすくなります。例えば、扇風機の商品レビューから「部屋」と「全体」が良く共起する場合、消費者が部屋全体まで風が行き渡ることを重視していることがわかります。

<br>

- **商品特性の把握**:
  - 共起キーワードを分析することで、商品やサービスの特性や特徴を把握できます。例えば、スマートフォンのレビューから「バッテリー持ち」と「長時間利用」が共起する場合、その商品が長時間の利用に適していることが示唆されます。

<br>

- **競合製品の比較**:
  - 競合製品や自社製品の差異を把握し、マーケティング戦略を立てる上での情報を得ることができます。



## サンプルコード
### 共起単語の抽出とカウント

以下の関数は商品レビュー内で共起する単語を抽出し、その出現回数をカウントします。この処理では、１文ごとに名詞の単語に限定して共起を抽出します。その理由は、「助詞」などの重要度の低い文字列がカウント上位にランクインする可能性があるためです。

<br>

```python
    def get_noun_cooccurrence(self, sentences):
        split_sentences = re.split(r'[。.!?]\s*', sentences)

        split_sentences = [sentence.strip() for sentence in split_sentences if sentence.strip()]
        all_counter = Counter()
        for sentence in split_sentences:
            nodes = self.mecab.parse(sentence).split("\n")
            words = [node.split("\t")[0] for node in nodes[:-2] if "名詞" in node.split("\t")[3]]
            pair_counter = Counter()
            for pair in combinations(words, 2):
                sorted_pair = tuple(sorted(pair))  
                pair_counter[sorted_pair] = 1  # 1sentence毎での共起の重複削除

            all_counter += pair_counter

        all_counter = self.remove_duplicate_tuples(all_counter)

        return all_counter.most_common()
```
#### 処理のステップ:

1. 形態素解析により、文ごとに名詞の単語リストの取得
2. 単語ペアのカウント
3. 共起回数でソートして返す

<br>

### 商品毎の共起語のカウントとリスト取得

以下のコードにより商品毎に共起後の単語リストを取得します。

```python
def summary_cooccurrence(self, reviews, num_of_cooccurrence):
    cooccurrence_dict = {}
    # 商品毎の空の辞書
    for demographic, review in reviews.items():
        product_name = demographic[self.product_name_index]
        if product_name not in cooccurrence_dict:
            cooccurrence_dict[product_name] = []
    # 商品毎に共起カウントのリストを合算/ソート
    for demographic, review in reviews.items():
        summary_list_by_product = cooccurrence_dict[demographic[self.product_name_index]]
        summary_counter = Counter(dict(summary_list_by_product))
        add_list = self.get_noun_cooccurrence(reviews[demographic])
        add_counter = Counter(dict(add_list))
        summary_counter += add_counter
        summary_list_by_product = list(sorted(summary_counter.items(), key=lambda x: x[1], reverse=True))
        cooccurrence_dict[demographic[self.product_name_index]] = summary_list_by_product
    
    # カウント数上位num_of_cooccurrence取得
    for product_name, cooccurrence_list in cooccurrence_dict.items():
        cooccurrence_dict[product_name] = cooccurrence_list[:num_of_cooccurrence]
    
    return cooccurrence_dict
```
#### 処理のステップ:

1. 商品毎の空の辞書を初期化
2. 商品毎に共起カウントのリストを合算
   get_noun_cooccurrence関数により名詞に限定して共起している組を作成しカウントします。
3. 商品毎に上位共起後のリストを返す


# まとめ
MeCabを用いて単語の形態素解析を行うことで単語の「品詞」や「原型」など商品レビューの分析に役立つ情報を取得することができます。今回は主にキーワードの分類とカウントに用いましたが、機械学習の前処理などに使われることも多いです。それほどMeCabは分析に重要なライブラリであることがわかりました。

* [第一回 | 商品レビュー分析のリニューアルに伴う自動化システム構築について](https://qiita.com/venect_qiita/items/afc8e35a579f494d7d60)
* [第二回 | Google Natural Language API](https://qiita.com/venect_qiita/items/83607a124cad9dcb4e8a)
* [第三回 | ChatGPT](https://qiita.com/venect_qiita/items/d53be4b15ad44be8f1db)
* 第四回 | MeCab