SPSS Modelerでテキストマイニングをやってみる その3 形態素解析編

# SPSS Modelerでのテキストマイニング 形態素解析編

こんにちは
前回の感情分析編からの続きです。今回は、Mecabによる形態素解析をやってみます。


https://qiita.com/harrowharrow16/items/a3ac51a91080c21da87d

Modelerでのjanomeによる形態素解析はすでにIBMブログにありますので、そちらも参考してみてください。

https://www.ibm.com/blogs/solutions/jp-ja/spssmodeler-push-node-22/

**※ 2025/03/13 記事で使用したストリームとデータをアップロードしました。**

https://github.com/harrow16/Qiita/tree/main/TextMining_Part3_1001

## 1. さっそく形態素解析をやっていく
　まずは、Mecabのインストールをお願いします。準備編で説明しています。

 https://qiita.com/harrowharrow16/items/248ff8fe3879b63e7ae3

### ①. ストリーム全体

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/becab869-7817-972c-489a-7d6bc04a6b50.png)

前回の感情分析ストリームとほぼ同じです。感情分析を実施する拡張ノードが形態素解析を実施するものになっただけです。


### ②. データ入力処理

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/98a7f4e8-8486-6100-a1f2-965550c78a8f.png)

前回と入力データも、サンプリングも同じです。そのまま流用してください。

### ③. 形態素解析処理

こちらも前回と同様に「拡張の変換ノード + Pythonシンタックス」で実装します。

※.2025/3/13 修正
ipadicをインポートする処理を追加しました。
また、Tagger()メソッドでipadicを明示的に使用するように修正しました。m(_ _)m

#### a. コード全体

``` python:形態素解析コード全体
#------------------------------------------------------
# ライブラリ定義
#------------------------------------------------------
# Modeler用ライブラリ
import modelerpy

# 形態素解析用 MeCab - 事前にインストールしておくこと
import MeCab
# 2025/3/13 追加
# ipadicをインポート
import ipadic 

# Pandas - 事前にインストールしておくこと
import pandas as pd

# MeCabのTaggerを作成（chasen辞書を指定）
# 2025/3/13 ipadicを指定するように変更
#mecab = MeCab.Tagger("-Ochasen")
mecab = MeCab.Tagger(f'-d "{ipadic.DICDIR}" -Ochasen')

#----------------------------------------------------
# 形態素解析用関数
#----------------------------------------------------
def mecab_parse(text):
    # mecabで形態素解析を実行
    parsed_text = mecab.parse(text)
    # 結果を行ごとに分割
    lines = parsed_text.splitlines()
    # 最後のEOF行を除外
    lines = [line for line in lines if line != 'EOS']

    # 結果をリストに変換
    results = []
    for line in lines:
        # 各行をタブで分割してリストに変換
        parts = line.split("\t")
        # タブ区切りの要素が正しく含まれているか確認
        if len(parts) >= 4:
            surface = parts[0]  # 表層形
            base = parts[2]     # 原形
            pos = parts[3]      # 品詞
            results.append((surface, base, pos))
 
    #結果を戻す
    return results

#-------------------------------------------------------
# 出力用データ定義処理
#-------------------------------------------------------
if modelerpy.isComputeDataModelOnly():
    #データモデル取得
    modelerDataModel = modelerpy.getDataModel()

    #--------------------------------------------------------------
    #出力用変数フィールドを追加
    #--------------------------------------------------------------
    #データモデルにフィールドを追加
    #形態素解析アウトプット用のフィール定義
    field_name_1 = "表層形"
    field_name_2 = "原形"
    field_name_3 = "品詞"

    #データモデルの設定
    modelerDataModel.addField(modelerpy.Field(field_name_1, "string", measure="nominal"))
    modelerDataModel.addField(modelerpy.Field(field_name_2, "string", measure="nominal"))
    modelerDataModel.addField(modelerpy.Field(field_name_3, "string", measure="nominal"))

    #出力データモデル定義
    modelerpy.setOutputDataModel(modelerDataModel)

#-------------------------------------------------------
# 形態素解析処理
#-------------------------------------------------------
else:
    #入力データ取得
    modelerData = modelerpy.readPandasDataframe()

    #-------------------------------------------------------
    # 形態素解析処理実行
    #-------------------------------------------------------
    # DataFrameの「Sentence」カラムに対して形態素解析を実行し、解析結果を追加
    modelerData['parsed'] = modelerData['Sentence'].apply(mecab_parse)

    #-------------------------------------------------------
    # 形態素解析処理結果をまとめる
    #-------------------------------------------------------
    # parsed列を縦持ちにする（リストを展開する）
    inputData_exploded =modelerData.explode('parsed')

    # parsed列を「表層形」「原形」「品詞」に分割
    inputData_exploded[['表層形', '原形', '品詞']] = pd.DataFrame(inputData_exploded['parsed'].tolist(), index=inputData_exploded.index)

    # 不要なカラムを削除
    inputData_exploded = inputData_exploded.drop(columns=['parsed'])

    #-------------------------------------------------------
    # Modelerへデータを戻す
    #-------------------------------------------------------
    modelerpy.writePandasDataframe(inputData_exploded)
```

