SPSS Modelerのテキスト分析のチュートリアル②カテゴリーのフラグ化

# はじめに
SPSS Modeler Premium 18.6では日本語テキスト分析が可能になっています。

テキスト分析については[ModelerFlowのチュートリアル](https://dataplatform.cloud.ibm.com/docs/content/wsd/tutorials/tut_ta_hotel.html?locale=ja&context=cpdaas&audience=wdp&audience=wdp)と@TTS22 さんの[日本語解説記事](https://qiita.com/TTS22/items/5c00b53a473737586be4)がありますので、この内容をオンプレ版のModelerで実行してみます。

３つの記事からなっています。

[①インタラクティブ・ワークベンチ](https://qiita.com/spssfun2017/items/1f9e8af832ca19a90b35)
②カテゴリーのフラグ化（←この記事）
[③テキストリンク分析](https://qiita.com/spssfun2017/items/af4cf51083b3a3a3dd1e)

■テスト環境
* Modeler Premium 18.6
* Windows 11 64bit

# テストデータ
@TTS22 さんが翻訳してくれたホテルの満足度調査のデータを使います。
Comments列にテキストデータが入っています。820件あります。
![{F9DA5B8D-38EC-44FD-9CD7-8AD26AFEA503}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/de7236a2-96c9-ba25-9ba1-02b2c0bfcdbe.png)


# テキストマイニング
「IBM SPSS Text Analytics」のパレットから「テキストマイニング」のノードを接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/11c80a6d-6d97-2e83-c988-ad690f3d91d3.png)

まず、フィールドのタブで以下を選択します。
IDフィールド：`id`
テキストフィールド：`Comments`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/be89c8b1-7d36-b02e-0940-761e26545632.png)

次に、モデルのタブで「テキスト分析パッケージ」を選び、「読み込み」をクリックし、「HotelSatisfaction (Japanese).tap」を選んで「ロード」します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/19ebdd82-82be-e850-caf7-7a63b0a6753c.png)

そして「実行します」
![{1805502E-A044-4759-9E35-B7D6FA590697}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/2aedda1c-c7f1-a9b9-aa35-774790d899fa.png)

インタラクティブ・ワークベンチが開きます。
「カテゴリーとコンセプト」を選びます。
「HotelSatisfaction (Japanese)」のテキスト分析パッケージで定義された「カテゴリー」が表示されています。
「`Atomosphere/Pos`」などのカテゴリーが定義されています。このカテゴリーで「モデルを生成」します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/03f0184e-b1c6-d417-3868-31af374bd1e5.png)

モデルのパレットに「Comments」というモデルができますので、これを「hotelSatisfaction_japanese.csv」ノードに接続します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/9824e5dd-0622-ddd9-93b9-9d5d68191e36.png)


# センチメント分析
このモデルではPositiveかNegativeかの分類ができているので、2つの方法でセンチメント分析をしてみます。

## フィールドに展開して集計
まずはカテゴリーをフィールドに展開していきます。

モデルを開いてみると、AtomosphereやCheckin＆Outなどのカテゴリーの下にNegとPosのサブカテゴリーがあり、PositiveかNegativeかを分類できることがわかります。これらをフラグ化していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/56563bd1-a2ff-cf29-b182-e6217466ee7d.png)

「設定」タブにうつり、「フィールドとしてのカテゴリー」にチェックがあることを確認します。これでフラグ化が行われます。「真の値」と「偽の値」は集計しやすいように「1」「0」にしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/02692e8a-a93c-b8bc-5150-7f5724173eb4.png)

プレビューをしてみると各カテゴリーがフラグ化されたことがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/4029a324-ce59-3a03-7e45-207cb6fef82d.png)

モデルの実行は内部的にパラレル実行されるようで順序が変わってしまうので、ソートノードで並べておくのがおすすめです。また、スコアリングの実行は重めの処理なのでキャッシュしておくのもおすすめです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/22b7ca36-815f-fd71-3bca-13c3f1acc200.png)

フィールド作成ノードで、以下のClem式を使って、PositiveとNegativeのカテゴリ数を計算します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/98f5d6f0-bf8a-2de0-6b18-de0826399897.png)

```java:Neg
sum_n(@FIELDS_MATCHING("Category_*Neg"))
```
```java:Pos
sum_n(@FIELDS_MATCHING("Category_*Pos"))
```
以下のように"Category_*Neg"などにマッチする列の値を足しこんでいっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/c42ba1ac-a52e-6d47-4ee6-960f9286fc67.png)

プレビューすると以下のように算出されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/a0343175-c8fb-4d73-2c9f-4781ba6bd927.png)

