COTOHAを利用して、走れメロスの感情の経過に追走してみた。

#暴君ディオニス ： えいえいっ、おこった？
メロス ： おこってないよ！

「走れメロス」について[COTOHA](https://api.ce-cotoha.com/contents/index.html)の感情分析を用いて、読み解いていきたいと思います。

##処理の流れ
1.青空文庫より「走れメロス」の全文を取得
2.走れメロス全文を、COTOHA(感情分析)にかけていく。
3.感情の数値をグラフ化して分析してみる。


#事前準備
```python:青空文庫をクローン
!git clone --branch master --depth 1 https://github.com/aozorabunko/aozorabunko.git
```

#コード
<details><summary>1.青空文庫より「走れメロス」の全文を取得</summary><div>

```python:青空文庫より「走れメロス」全文取得
from bs4 import BeautifulSoup

def get_word():

  #クローンしたhtmlからパスを指定(走れメロス)
  path_to_html='aozorabunko/cards/000035/files/1567_14913.html'
  
  #BeautifulSoupでhtml解析
  with open(path_to_html, 'rb') as html:
    soup = BeautifulSoup(html, 'lxml')
  main_text = soup.find("div", class_='main_text')
  for yomigana in main_text.find_all(["rp","h4","rt"]):
    yomigana.decompose()
  sentences = [line.strip() for line in main_text.text.strip().splitlines()]
  aozora_text=','.join(sentences)

  aozora_text_list = aozora_text.split("。")
  return aozora_text_list
```
</div></details>
ローカルにクローンした青空文庫より「走れメロス」全文を取得。
また、このままではAPIにかけれない（文字数が多い）ので
句読点ごとに分割して配列化してます。



<details><summary>2.走れメロス全文を、COTOHA(感情分析)にかけていく。</summary><div>

```python:走れメロス全文を、COTOHA(感情分析)にかけていく。
mport os
import urllib.request
import json
import configparser
import codecs
import sys
import time


client_id = "各自のクライアントID"
client_secret = "各自のシークレットキー"

developer_api_base_url = "https://api.ce-cotoha.com/api/dev/nlp/"
access_token_publish_url = "https://api.ce-cotoha.com/v1/oauth/accesstokens"

def cotoha_call(sentence_1,api_type):
    # アクセストークン取得
    def getAccessToken():     
        url = access_token_publish_url
        headers={
            "Content-Type": "application/json;charset=UTF-8"
        }
        data = {
            "grantType": "client_credentials",
            "clientId": client_id,
            "clientSecret": client_secret
        }
        data = json.dumps(data).encode()
        req = urllib.request.Request(url, data, headers)
        res = urllib.request.urlopen(req)
        res_body = res.read()
        res_body = json.loads(res_body)
        access_token = res_body["access_token"]
        return access_token

    # API URL指定(固有表現抽出)
    base_url_footer = "v1/"  + api_type
    url = developer_api_base_url + base_url_footer
    headers={
        "Authorization": "Bearer " + getAccessToken(), #access_token,
        "Content-Type": "application/json;charset=UTF-8",
    }
    data = {
        "sentence": sentence_1
    }
    data = json.dumps(data).encode()
    time.sleep(0.5)
    req = urllib.request.Request(url, data, headers)
        
    try:
        res = urllib.request.urlopen(req)
    # リクエストでエラーが発生した場合の処理
    except urllib.request.HTTPError as e:
        # ステータスコードが401 Unauthorized or 500 Internal Server Errorならアクセストークンを取得し直して再リクエスト
        if e.code == 401 or 500:
            access_token = getAccessToken()
            headers["Authorization"] = "Bearer " + access_token
            time.sleep(0.5)
            req = urllib.request.Request(url, data, headers)
            res = urllib.request.urlopen(req)
        # 401 or 500 以外のエラーなら原因を表示
        else:
            print ("<Error> " + e.reason)
            #sys.exit()

    res_body = res.read()
    res_body = json.loads(res_body)
    return res_body


sentence = get_word()
end = len(a)
full_text = len(''.join(sentence))
sentiment_list = []
cnt = 0
wcnt = 0
for i in a:
  cnt+=1
  print(str(cnt)+ "/" + str(end))
  b = cotoha_call(i,"sentiment")
  sentiment_list.append([b['result']['sentiment'],b['result']['score'],i,wcnt])
  wcnt+=len(i)

```

</div></details>
配列化した「走れメロス」全文をCOTOHA（感情分析）に掛ける部分。
ちなみに句読点で、「走れメロス」全文を分割すると４６０個に分割されます。
つまり、４６０回APIをコールします。
（※COTOHAは無料枠だと1日各API１０００コールまでです。）


<details><summary>3.数値をグラフ化する。</summary><div>

```python:数値をグラフ化する。
# 数値計算に使うライブラリ
import numpy as np
import pandas as pd
import seaborn as sns

# グラフを描画するライブラリ
from matplotlib import pyplot as plt

# グラフをcolab内に表示させるための指定
%matplotlib inline

# グラフ用に値を調整
graph_x = []
graph_y = []
for i in sentiment_list:
  graph_x.append(i[3])
  if(i[0] == 'Negative'):
    tmp_y = (i[1] * -1) + (-1)
    graph_y.append(tmp_y)

  if(i[0] == 'Positive'):
    tmp_y = i[1]+1
    graph_y.append(tmp_y)
  
  if(i[0] == 'Neutral'):
    graph_y.append(i[1])

sns.set()

#plt.plot(x, y, color = 'black')
plt.figure(figsize=(40, 8), dpi=100)
plt.plot(graph_x, graph_y, color = 'red', marker = 'o', linestyle = '-', label = 'Sensor1')
#plt.xlim([0,5000])
plt.title("Run, Melos,")
plt.xlabel("Sentence")
plt.ylabel("Emotion")
```

</div></details>
matplotlibを使用して感情分析結果を折れ線グラフにしてます。
またCOTOHAにかけただけだと、ニュートラル、ネガティブ、ポジティブで区分されるだけで
値はすべて同じ0～1の範囲なのでグラフ用に、オフセットを設定してます。
ポジティブなら＋１
ネガティブなら値をマイナスにして+(－１)
ニュートラルなら何もしない。


#出力結果
**折れ線グラフ**
![meros_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586438/08cdb269-c321-9f1e-a863-2d37948b064d.png)

縦軸が感情で、横軸が各フレーズのテキスト位置です。
結構感情の振れ幅がありますね。

####ポジティブ側の分析


```:ポジティブなフレーズ上位No1〜3
[1.8126587191707609, '綺麗な衣裳も買って来た']
[1.6346889479386029, 'いまはご自分のお命が大事です'],
[1.633215237292569, '」その若い石工も、メロスの後について走りながら叫んだ']
```
２位、３位にスコア差をだいぶつけて、もっともポジティブなフレーズが**「綺麗な衣裳も買って来た」**ですね。

こちらは「メロス」が村へ帰った際の「メロス」と「妹」の会話の中の１フレーズですね。
村から遠路はるばる、走って市まで向かい、購入した衣裳を、妹に無事手渡すことができたのが、よっぽど嬉しかったんでしょう。（そもそもメロスの本来の目的ですしね。）

```:最もポジティブだと思われるフレーズの前後の文章(参考)
よろめいて歩いて来る兄の、疲労困憊こんぱいの姿を見つけて驚いた。そうして、うるさく兄に質問を浴びせた。
「なんでも無い。」メロスは無理に笑おうと努めた。「市に用事を残して来た。またすぐ市に行かなければならぬ。あす、おまえの結婚式を挙げる。早いほうがよかろう。」
　妹は頬をあからめた。
「うれしいか。綺麗きれいな衣裳も買って来た。さあ、これから行って、村の人たちに知らせて来い。結婚式は、あすだと。」
　メロスは、また、よろよろと歩き出し、家へ帰って神々の祭壇を飾り、祝宴の席を調え、間もなく床に倒れ伏し、呼吸もせぬくらいの深い眠りに落ちてしまった。
```

####ネガティブ側の分析

```:最もネガティブなフレーズ上位No1〜3
[-1.9459608426670426, 'その男を死なせてはならない']
[-1.939408157054805, '一刻といえども、むだには出来ない']
[-1.8666593927565555, 'ああ、陽が沈む']
```

１位、２位があまり、ネガティブなフレーズに見えず、しっくりきませんね。（「死なせて」、「むだ」このワードが原因となってるみたいです。）

なので、実質的な一番ネガティブなフレーズは、**「ああ、陽が沈む」**ですかね？

人質となっている、友人のセリヌンティウスを解放するため、時限までに全身全力で都に帰っている最中の一文ですね。

メロスの目前に複数の困難が立ちはだかるが、それを突破していき
ついに一度膝をつくも、様々な思考が巡り、再度立ち上がる描写のなかで
こうしている間にも時間は刻一刻と経過しているという部分の描写ですね。



```:最もネガティブだと思われるフレーズの前後の文章(参考)
走れ！　メロス。
　私は信頼されている。私は信頼されている。先刻の、あの悪魔の囁きは、あれは夢だ。悪い夢だ。忘れてしまえ。
五臓が疲れているときは、ふいとあんな悪い夢を見るものだ。メロス、おまえの恥ではない。
やはり、おまえは真の勇者だ。再び立って走れるようになったではないか。ありがたい！　
私は、正義の士として死ぬ事が出来るぞ。ああ、陽が沈む。ずんずん沈む。待ってくれ、ゼウスよ。
私は生れた時から正直な男であった。正直な男のままにして死なせて下さい。
```

####感情値をブロックで分析してみると・・
感情値のネガポジ、それぞれがまとまっている部分をブロックで見ると以下。
※上記に記述している、グラフ描写の部分を以下の散布図（scatter）に変えて実行。

```python:散布図表示
#plt.plot(graph_x, graph_y, color = 'red', marker = 'o', linestyle = '-', label = 'Sensor1')
plt.scatter(graph_x, graph_y, color = 'red', marker = 'o', linestyle = '-', label = 'Sensor1')
```

#####散布図
![meros_scat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586438/d968c1b3-11f4-8156-cac5-172d05d6ed0f.png)


#####最もポジティブな値が連続したブロック（オレンジで丸印をつけてる部分）

```:
義務遂行の希望である。
わが身を殺して、名誉を守る希望である。
斜陽は赤い光を、樹々の葉に投じ、葉も枝も燃えるばかりに輝いている。
日没までには、まだ間がある。私を、待っている人があるのだ。
少しも疑わず、静かに期待してくれている人があるのだ。
私は、信じられている。私の命なぞは、問題ではない。死んでお詫び、などと気のいい事は言って居られぬ。
私は、信頼に報いなければならぬ。いまはただその一事だ。
走れ！　メロス。
私は信頼されている。私は信頼されている。先刻の、あの悪魔の囁きは、あれは夢だ。悪い夢だ。忘れてしまえ。
五臓が疲れているときは、ふいとあんな悪い夢を見るものだ。メロス、おまえの恥ではない。
やはり、おまえは真の勇者だ。再び立って走れるようになったではないか。
ありがたい！　私は、正義の士として死ぬ事が出来るぞ。
```

一度、膝をついたメロスが、再度立ち上がる際の描写ですね。
感情の高まりが読んでとれます。
（ちなみに補足すると、上記で記述している、最もネガティブなフレーズの直前の文章です。）


#####最もネガティブな値が連続したブロック（ブルーで丸印をつけてる部分）

```:
そうなったら、私は、死ぬよりつらい。私は、永遠に裏切者だ。地上で最も、不名誉の人種だ。
セリヌンティウスよ、私も死ぬぞ。君と一緒に死なせてくれ。君だけは私を信じてくれるにちがい無い。
いや、それも私の、ひとりよがりか？　ああ、もういっそ、悪徳者として生き伸びてやろうか。
村には私の家が在る。羊も居る。妹夫婦は、まさか私を村から追い出すような事はしないだろう。
```

友人のセリウンティウスを助けることを諦めようとする際の描写部分ですね。
確かに、投げやりになってますね。（このあと四肢を投げ出して、うとうと、まどろんでしまいます。）


#まとめ
~~ポジティブの感情値から読み取るに、メロスはシスコンだと思いました。~~

簡単にですが、感情分析を用いて「走れメロス」を読み解いてみました
こうやって文章を読んでいくのもなかなか面白いなと。

以上です。ここまで、ご一読ありがとうございました。