Excelで誰でも簡単言語処理 (感情推定, 固有表現抽出, キーワード抽出,  文類似度推定 etc...)

# 3行まとめ
- Excel関数一発で高度な言語処理を使えるようにしました
- 感情推定、固有表現抽出など日本語を分析・整理するのにいろいろ使えます 
- Windows + Officeユーザならマクロファイルで誰でも簡単に使えます 

※Macだと多分動かないと思います。VBAのHTTPリクエストを有効にできないため。。。

> 9/1追記: コメント頂きましたが、64bit版OfficeだとjsonParseが動かないようなのでアップデートしてみました。動作確認できていないので自己責任でお願いします
>https://github.com/korinzuz2/excelcotoha/blob/master/COTOHA公開用64bitExcel対応版.xlsm

# はじめに
MicrosoftのExcel って使ってますか？

エンジニアには馬鹿にされがちな気もするExcelですが、
とあるアンケート調査によると国内就業者の実に**93.4％**もの方が**「業務においてExcelは重要」**と答えているそうです。[^1]

日本の業務はExcelで回っていると言っても過言ではない割合ではないでしょうか。

今回はそんなExcelで様々な言語処理を扱えるようにしてみました。
WindowsでExcelを使っている方ならファイルをダウンロードすれば(多分)簡単に使えます！！

#ユースケース例

例えば、お客様の声がたくさん集まったので分析したい・・・という場面を想像してください。
![example4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287075/e5a41186-43d2-4999-c69f-ac95db28fd33.png)
こんな感じで沢山のコメント[^2]が集まっているのですが、一つ一つ中身を見て分析するのは面倒です。そんなときは横のセルに、 `=easyCotohaSentiment(分析したいセル,$B$3)`と入力してみましょう
![example3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287075/e0ee3c38-424a-f6a3-c0ec-644a3826aa63.png)

あっという間にPositiveかNegativeかをそのスコアとともに判定してくれました！[^3]

