Watson NLU で分類器(classification)を使ってみた

# はじめに
IBM Watsonが提供するサービスで、NLU(Natural Language Understanding）を利用して文書の分類を行うことができます。
今回はニュース記事のサンプルデータでカテゴリーを作成して、新たな記事を分類する手順を試してみます。

# 目次

1. NLU環境準備
2. 学習用データの準備
2. カスタム分類モデルの作成
3. 分類器の実行
3. （オプション）カスタム分類モデルの削除
3. （おまけ）jupyter notebookでの実行例

# 1. NLU環境準備
[IBM Cloud](https://cloud.ibm.com/) のカタログから [NLU](https://cloud.ibm.com/catalog/services/natural-language-understanding) のライトプランを作成して、管理画面を開きます。
NLUの機能を利用するときは、ここにある **apikey** と **url** を使用します。
![nlu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/ff04e958-6f32-d086-8b29-249d303f9071.png)


# 2. 学習用データの準備
カスタム分類モデルを作成するために、学習用の分類ラベル付きデータをJSONまたはCSV形式を使用します。
CSVファイルはUTF-8形式で、以下の形式で準備します。
・形式は **text,label** （textはサンプル文書、labelはカテゴリー名。）
　テキスト列の文に複数のラベルを適用する場合は、ラベル列をさらに追加できます。
　例： **text,label,label**
今回はサンプルとしてニュース記事をtext、記事カテゴリーをlabelとしてCSVファイルを作成して登録しています。
![classify_train.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/87ee58b9-4008-8794-95ed-8002a6c332d2.png)

# 3. カスタム分類モデルの作成
学習用データを使用して、カスタム分類モデルを作成します。
学習用データの存在するディレクトリで以下のコマンドを実行します。
```sh
curl -X POST -u "apikey:{apikey}" \
 -H "Content-Type: multipart/form-data" \
 -F "name=MyClassificationsModel" \
 -F "language=ja" \
 -F "model_version=1.0.1" \
 -F "training_data=@{file_name};type=text/csv" \
"{url}/v1/models/classifications?version=2021-08-01"
```
:::note info
**{apikey}** と **{url}** の箇所はそれぞれ上記NLU環境の値にして、 **{file_neme}** は学習用データのファイル名に書き換えて実行します。
:::

**実行結果**
```
curl -X POST -u "apikey:xxxxxxxxxx" -H "Content-Type: multipart/form-data" -F "name=MyClassificationsModel" -F "language=ja" -F "model_version=1.0.1" -F "training_data=@news_train.csv;type=text/csv" "https://api.jp-tok.natural-language-understanding.watson.cloud.ibm.com/instances/xxxxxxxxxx/v1/models/classifications?version=2021-08-01"
{"name":"MyClassificationsModel","user_metadata":null,"language":"ja","description":null,"model_version":"1.0.1","version":"1.0.1","workspace_id":null,"version_description":null,
"status":"starting","notices":[],
"model_id":"0ec2385f-1bb3-46b2-a1a8-7a647d18278b",
"features":["classifications"],"created":"2022-03-16T10:17:20Z","last_trained":"2022-03-16T10:17:20Z","last_deployed":null}
```
:::note info
実行結果には **"model_id"** などが返されます。
**model_id** は、これ以降のステータス確認や分類実行時に使用します。
:::

学習の完了までは時間がかかるため、ステータスを見て分類モデルが利用できる状態になっているかを確認します。

**ステータス確認**
```shell
curl -X GET -u "apikey:{apikey}" \
 "{url}/v1/models/classifications/{model_id}?version=2021-08-01"
```

:::note info
statusが **"standby"** や **”available”** になっていれば学習は完了しています。
:::

学習が完了すると、カスタム分類モデルはNLUにデプロイされて、分析に使用できる状態になります。


# 4. 分類器の実行
作成した分類モデルを使用して、文書の分類を行います。


```sh
curl -u "apikey:{apikey}" \
"{url}/v1/analyze" \
  --get \
  --data-urlencode "version=2021-08-01" \
  --data-urlencode "features=classifications" \
  --data-urlencode "classifications.model={model_id}" \
  --data-urlencode "text={分類対象文書}"
```

:::note info
**{分類対象文書}** の箇所は実際に分類を行いたい文書文字列に置き換えて実行します
:::

**実行例**
```
curl -u "apikey:xxxxxxxxxx" \
"https://api.jp-tok.natural-language-understanding.watson.cloud.ibm.com/instances/xxxxxxxxxx/v1/analyze" \
  --get \
  --data-urlencode "version=2021-08-01" \
  --data-urlencode "features=classifications" \
  --data-urlencode "classifications.model=6fc45743-89e8-4df8-9290-ff3a20b09c5c" \
  --data-urlencode "text=米地質調査所（ＵＳＧＳ）によると、南太平洋の島国ソロモン諸島で９日朝、マグニチュード （Ｍ）７・８の強い地震が発生した。"
{
  "usage": {
    "text_units": 1,
    "text_characters": 59,
    "features": 1
  },
  "language": "ja",
  "classifications": [
    {
      "confidence": 0.611503,
      "class_name": "国際"
    },
    {
      "confidence": 0.221767,
      "class_name": "科学"
    },
    {
　　・・・以下省略
```

:::note info
実行結果として、分類カテゴリー(class_name)と信頼度(confidence)が得られます。
confidenceは 0〜1の範囲で、値が大きいほど信頼性が高いことを示します。
:::

このように、ニュース記事の分類モデルを作成して、新たな文書で分類を試すことができました。
NLUの分類器では、複数カテゴリーへの分類結果と信頼度を得ることができます。信頼度の値を利用して一番値の大きい単一カテゴリーへの分類するか、閾値(例えば0.6以上)を分類カテゴリーとするか、などは用途によって決めていくことになります。

# 5. （オプション）カスタム分類モデルの削除
不要になった分類モデルを削除します。
```shell
curl -X DELETE -u "apikey:{apikey}" \
 "{url}/v1/models/classifications/{model_id}?version=2021-08-01"
```

:::note info
実行結果が、**"deleted"** となれば削除完了です。
:::

# 6. （おまけ）jupyter notebookでの実行例
jupyter notebookを利用すると、より簡単に実行することができます。

```python
# Watsonのライブラリをインストールします
!pip install --upgrade ibm-watson
```

###### Watson NLU に接続

```python
# 各自のNLU環境に合わせて書き換えます
api_key = '{apikey}'
url = '{url}'

from ibm_watson import NaturalLanguageUnderstandingV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

auth = IAMAuthenticator(api_key)
nlu = NaturalLanguageUnderstandingV1(version='2021-08-01', authenticator=auth)

nlu.set_service_url(url)

print("NLUサービスに接続成功")
```

###### ニュースのサンプルを使用して分類モデルを作成（学習）

```python
# カテゴリー付きのニュースサンプル(CSV形式)を学習用データとして指定します
training_data_filename = 'news_train.csv'
with open(training_data_filename, 'rb') as file:
    model = nlu.create_classifications_model(language='ja', training_data=file, training_data_content_type='text/csv', name='NewsClassificationsModel', model_version='1.0.2').get_result()
    
    print("作成されたNLU 分類モデル:")
    print(json.dumps(model, indent=4))
```

###### ステータスの確認

```python
# statusは starting -> training -> standby となるので、standbyになるまで待ちます
import json
model_id = model['model_id']
model_to_view = nlu.get_classifications_model(model_id=model_id).get_result()

print("作成されたNLU分類モデルの情報:")
print(json.dumps(model_to_view, indent=4))
```

###### 文書の分類を実行

```python
from ibm_watson.natural_language_understanding_v1 import Features, ClassificationsOptions

# 分類対象文書（ここを書き換えて試します）
text = "新型コロナウイルスの感染「第6波」の減少ペースが鈍化している。感染が急拡大したオミクロン株の流行は、収束も速いとの見方が強かった。だが、2月上旬にピークを超えた後に新規感染者数の減少ペースが遅いのは、なぜか。"

analysis = nlu.analyze(text=text, features=Features(classifications=ClassificationsOptions(model=model_id))).get_result()
print(json.dumps(analysis, indent=4, ensure_ascii=False))
```
###### 実行結果
```
    {
        "usage": {
            "text_units": 1,
            "text_characters": 104,
            "features": 1
        },
        "language": "ja",
        "classifications": [
            {
                "confidence": 0.407471,
                "class_name": "科学"
            },
            {
                "confidence": 0.157387,
                "class_name": "経済"
            },
            {
                "confidence": 0.114667,
                "class_name": "国際"
            },
            {
                "confidence": 0.109498,
                "class_name": "国内"
            },
            {
                "confidence": 0.052802,
                "class_name": "政治"
            },
            {
                "confidence": 0.049228,
                "class_name": "カルチャー"
            }
        ]
    }
```

---
**Natural Language Understanding 製品マニュアル**
https://cloud.ibm.com/docs/natural-language-understanding?topic=natural-language-understanding-classifications