Natural Language API でお手軽センチメント分析(感情分析)

SNSで取り上げられている発言を分析して、あるサービスや商品に対する評判を可視化したい、と言うケースに当たりました。
(=センチメント分析)。

GCPのサービスの一つ 「Natural Language API」を使ったところ、お手軽にセンチメント分析ができたので、メモがてら記述しておきます。

## Natural Language API とは

Google Cloud Platform が提供する機械学習系サービスの一つ。
https://cloud.google.com/natural-language?hl=ja

テキストデータの分析を手軽に行える。

- エンティティ分析
    - 文章中の単語や固有名詞を抽出
- 感情分析
    - 文章内の感情を数値化
- コンテンツ分類
    - 文章のタイプ・分類を判定する

などができる。

## Natural Language API の使い方

1. GCPのダッシュボードからプロジェクト作成
2. APIの有効化
3. APIキーを取得

詳しくは以下を参照。
https://cloud.google.com/natural-language?hl=ja

以下のガイドを見れば、迷う箇所はほとんどない。
https://codelabs.developers.google.com/codelabs/nlp-from-google-docs-ja/index.html?index=..%2F..next17-tok#0


## Google Apps Script で Twitter のツイート分析をする

- Twitter のツイートを、Google スプレッドシートに保存
- Google Apps Script で スクリプト作成
    - スプレッドシートのセルからツイートを取得
    - Natural Language APIで感情分析
    - 取得した結果をシートに記入

というユースケースで実装してみました。


## Google スプレッドシートの準備

最初に、分析したい文章を準備

<img width="712" alt="nla_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83767/ba5d8f2f-b1bf-2848-a945-df26183e4cc1.png">


## Google Apps Script の記述

次に、テキストデータを分析するためのスクリプトを準備。
今回は

- Natural Language APIをコールする関数
- シートからテキストデータを取得して、APIコールする関数へ引き渡し、返り値を記入する関数

の２種類で記述しました。

### Natural Language APIをコールする関数

[Google Code Lab のコード](https://codelabs.developers.google.com/codelabs/nlp-from-google-docs-ja/index.html?index=..%2F..next17-tok#4)をほぼそのまま流用

retrieveSentiment.gs

```javascript
function retrieveSentiment (textData) {
  var apiKey = 'APIキーを記述';
  var apiEndpoint = 
'https://language.googleapis.com/v1/documents:analyzeSentiment?key=' 
+ apiKey;

  //  Create a structure with the text, its language, its type,
  //  and its encoding
  var docDetails = {
    language: 'ja-jp',
    type: 'PLAIN_TEXT',
    content: textData
  };
  
  var nlData = {
    document: docDetails,
    encodingType: 'UTF8'
  };
  
  //  Package all of the options and the data together for the call
  var nlOptions = {
    method : 'post',
    contentType: 'application/json',
    payload : JSON.stringify(nlData)
  };
  
  //  And make the call
  var response = UrlFetchApp.fetch(apiEndpoint, nlOptions);
  Logger.log('json is :' + response)
  
return response;
  
}
```


### シートからテキストデータを取得して、APIコールする関数へ引き渡し、返り値を記入する関数

関数内で、先に記述した関数「retrieveSentiment」を呼び出す

getSentiment.gs

```javascript
// 取得したい開始行と終了行を記述
var start = '2';
var end = '5';

// シート情報取得
var mySheet = SpreadsheetApp.openById('シートのID').getSheetByName('シート名');

function getSentiment() {
  // 開始行と終了行でループを回す
  for (i = start; i <= end; i++) {
    var tweet = mySheet.getRange(i, 1).getValue();
    var response = retrieveSentiment(tweet);
    var json = JSON.parse(response);
    var score = json['documentSentiment']['score'];
    var magnitude = json['documentSentiment']['magnitude'];

    // 取得したScore Magnitudee,Jsonをシートに記述
    mySheet.getRange(i, 2).setValue(score);
    mySheet.getRange(i, 3).setValue(magnitude);
    mySheet.getRange(i, 4).setValue(response);
  }
}
```


## 実行結果

<img width="712" alt="nla_02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83767/1defc09e-238e-cefa-2fea-ef036287a90a.png">

scoreは、感情がポジティブかネガティブかを表す。０が中央値。マイナスだとネガティブ。
Magnitudeは、感情の振れ幅。この数値が大きいと、ポジティブ・ネガティブそれぞれの感情がより強い。

Score、Magnitude共に1を超えると、肯定的かつ感動度合いが大きい。画像の2行目がその例。
逆だと、否定的で感情的になっている。
と言えそうです。


## センチメント分析の難しさ

Scoreは、分析したテキスト全体から割り出しているため、複雑な文章だと正確な感情の抽出が難しい。

今回の例で言うと、シートの5行目。よく読むと、AAAに対する評価が非常に高く、好意的な感情を持っていることがわかるが、Scoreは 0.1 に止まっている。これは、文章全体の感情を平均化して出しているから。

特定の語句に対する正確なセンチメント分析を行おうとすると、エンティティ抽出が必要で、結構大変。

業務として使うには、手元の調整が必須な感じでした。

それはそれとして、非常に手軽にセンチメント分析ができ、面白いことに変わりはありません。