次にこのPosとNegの値から、以下の条件でセンチメントを一意に決定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/703ea917-fde7-079d-3fee-6d4c3ae826f2.png)

|設定値|条件|
|---|---|
|"no score"|Neg =0 and Pos=0| 
|"positive"|Neg=0 and Pos>0|
|"negative"|Neg > 0 and Pos=0|
|"mixed"|Pos > 0 and Neg > 0|

以下のように判定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/981f03b9-f8bc-f05a-51d8-3c4fee91601a.png)

棒グラフで表示してみます。
フィールド：Sentiment
色：Reason
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/67e918ca-581d-c708-4d97-821db045ee21.png)

結果は以下のようになりました。
45.1％がポジティブな意見で、ネガティブな意見はレジャーの割合が高そうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/94702b28-1d91-7bc7-36c5-543413890d4f.png)



## レコードに展開して集計
次はカテゴリーをフィールドに展開していきます。

モデルナゲットをコピーして、「設定」タブで「レコードとしてのカテゴリー」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/5fda9071-532c-03f5-36bb-f0cb8c7da657.png)

やはり、モデルの実行は内部的にパラレル実行されるようで順序が変わってしまうので、ソートノードで並べておくのがおすすめです。また、スコアリングの実行は重めの処理なのでキャッシュしておくのもおすすめです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/188b61c1-05ad-90b0-7870-9001e240c0f4.png)

結果は以下のようになります。カテゴリーがレコードに展開されるので、一つのコメントが複数のカテゴリに該当すると複数行になります。この例ではid=5の「快適な客室, 素晴らしい朝食, 素晴らしいサービス」のコメントは`Comfort/Pos`、`HotelAmenities/Restaurant/Pos`、`Staff/GenSat/Pos`のカテゴリに該当したので3レコードになっています。
一方でid=2のコメントはどのカテゴリーにも該当しなかったのでレコードが削除されています。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/60685afe-6e1e-3d32-8f06-067298dcbe9d.png)

センチメントの情報を抜き出します。Category列にNegやPosが含まれているかで判定しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/8730f4c9-505d-c030-e2a8-6dec6445fe14.png)

|設定値|条件|
|---|---|
|Neg|Category matches "*/Neg"| 
|Pos|Category matches "*/Pos"|

以下のように抜き出せます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/d69ec756-c39c-01ec-ecfa-15974c40b87d.png)

次に「置換」ノードで、CategoryからNegとPosを取り除いて上位カテゴリーのみを抜き出します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/b55361bc-b7ab-eabe-7445-02c8054074a4.png)
```java:Pos
replace('/Pos','',@FIELD)
```
```java:Neg
replace('/Neg','',@FIELD)
```
以下のようにCategoryからNegとPosを取り除けました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/f5f9944d-16a6-86b6-7436-3c46c7ab7f58.png)

カテゴリーごとのセンチメントを棒グラフで表示します。
フィールド：Category
色：Sentiment
色で正規化：チェック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/117a0bb9-8edb-7536-a5fd-9ae367cecd76.png)

以下の結果を見ると`Location`や`Upgrade`はポジティブな意見が100％で、`Confort/Size`はネガティブな意見が多いことがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/b8c83e57-7e82-0479-4046-29a256e74308.png)


# まとめ

やはり、Modelerのテキスト分析ではこの記事で紹介したカテゴリーのフラグ化が最も使われると思います。
レコードに展開して集計も上位カテゴリで分析する際には役に立つことがわかりました。ただ、このサンプルは「HotelSatisfaction (Japanese)」のテキスト分析パッケージはがあったので、比較的簡単な操作できましたが、カテゴリを自分で定義していくのはかなり大変です。
単純なコンセプトによるフラグ化が、やはり一番出番が多いのかなと思います。


# サンプル
#### サンプルストリーム
https://github.com/hkwd/spsssample/raw/refs/heads/master/241227TA_HotelSatisfaction/15%20-%20Hotel%20Satisfaction%E3%82%AB%E3%83%86%E3%82%B4%E3%83%AA2SAJA.str


#### サンプルデータ
https://github.com/hkwd/spsssample/blob/master/241227TA_HotelSatisfaction/hotelSatisfaction_japanese.csv

# 参考

#### ホテル満足度のテキスト分析 - Docs | IBM Cloud Pak for Data as a Service 

https://dataplatform.cloud.ibm.com/docs/content/wsd/tutorials/tut_ta_hotel.html?locale=ja&context=cpdaas&audience=wdp&audience=wdp

#### 【CP4DaaS】SPSS ModelerのText Analyticsで日本語テキストデータを分析する （テキスト・マイニング） #ibmcloud - Qiita 
https://qiita.com/TTS22/items/5c00b53a473737586be4