#### b. コード詳細
さて処理別にコードの内容をみていきましょう。

##### b-1. ライブラリインポート部分
まずは必要なライブラリをインポートしているだけです。
事前に準備の記事を参考にライブラリを導入しましょう。

また、Tagger()メソッドで、MeCabの解析機能を持つオブジェクトを作成しています。
これを使ってテキスト解析します。

**※.2025/3/13 修正**
ipadicをインポートする処理を追加しました。
また、Tagger()メソッドでipadicを明示的に使用するように修正しました。

**理由**
v18.5で実行している時は、修正前のコードで動いたのですが、
v18.6で実行した際に"chasen"がipadicを指定しないと動かなくなりました。

これも原因は分かっていて、感情分析する際にunidic_liteを導入しないとv18.6では動かなくなりました。
そのため、unidic_liteを導入したのですが、するとこちらの"chasen"がipadicを指定しないと使えなくなりました。

おそらく、辞書のパスなどが変わってしまったのでしょう。v18.5で動いていたのが奇跡かもしれませんね。
申し訳ございませんでした。



``` Python:ライブラリインポート部分
#------------------------------------------------------
# ライブラリ定義
#------------------------------------------------------
# Modeler用ライブラリ
import modelerpy

# 形態素解析用 MeCab - 事前にインストールしておくこと
import MeCab
# 2025/3/13 追加
# ipadicをインポート
import ipadic 

# Pandas - 事前にインストールしておくこと
import pandas as pd

# MeCabのTaggerを作成（chasen辞書を指定）
# 2025/3/13 ipadicを指定するように変更
#mecab = MeCab.Tagger("-Ochasen")
mecab = MeCab.Tagger(f'-d "{ipadic.DICDIR}" -Ochasen')

```

##### b-2. 形態素解析関数部分
ここでは、形態素解析処理を関数化しています。

関数名 : mecab_parse　
入力 : text = 文字列データ
出力 : result = 表層系、原形、品詞をリスト化した結果データ

``` Python: 形態素解析関数
#----------------------------------------------------
# 形態素解析用関数
#----------------------------------------------------
def mecab_parse(text):
    # mecabで形態素解析を実行
    parsed_text = mecab.parse(text)
    # 結果を行ごとに分割
    lines = parsed_text.splitlines()
    # 最後のEOF行を除外
    lines = [line for line in lines if line != 'EOS']

    # 結果をリストに変換
    results = []
    for line in lines:
        # 各行をタブで分割してリストに変換
        parts = line.split("\t")
        # タブ区切りの要素が正しく含まれているか確認
        if len(parts) >= 4:
            surface = parts[0]  # 表層形
            base = parts[2]     # 原形
            pos = parts[3]      # 品詞
            results.append((surface, base, pos))
 
    #結果を戻す
    return results
```

さらに詳細をみていきます。
最初に、mecabのparse関数で形態素解析を実行します。

``` Python: 形態素解析処理
    # mecabで形態素解析を実行
    parsed_text = mecab.parse(text)
```

形態素解析の結果を行ごとに分割、EOF行を削除します。

``` Python: 結果格納処理1
    # 結果を行ごとに分割
    lines = parsed_text.splitlines()
    # 最後のEOF行を除外
    lines = [line for line in lines if line != 'EOS']
```

各行ごとのデータはタブ区切りデータとなっているので、
タブで分割して各項目を取得してリストに追加します。

``` Python: 解析結果格納処理2
for line in lines:
        # 各行をタブで分割してリストに変換
        parts = line.split("\t")
        # タブ区切りの要素が正しく含まれているか確認
        if len(parts) >= 4:
            surface = parts[0]  # 表層形
            base = parts[2]     # 原形
            pos = parts[3]      # 品詞
            results.append((surface, base, pos))
```

最後、結果を戻します。

``` Python: 戻り値設定
    #結果を戻す
    return results
```

##### b-3. データモデル定義処理
前回と同様にまずは、データモデル定義を行います。
今回は、表層形、原形、品詞のフィールドを追加定義します。


``` Python: データモデル定義処理
#-------------------------------------------------------
# 出力用データ定義処理
#-------------------------------------------------------
if modelerpy.isComputeDataModelOnly():
    #データモデル取得
    modelerDataModel = modelerpy.getDataModel()

    #--------------------------------------------------------------
    #出力用変数フィールドを追加
    #--------------------------------------------------------------
    #データモデルにフィールドを追加
    #形態素解析アウトプット用のフィール定義
    field_name_1 = "表層形"
    field_name_2 = "原形"
    field_name_3 = "品詞"

    #データモデルの設定
    modelerDataModel.addField(modelerpy.Field(field_name_1, "string", measure="nominal"))
    modelerDataModel.addField(modelerpy.Field(field_name_2, "string", measure="nominal"))
    modelerDataModel.addField(modelerpy.Field(field_name_3, "string", measure="nominal"))

    #出力データモデル定義
    modelerpy.setOutputDataModel(modelerDataModel)
```