#他に作ったもの
### 固有表現抽出
解析したい文をセルに書き、easyCotohaNeという関数でそのセルを引数に指定すると、固有表現を抽出します
![easyCotohaNe.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287075/3c1e999c-b1f6-107d-470f-a30939f929b2.png)
### キーワード抽出
上記同様、easyCotohaKeywordという関数でセルを引数に指定すると、キーワードを抽出します。
![easyCotohaKeyword.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287075/2964ba29-ea08-244d-8b3c-e2d4ac7994f6.png)
### 類似度算出
easyCotohaSimilarityという関数で類似度を比較したいセルを２つ指定すると、類似度を算出します。[^4]
![easyCotohaSimilarity.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287075/41c44a01-1c7a-9038-95ae-ccdcdd77266b.png)
### その他
使い方はやや複雑になりますが、他にも下記リンクの言語処理系の機能は全て使えるようにしています。
[COTOHA API](https://api.ce-cotoha.com/contents/index.html#api)
例えば構文解析を使えば以下のように形態素解析+読みがな生成などもできます。
![parse.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287075/29bbcbc1-cc3a-e20b-87a6-d49727542d10.png)


#使い方

### 1.[COTOHA API](https://api.ce-cotoha.com/contents/index.html)に登録する
今回の言語処理は[COTOHA API](https://api.ce-cotoha.com/contents/index.html)を使っているため、まず登録します。
for Deveropersという無料プランがあるのでそちらを申し込みます。[^5]
Developer Client id、Developer Client secretという２つのキーがもらえるので、控えておきます。

### 2. マクロ入りエクセルファイルをダウンロードする
下記からダウンロード (Downloadと書かれたボタンをクリック)
https://github.com/korinzuz2/excelcotoha/blob/master/COTOHA%E5%85%AC%E9%96%8B%E7%94%A8.xlsm

> 9/1追記
> 64bit版Officeだとjson解釈のところがうまく動かないようなので、以下をダウンロードください
> https://github.com/korinzuz2/excelcotoha/blob/master/COTOHA公開用64bitExcel対応版.xlsm

### 3. ダウンロードしたブックを開き、マクロを有効化する
開くと警告ウインドウなりでマクロを有効化するか聞かれるので、有効にするをクリック

### 4. HTTPリクエストを有効にする
Excelを開いた状態でAlt + F11するとウインドウが立ち上がるので
そのツールバーからツール→参照設定で「Microsoft XML v6.0」というものにチェックを入れます。

### 5. 項番1で得たキーを書き込む
シートのB1, B2セルに項番1で発行されたClient id、Client secretを書き込みます。
書き込むとしばらくして、様々なサンプルの解析結果が表示されます。
※サンプルは色々やってるので時間がかかると思います。適宜削ってお使いください。

# 中身の解説

やっていることはVBAでCOTOHA APIにPOSTしてレスポンスを解釈しているだけです。

### 1. アクセストークンを取得する
`=getAccessToken(B1,B2)`という関数を使って、COTOHA APIにkeyとsecretをPOSTすることでアクセストークンを取得します。(ファイルだとB3セルで実施しています。)

<details><summary>getAccessToken (クリックで展開)</summary><div>


```visualbasic
Function getAccessToken(ByVal clientId As String, ByVal clientSecret As String) As String

  Dim url As String
  url = "https://api.ce-cotoha.com/v1/oauth/accesstokens"
  
  Dim paramStr As String: paramStr = "{""grantType"":""client_credentials"",""clientId"":""" & clientId & """,""clientSecret"":""" & clientSecret & """}"
  
  Dim req As XMLHTTP60: Set req = New XMLHTTP60
  
  With req
        .Open "POST", url
        .setRequestHeader "Content-Type", "application/json"
        .setRequestHeader "charset", "utf-8"
        .send paramStr
  End With
  
  Dim obj As Object
  Dim json As Object

  Set obj = CreateObject("ScriptControl")
  obj.Language = "JScript"
  obj.addcode "function jsonParse(s){ return eval('('+s+')');}"

  Set json = obj.CodeObject.jsonParse(req.responseText)
  
  getAccessToken = CallByName(json, "access_token", VbGet)
  
  Set req = Nothing
 
End Function
```

</div>

### 2. COTOHAの各APIにPOSTしてjsonを取ってくる

例えば `=cotohaSentiment()`は、解析したい文と項番1のアクセストークンをCOTOHA APIの感情推定APIにPOSTしてそのレスポンス(json形式)を返します。

<details><summary>cotohaSentiment (クリックで展開)</summary><div>

```visualbasic

Function cotohaSentiment(ByVal document As String, ByVal accessToken As String) As String
  Dim url As String
  url = "https://api.ce-cotoha.com/api/dev/nlp/v1/sentiment"
  
  Dim paramStr As String: paramStr = "{""sentence"":""" & document & """}"

  Dim req As XMLHTTP60: Set req = New XMLHTTP60
  
  With req
        .Open "POST", url
        .setRequestHeader "Content-Type", "application/json"
        .setRequestHeader "charset", "utf-8"
        .setRequestHeader "Authorization", "Bearer " & accessToken
        .send paramStr
  End With
  cotohaSentiment = req.responseText
  Set req = Nothing
  
End Function

```

</div>

### 3. 返ってきたjson形式のレスポンスから情報を抽出する

COTOHA APIは様々な解析結果を返してくるので、適宜取捨選択して表示します。
たとえば最初に例として挙げた `=easyCotohaSentiment()` なら、
"emotional_phrase"という感情を表す語が何か、というのが本来解析結果に含まれるのですが、今回はそれを無視して、感情がPositiveかNegativeか、とそのスコアについてのみ抽出して表示するようにしています。

<details><summary>easyCotohaSentiment (クリックで展開)</summary><div>

```visualbasic

Function easyCotohaSentiment(ByVal document As String, ByVal accessToken As String) As String
  
  Dim obj As Object
  Dim response As String
  Dim json As Object
  Dim result As String
  
  ' json形式でキーワード抽出結果を取得
  response = cotohaSentiment(document, accessToken)
  
  ' jsonを解析
  Set obj = CreateObject("ScriptControl")
  obj.Language = "JScript"
  obj.addcode "function jsonParse(s){ return eval('('+s+')');}"
  Set json = obj.CodeObject.jsonParse(response)
  
  ' sentimentとscore値を取り出しカンマ区切りで連結
  result = CallByName(CallByName(json, "result", VbGet), "sentiment", VbGet) + ","
  result = result + CStr(CallByName(CallByName(json, "result", VbGet), "score", VbGet))
  easyCotohaSentiment = result

End Function

```

> 9/1追記:64bit版OfficeだとScriptControlが動かせないようなので、対応版では以下を実施しています。

```

Function easyCotohaSentiment(ByVal document As String, ByVal accessToken As String) As String
  
  Dim doc
  Dim response As String
  Dim json As Object
  Dim result As String
  
  ' json形式でキーワード抽出結果を取得
  response = cotohaSentiment(document, accessToken)
  
  ' jsonを解析
  Set doc = CreateObject("HtmlFile")
  'JSONオブジェクトを使うにはIEの互換表示で8以上(edgeも可)にする。
  doc.write "<meta http-equiv='X-UA-Compatible' content='IE=8' />"
  'scriptタグを追加
  'パースはJSON.parseを使うとチェックが厳しいのでevalを使う。
  doc.write "<script>document.JsonParse=function (s) {return eval('(' + s + ')');}</script>"
  doc.write "<script>document.JsonStringify=JSON.stringify;</script>"
  
  Set json = doc.JsonParse(response)
  
  ' sentimentとscore値を取り出しカンマ区切りで連結
  result = CallByName(CallByName(json, "result", VbGet), "sentiment", VbGet) + ","
  result = result + CStr(CallByName(CallByName(json, "result", VbGet), "score", VbGet))
  easyCotohaSentiment = result

End Function

```

</div>

また、これらの`easy〜`の関数を使わずとも、前述した構文解析のようにExcelのFIND関数やMID関数を駆使してjsonから無理やり情報抽出することも可能です。
Excelの別シートにそれらの例もいろいろと記載してみたので、よろしければ使ってみてください。

# まとめ

以上、Excelで言語処理をやってみました。
エンジニアとして「わざわざExcelでやる必要はないだろ」とはちょっと思うのですが、やってみると意外と結果がわかりやすく表示されるのでこれはこれで楽しかったりします。
また、営業さんだろうがお偉いさんだろうが普段コードを全く書かないという人にも触ってもらえる可能性があるので、言語処理の間口を広げるのには案外良いかなと思ったりもします。

あと、実体験上、業務用のPCだとセキュリティだ何だでコードがまともに書けなかったりインストールができなかったりしますが、Excelのマクロは案外許容されてたりします。インターネットにさえ繋がっていれば言語処理ができるというのは無視できない利点なのかもしれない・・・。

　


[^1]: [Excelに関するアンケート](https://prtimes.jp/main/html/rd/p/000000032.000007838.html) (株式会社わかるとできる 調査期間：2016年1月26日～2016年1月27日 調査方法：インターネット調査 調査対象：現在就業している20～59歳の男女562名 )
[^2]: 「人間失格」 太宰 治 (1948) [青空文庫](https://www.aozora.gr.jp/cards/000035/card301.html)
[^3]: 色は条件付き書式。Positive or Negativeが含まれてたら色変える、としてるだけ。
[^4]: 類似度は0.0-1.0で判定。今回は0.87なのでかなり似ている、という意味。詳しくは→[類似度算出API](https://api.ce-cotoha.com/contents/reference.html#api-Similarity)
[^5]: 1日各API1000回まで。それを超えると翌日までエラーになる。