##### b-4. 形態素解析処理
さて、本題の形態素解析処理をelseパートで記述します。


``` Python: 形態素解析処理

#-------------------------------------------------------
# 形態素解析処理
#-------------------------------------------------------
else:
    #入力データ取得
    modelerData = modelerpy.readPandasDataframe()

    #-------------------------------------------------------
    # 形態素解析処理実行
    #-------------------------------------------------------
    # DataFrameの「Sentence」カラムに対して形態素解析を実行し、解析結果を追加
    modelerData['parsed'] = modelerData['Sentence'].apply(mecab_parse)

    #-------------------------------------------------------
    # 形態素解析処理結果をまとめる
    #-------------------------------------------------------
    # parsed列を縦持ちにする（リストを展開する）
    inputData_exploded = modelerData.explode('parsed')

    # parsed列を「表層形」「原形」「品詞」に分割
    inputData_exploded[['表層形', '原形', '品詞']] = pd.DataFrame(inputData_exploded['parsed'].tolist(), index=inputData_exploded.index)

    # 不要なカラムを削除
    inputData_exploded = inputData_exploded.drop(columns=['parsed'])

    #-------------------------------------------------------
    # Modelerへデータを戻す
    #-------------------------------------------------------
    modelerpy.writePandasDataframe(inputData_exploded)
```

まずは、Modelerからデータを入力。readPandasDataframe()を使用してPandasデータフレームで読み込みができます。

``` Python: データ入力
    #入力データ取得
    modelerData = modelerpy.readPandasDataframe()
```

先述した関数を呼び出して形態素解析を実行します。
結果は'parsed'カラムにリスト形式で受け取ります。


``` Python: 形態素解析用関数呼び出し
    #-------------------------------------------------------
    # 形態素解析処理実行
    #-------------------------------------------------------
    # DataFrameの「Sentence」カラムに対して形態素解析を実行し、解析結果を追加
    inputData['parsed'] = modelerData['Sentence'].apply(mecab_parse)
```

形態素解析結果の単語リストデータを縦持ちに展開します。
また、各単語ごとにさらに表層形、原形、品詞をカラムに展開しておきます。
これは、後々Modelerでフラグ設定ノードをはじめデータ加工や分析で利用したいので、この形式にしています。


``` Python: 結果の展開
    #-------------------------------------------------------
    # 形態素解析処理結果をまとめる
    #-------------------------------------------------------
    # parsed列を縦持ちにする（リストを展開する）
    inputData_exploded = modelerData.explode('parsed')

    # parsed列を「表層形」「原形」「品詞」に分割
    inputData_exploded[['表層形', '原形', '品詞']] = pd.DataFrame(inputData_exploded['parsed'].tolist(), index=inputData_exploded.index)

    # 不要なカラムを削除
    inputData_exploded = inputData_exploded.drop(columns=['parsed'])
```

最後にデータをModelerに戻します。
``` Python: データ出力
    #-------------------------------------------------------
    # Modelerへデータを戻す
    #-------------------------------------------------------
    modelerpy.writePandasDataframe(inputData_exploded)
```

### ④. 結果の確認
結果は、下記画像の通りになります。
各テキスト毎に形態素解析して縦持ちにしたのは、このフォーマットにするためです。
Modelerのユーザーであれば、フラグ設定ノード等を利用して、ここから様々な分析に活用できることが想像できると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3839172/8d225260-bba7-b2c9-86ee-ca951d3fd7f0.png)



## 2. まとめ
前回と今回の2回に分けてModelerでの日本語テキストマイニングの方法をご紹介しました。テキストマイニングに関してはノードでの日本語サポートは終了していますが、拡張ノードを利用することで、GoogleのBERTなど最新の技術をすぐに利用して分析が実施できるので、チャレンジしてみてください。


 10/17 追記

 v18.4以前のユーザーさんでも参考になるように「Python for Spark」での記事も書きました。
 
 https://qiita.com/harrowharrow16/items/56770bf38f5e20a799dd



## 3. 次回
さて次回は、感情分析・形態素解析の結果をModelerで活用してみようと思います。
ワードクラウドやアソシエーションモデルをご紹介します。

https://qiita.com/harrowharrow16/items/871a1db08c43cab4f6d9


# 参考

SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/items/503037195081d3323eee

SPSS Modeler 逆引きストリーム集

https://qiita.com/416nishimaki/items/4bf813e6cba84b2a1008

SPSS funさん記事集

https://qiita.com/spssfun2017

SPSS連載ブログバックナンバー

https://qiita.com/416nishimaki/items/24c054defbe7280bcf0e

SPSSヒモトクブログ

https://www.ibm.com/blogs/solutions/jp-ja/category/bigdata-analytics/spss-modeler-himotoku/