テキスト解析 AI サービス Amazon Comprehend で本を読まずに読書感想文に挑戦してみる

2020-07-02
デベロッパーのためのクラウド活用方法

Author : 呉 和仁

Builder な皆様、こんにちは!機械学習ソリューションアーキテクト呉です。いかがお過ごしでしょうか。

日に日に暑さが増してきておりますね。暑くなると皆様は何を思い出しますか ?
私は夏休みの読書感想文を思い出します。
本を読むのが大嫌いだった私は、苦痛で仕方がありませんでした。

そんなことを思い出したら、
「Amazon Comprehendを使えば、本を読まずに読書感想文を書けるのでは !?」
と、思ったので試してみました。


Amazon Comprehend とは ?

Amazon Comprehend は、機械学習を使用してテキスト内でインサイトや関係性を検出する自然言語処理(NLP)サービスです。

…と言われてもピンと来ない方もいらっしゃるかと思いますので、何ができるかをもう少し具体的にご紹介いたします。

よく使われる主要な機能は下記 5 つです。

エンティティ認識

エンティティは固有表現とも呼ばれ、固有名詞や組織、日付などを指します。これらは、文章を理解する上で特徴的なキーワードとなることがあるため、エンティティを認識して文章の理解に役立てます。

キーフレーズ抽出

Amazon Comprehend では、修飾語と名詞からなるフレーズのうち特徴的なものをキーフレーズとして抽出します。例えば、「風景」という名詞だけでなく「美しい風景」といった名詞句を抽出します。

言語検出

使用している言語を検出します。 

感情分析

テキストの全体的な感情(混在・肯定的・否定的・中立的)の度合いを分析します。 

構文解析

テキストに利用される各単語の品詞を特定します。 

具体的にどのように使えるか、エンティティ抽出を例にご紹介します。

エンティティの抽出の例

では AWS にログインして、Amazon Comprehend のコンソールからエンティティを抽出してみましょう。

左側のメニューの Real-time Analysis から Input text のところに文章を入力します。すると、このように「Amazon.com, Inc」「Seatle, WA」など組織や、場所、日付、人物など、エンティティの抽出を簡単に行うことができます。

img_comprehend-readingimpressions_01

エンティティの抽出の例 

AWS のマネジメントコンソールをご利用の場合は、「Entities」タブの隣に並んでいる、「Key phrases」「Language」「Sentiment」「Syntax」タブをクリックするだけで、それぞれキーフレーズ抽出、言語検出、感情分析、構文解析を行うことが可能です。

また、トピックモデルを扱うことが可能で、例えばスポーツや娯楽といった、テキストのベースとなるトピックを認識し、それに関するキーワードを抽出することもできます。
それぞれの機能を実行する際は、AWS マネジメントコンソールの GUI から実行することもできますし、各種 SDK や AWS コマンドラインインターフェース (CLI) からもご利用いただけます。

これらを利用すれば、本を読まなくてもなんとなく書かれている内容を理解できそうな気がします。


Amazon Comprehend の最近のアップデート

本題に入る前に、 Amazon Comprehend のアップデートについて簡単にご紹介いたします。

  1. Amazon Aurora から Amazon Comprehend を利用して 感情分析が可能に
    Amazon Aurora で実行可能な SQL において、Amazon Comprehend の感情分析を実行する関数が用意されました。

    感情分析を実施したいテキストが Amazon Aurora に格納されている場合、以前は、事前に SQL でそのテキストを抽出して、別個に感情分析にかける必要がありました。このアップデートによって、Amazon Aurora データベースにテキストを格納したまま SQL を用いて直接感情分析を実施できるようになりました。

    実行方法は SQL で aws_comprehend_detect_sentiment 関数を呼び出すだけで利用することが可能です。詳細はこちらをご参照ください。

  2. カスタム分類子とカスタムエンティティ
    Amazon Comprehend でユーザーがデータを用意することで、カスタマイズすることができます。

    a. カスタム分類子
    テキストを任意のクラスに分類することが可能です。2020 年 6 月時点では日本語には対応しておりません。
    例えばチャットボットのログがあった場合、それぞれのテキストに対して「Inquiries about products」「Request for repair」「Opinions」等のラベル付けした上で、Amazon Comprehend のカスタム分類子の学習を行うことで、以降、新しいチャットの内容を上記のラベルに分類できるようになります。詳しくはこちらをご参照ください。

    b. カスタムエンティティ
    これまでのエンティティの抽出だと、例えば人の名前があった場合は、Person と抽出することが可能ですが、その人物が何者なのか、というのはわかりません。カスタムエンティティを利用して、人の名前とラベルのペア(例: Josef Brown, ENGINEER)と、またその人の名前を用いた文章を用意して学習させると、以降、「Josef Brown」を「ENGINEER」として認識できるようになります。これは人に限った話ではなく、「123-ABC, PRODUCT_CODE」のようなラベルを覚えさせると、 123-ABC を PRODUCT_CODE として認識できるようになります。2020 年 6 月時点では英語のみ対応しています。詳しくはこちらをご参照ください。

  3. Amazon Comprehend Medical
    医療情報に特化した文章分析を行うことが可能です。例えば、医療においては、「Methicillin-resistant Staphylococcus aureus」を「MRSA」と略すことが多いですが、自動で「MRSA」を「Methicillin-resistant Staphylococcus aureus」と認識することが可能です。その他、患者情報の保護機能や、医療オントロジーリンク API の提供など、様々な機能を持っております。2020 年 6 月時点では英語のみ対応しています。詳しくはこちらをご参照ください。

読書感想文に必要な情報を Amazon Comprehend で抽出してみる

さて前置きが長くなりましたが、本題である「本を読まずに読書感想文を書く」に挑戦してみたいと思います。 AI サービスといえど、原文データが手に入らなければ何もできないので、まずは原文データを入手してみます。 

文章の抽出

今回は皆様よくご存知の「走れメロス」を題材にしてみたいと思います。
青空文庫で「走れメロス」を閲覧可能ですので、まずは見てみましょう。
こちらから入手可能です

さて、ここからマウスで必要な部分をコピーしてテキストエディタに貼り付け…ると、ふりがなのルビが邪魔をしてしまいます。漢字の後にふりがなが表示されてしまいますね。

必ず、かの 邪智暴虐じゃちぼうぎゃく の王を覗かなければならぬと決意した。

ここは一つ、html をパースして、ルビを除去してみましょう。
python の HTMLParser を利用してみます。

import requests
from html.parser import HTMLParser

class MyHTMLParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.text = ""
        self.extract = False
        
    def handle_starttag(self, tag, attrs):
        if tag == "div":
            self.extract = True
        elif tag in ["rp","rt"]:
            self.extract = False

    def handle_endtag(self, tag):
        if tag in ["rp","rt"]:
            self.extract = True
        elif tag == "div":
            self.extract = False

    def handle_data(self, data):
        if self.extract:
            self.text += data
URL = "https://www.aozora.gr.jp/cards/000035/files/1567_14913.html"
response = requests.get(URL)
response.encoding = response.apparent_encoding
response.text
parser = MyHTMLParser()
parser.feed(response.text)
print(parser.text)

出力結果

走れメロス
太宰治



 メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。
…
(中略)
…
 勇者は、ひどく赤面した。
(古伝説と、シルレルの詩から。)


底本:「太宰治全集3」ちくま文庫、筑摩書房
   1988(昭和63)年10月25日初版発行
…
(以下略)

さて、ルビは除去出来ていい感じに抽出できましたが、最初にタイトルと著者、最後に発行年数といった、本文ではない部分も抽出されています。ここはハードコーディングで不要な部分を削ってみましょう。 

text = parser.text.replace("\r","").replace("\n","").replace("\u3000","").replace("(古伝説と、シルレルの詩から。)底本:「太宰治全集3」ちくま文庫、筑摩書房1988(昭和63)年10月25日初版発行1998(平成10)年6月15日第2刷底本の親本:「筑摩全集類聚版太宰治全集」筑摩書房1975(昭和50)年6月〜1976(昭和51)年6月入力:金川一之校正:高橋美奈子2000年12月4日公開2011年1月17日修正青空文庫作成ファイル:このファイルは、インターネットの図書館、青空文庫(http://www.aozora.gr.jp/)で作られました。入力、校正、制作にあたったのは、ボランティアの皆さんです。●表記について    このファイルは W3C 勧告 XHTML1.1 にそった形式で作成されています。●図書カード","").replace("走れメロス太宰治","")
print(text)

出力結果

メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。
(中略)
勇者は、ひどく赤面した。

これで必要な文章だけを抽出できました。
文章を全部まとめて Amazon Comprehend にかけてもあまりいい結果は出ないと思うので、句点で文章を区切ってリスト形式にしてみましょう。また、鉤括弧も不要ですので、併せて除去してみましょう。

sentences = text.replace("「","").replace("」","").split("。")[:-1]
print(sentences)

出力結果

['メロスは激怒した', '必ず、かの邪智暴虐の王を除かなければならぬと決意した', …(中略)…, '勇者は、ひどく赤面した']

これで 1 文ずつAmazon Comprehend にかけられるようになりました。 

エンティティの抽出で主要な登場人物を把握してみる

まずは登場人物を把握したいと思います。
Amazon Comprehend にはエンティティを認識する API があり、そのレスポンスにはエンティティの種類が入っております。エンティティが “Person” のものだけを抽出してみましょう。
まずは python から Amazon Comprehend API を実行できるよう、 boto3 の comprehend クライアントを生成します。

import boto3
comprehend_client = boto3.client("comprehend")

次にエンティティ認識してみましょう。 detect_entities というメソッドでエンティティを認識することができます。きっと主要人物は何回も登場するため、併せてカウントを取ってみます。 

from collections import defaultdict
characters = defaultdict(int)
for i,sentence in enumerate(sentences):
    entities_response = comprehend_client.detect_entities(Text=sentence,LanguageCode="ja")
    for entity in entities_response["Entities"]:
        if entity["Type"] == "PERSON":
            characters[entity["Text"]] += 1
print(sorted(characters.items(), key=lambda x:x[1],reverse=True))

出力結果

[('メロス', 70), ('セリヌンティウス', 15), ('王', 11), ('ディオニス', 3), ('竹馬', 1), ('アレキス', 1), ('きょう', 1), ('南無三', 1), ('えい', 1), ('飛鳥', 1), ('やはり', 1), ('フィロストラトス', 1)]

メロスが 70 回、セリヌンティウスが 15 回、王が 11 回なのでこの 3 人が主要人物で間違いないですね。
また 70 回という 2 位のセリヌンティウスと比べて 5 倍近い登場回数であるメロスが主人公で間違いないでしょう。
たった 8 行のコードを書くだけで主人公を捉えることができました。読書感想文が書けそうな気がしてきましたね !

主要登場人物のストーリーを把握する

各登場人物に何が起きたのか見てみましょう。主要登場人物である、メロス、セリヌンティウス、王をエンティティに含む文章に、それぞれキーフレーズの抽出を行ってみます。 detect_key_phrases というメソッドでキーフレーズを抽出できます。また、併せて感情分析もしてみます。感情分析は detect_sentiment というメソッドで分析できます。 

メロス編

まずはメロスのキーフレーズを抽出します。 

melos_key_phrases = []
for i,sentence in enumerate(sentences):
    entities_response = comprehend_client.detect_entities(Text=sentence,LanguageCode="ja")
    for entity in entities_response["Entities"]:
        if entity["Type"] == "PERSON":
            if entity["Text"] == "メロス":
                key_phrases_response = comprehend_client.detect_key_phrases(Text=sentence,LanguageCode="ja")
                for key_phrase in key_phrases_response["KeyPhrases"]:
                    if key_phrase["Text"] != "メロス":
                        melos_key_phrases.append(key_phrase["Text"])
print(melos_key_phrases)

出力結果

['政治', '村の牧人', 'きょう未明', '村', '野', '十里', '此のシラクスの市', '父', '母', 'それゆえ、花嫁の衣裳やら祝宴の御馳走やらを買い', 'はるばる市', 'うち', 'まちの様子', '両手', '老爺のからだ', '質問', '男', 'メロスの懐中', '短剣', '騒ぎ', '王の前', 'こんど', '足もと', '視線', '瞬時', '私', '情', 'つもり', '処刑', '三日間の日限', '必死', '地団駄', '友', '一切の事情', 'セリヌンティウス', '無言', '首肯き', 'その夜', '一睡', '十里の路', '村', '翌る日の午前', '陽', '村人たち', '野', '仕事', 'メロスの十六の妹', 'きょう', '兄の代り', '羊群の番', '家', '神々の祭壇', '祝宴の席', '床', '呼吸', '眠り', '花婿の家', '明日', 'くれ', '満面', '喜色', '王とのあの約束', '一生', 'このまま', 'ここ', 'わが身', '出発', 'メロスほどの男', 'やはり', '未練の情というもの', '花婿の肩', '仕度', 'お互', 'もう一つ', 'メロスの弟', '村人たち', '宴席', '羊小屋', '南無三', '約束の刻限', '十分', '間に合う', '悠々', '身仕度', '両腕', '雨中', '矢', '額の汗', 'こぶし', 'ここ', '大丈夫', '故郷への未練', '二里', '三里', '全里程の半ば', '頃', '災難、メロスの足', '川岸', '男泣き', 'ゼウス', '手', '濁流', 'メロスの叫び', 'ざんぶと', '流れ', '百匹の大蛇のようにのた打ち荒れ狂う', '浪を相手', '必死の闘争', '馬', '大きな胴震い', '一つ', '先き', 'からだ', '飛鳥', '身近かの一人', 'その棍棒', '気の毒', '正義のため', '猛然', '一撃', '三人', '者', '隙', '峠', '一気に', '峠', '流石', '折から午後の灼熱の太陽', '幾度', '眩暈', 'これではならぬ', '気', '二', '三歩', 'くり', '膝', 'ああ、あ、', '濁流', '山賊', '三人', '倒し', '韋駄天、ここ', 'その泉', '身', 'メロス、おまえの恥', '路', '人', '風', '急げ、メロス', 'いま', 'ほとんど全裸体', 'ああ、メロス様', 'その', '石工', 'メロスの後', '胸', '思い', '夕陽', '王様', 'さんざん', 'あの方', '信念', '様子', '最後の死力', 'メロスの頭', 'からっぽ', '陽', '地平線', '最後の一片の残光', '時', '疾風', '如く刑場', 'それ', '最後の勇、先刻、濁流', '群衆', '私', '刑吏', '私', '眼', '涙', 'セリヌンティウス', 'すべて', '様子で', '首肯き', '刑場一ぱい', 'メロスの右頬', '微笑み', 'メロス、私', '腕', '唸り', 'セリヌンティウスの頬', 'メロス、君', 'この可愛い娘さん', 'メロスの裸体', '皆']

これだけで、メロスのストーリーがわかりそうですが、続いて感情分析をかけてみましょう。Positive と Negative の度合いを数値で返す detect_sentiment を利用して、それぞれの度合いをストーリー順にプロットしてみます。 

melos_positive = []
melos_negative = []
for i,sentence in enumerate(sentences):
    entities_response = comprehend_client.detect_entities(Text=sentence,LanguageCode="ja")
    for entity in entities_response["Entities"]:
        if entity["Type"] == "PERSON":
            if entity["Text"] == "メロス":
                melos_sentiment_response = comprehend_client.detect_sentiment(Text=sentence,LanguageCode="ja")
                melos_positive.append(melos_sentiment_response["SentimentScore"]["Positive"])
                melos_negative.append(melos_sentiment_response["SentimentScore"]["Negative"])
from matplotlib import pyplot as plt
fig = plt.figure(figsize=(16.0, 10.0))
plt.plot(melos_positive,color="green")
plt.plot(melos_negative,color="red")

グラフの横軸はストーリーの順番、縦軸はそのテキストの感情の値です。最初から Negative 全開ですね…。またメロスがエンティティとして登場すると、 Negative な感情の上下が激しく、だいぶ情緒不安定です。小説は感情の揺れ動きが重要なため、「走れメロス」以外もそんなものなのかもしれませんね。最後のほうは Positive が目立つので、おそらくハッピーエンドだったのではないでしょうか。 

img_comprehend-readingimpressions_02

セリヌンティウス編

次にセリヌンティウスのキーフレーズを検出してみます。

selinuntius_key_phrases = []
for i,sentence in enumerate(sentences):
    entities_response = comprehend_client.detect_entities(Text=sentence,LanguageCode="ja")
    for entity in entities_response["Entities"]:
        if entity["Type"] == "PERSON":
            if entity["Text"] == "セリヌンティウス":
                key_phrases_response = comprehend_client.detect_key_phrases(Text=sentence,LanguageCode="ja")
                for key_phrase in key_phrases_response["KeyPhrases"]:
                    if key_phrase["Text"] != "セリヌンティウス":
                        selinuntius_key_phrases.append(key_phrase["Text"])
print(selinuntius_key_phrases)

出力結果

['私', 'この市', 'セリヌンティウスという石工', '竹馬の友', '深夜', '王城', '無言', '首肯き', 'メロス', 'セリヌンティウス、', '私', '私', '貴方のお友達セリヌンティウス様の弟子', '磔の柱', '縄', 'セリヌンティウスの縄', 'すべて', '様子で', '首肯き', '刑場一ぱい', 'メロスの右頬', 'メロス', '腕', '唸り', 'セリヌンティウスの頬']

エンティティの登場回数がメロスの 約 5 分の 1 とあって、セリヌンティウスのキーフレーズもメロスと比べるとずいぶん少ないです。メロス同様、セリヌンティウスも感情分析してみます。 

selinuntius_positive = []
selinuntius_negative = []
for i,sentence in enumerate(sentences):
    entities_response = comprehend_client.detect_entities(Text=sentence,LanguageCode="ja")
    for entity in entities_response["Entities"]:
        if entity["Type"] == "PERSON":
            if entity["Text"] == "セリヌンティウス":
                selinuntius_sentiment_response = comprehend_client.detect_sentiment(Text=sentence,LanguageCode="ja")
                selinuntius_positive.append(selinuntius_sentiment_response["SentimentScore"]["Positive"])
                selinuntius_negative.append(selinuntius_sentiment_response["SentimentScore"]["Negative"])
from matplotlib import pyplot as plt
fig = plt.figure(figsize=(16.0, 10.0))
plt.plot(selinuntius_positive,color="green")
plt.plot(selinuntius_negative,color="red")

前半は Positive が多めですが、物語後半に行くにしたがって Negative が乱高下しています。物語がクライマックスに向かっていくに従い、メロスがセリヌンティウスを怖がらせたり落ち着かせたりしているのでしょうか。 

img_comprehend-readingimpressions_03

王編

最後に王です。まずはキーフレーズから。 

king_key_phrases = []
for i,sentence in enumerate(sentences):
    entities_response = comprehend_client.detect_entities(Text=sentence,LanguageCode="ja")
    for entity in entities_response["Entities"]:
        if entity["Type"] == "PERSON":
            if entity["Text"] == "王":
                key_phrases_response = comprehend_client.detect_key_phrases(Text=sentence,LanguageCode="ja")
                for key_phrase in key_phrases_response["KeyPhrases"]:
                    if key_phrase["Text"] != "王":
                        king_key_phrases.append(key_phrase["Text"])
print(king_key_phrases)

出力結果

['その王の顔', '眉間の皺', 'おまえ', '民の忠誠', '顔', 'ああ、王', 'それ', '気持', '北叟笑ん', '王の命令', 'ここ', '私', 'おまえは、稀代の不信の人間、まさしく王の', '壺', '自分', '全身', '芋虫', '私', '耳打ち', '今', '私', '王の言うまま', '私', '事', '私']

「稀代の不信の人間」など罵っているような言葉がありますね。王は悪役なのでしょうか。
感情も確認してみましょう。

king_positive = []
king_negative = []
for i,sentence in enumerate(sentences):
    entities_response = comprehend_client.detect_entities(Text=sentence,LanguageCode="ja")
    for entity in entities_response["Entities"]:
        if entity["Type"] == "PERSON":
            if entity["Text"] == "王":
                king_sentiment_response = comprehend_client.detect_sentiment(Text=sentence,LanguageCode="ja")
                king_positive.append(king_sentiment_response["SentimentScore"]["Positive"])
                king_negative.append(king_sentiment_response["SentimentScore"]["Negative"])
from matplotlib import pyplot as plt
fig = plt.figure(figsize=(16.0, 10.0))
plt.plot(king_positive,color="green", label="positive")
plt.plot(king_negative,color="red", label="negative")
plt.legend(bbox_to_anchor=(1, 1), loc='upper right', borderaxespad=0, fontsize=18)

王は Negative 要素が強い、かつ「稀代の不信の人間」ともあったので悪役なのでしょう。しかし、最後に一気に Positive になり、メロスも最後 Positive で終わっていたので、きっと改心してハッピーエンドで終わったのではないでしょうか。

img_comprehend-readingimpressions_04

さて、これまでメロスとセリヌンティウスと王の、キーフレーズと感情を別個に見ることで、ストーリーが進むに従ってどのような感情を持ち、どんなイベントがあったかがわかってきました。しかし、各人を別個で見たため、3人のキーフレーズや感情が同期していません。例えばメロスの Positive が高まったときに、セリヌンティウスの感情がどうなっているのか、がわからないです。そこで、これらのキーフレーズと感情分析の結果を、同期させて理解しやすくしてみたいと思います。

同期させて理解するのに、一つ問題があります。メロスやセリヌンティウス、王が必ずしも文のエンティティとして出てくるとも限らないため、エンティティとして登場していない人の感情がわかりません。その場合は直前の感情を維持することとしてみましょう。登場人物 3 人の感情とキーフレーズを同時にグラフに表示してみます。

key_phrases = []
positives = {"メロス":[],"セリヌンティウス":[],"王":[]}
negatives = {"メロス":[],"セリヌンティウス":[],"王":[]}
entity_include_sentence_idx = []
for i,sentence in enumerate(sentences):
    entities_response = comprehend_client.detect_entities(Text=sentence,LanguageCode="ja")
    entities = []
    in_use = False
    for entity in entities_response["Entities"]:
        if entity["Text"] in ["メロス","セリヌンティウス","王"]:
            in_use = True
            entities.append(entity["Text"])
        if len(entities) >= 1:
            sentiment_response = comprehend_client.detect_sentiment(Text=sentence,LanguageCode="ja")
            for person in ["メロス","セリヌンティウス","王"]:
                if person in entities:
                    positives[person].append(sentiment_response["SentimentScore"]["Positive"])
                    negatives[person].append(sentiment_response["SentimentScore"]["Negative"])
                else:
                    # エンティティとして登場しない場合の処理
                    if positives[person] == []:
                        # 最初は 0
                        positives[person].append(0)
                        negatives[person].append(0)
                    else:
                        # 直前の感情で補完
                        positives[person].append(positives[person][-1])
                        negatives[person].append(negatives[person][-1])
    if in_use:
        entity_include_sentence_idx.append(i)
key_phrases = []
for i in entity_include_sentence_idx:
    key_phrases_response = comprehend_client.detect_key_phrases(Text=sentences[i],LanguageCode="ja")
    temp_key_phrase = ""
    for key_phrase in key_phrases_response["KeyPhrases"]:
        temp_key_phrase = temp_key_phrase + "\n" + key_phrase["Text"]
    key_phrases.append(temp_key_phrase)
import matplotlib as mpl

mpl.rcParams['font.family']='IPAexGothic'
fig = plt.figure(figsize=(16.0, 10.0))
plt.plot(positives["メロス"],color="green", label="メロスP")
plt.plot(negatives["メロス"],color="red", label="メロスN")
plt.plot(positives["セリヌンティウス"],color="blue", label="セリヌンティウスP")
plt.plot(negatives["セリヌンティウス"],color="orange", label="セリヌンティウスN")
plt.plot(positives["王"],color="purple", label="王P")
plt.plot(negatives["王"],color="yellow", label="王N")
plt.legend(bbox_to_anchor=(1, 1), loc='upper right', borderaxespad=0, fontsize=18)
for i,key_phrase in enumerate(key_phrases):
    plt.text(i,1,key_phrase,size=10)

キーフレーズが多すぎて文字がつぶれてしまいました。このままだと読書感想文を作成しづらいので工夫してみます。

おそらく物語で重要なポイントは感情の値が大きくなっているはずです。主要登場人物 3 人の誰か 1 人でも Positive ないし Negative の感情が高まっていたら重要な箇所だと思います。ここでは 0.5 というしきい値を設けて、誰かの Positive または Negative の値が 0.5 を超えていたら感情をプロットし、その時のキーフレーズを表示させてみます。また、キーフレーズもなるべくバラけて表示するようにちょっと工夫を加えてみます。

img_comprehend-readingimpressions_05
img_comprehend-readingimpressions_05

クリックすると拡大します

th = 0.5
th_over_positives = {"メロス":[],"セリヌンティウス":[],"王":[]}
th_over_negatives = {"メロス":[],"セリヌンティウス":[],"王":[]}
th_over_key_phrases = []
for i in range(len(key_phrases)):
    if positives["メロス"][i] >= 0.5 or positives["セリヌンティウス"][i] >= 0.5 or positives["王"][i] >= 0.5 or negatives["メロス"][i] >= 0.5 or negatives["セリヌンティウス"][i] >= 0.5 or negatives["王"][i] >= 0.5:
        th_over_positives["メロス"].append(positives["メロス"][i])
        th_over_positives["セリヌンティウス"].append(positives["セリヌンティウス"][i])
        th_over_positives["王"].append(positives["王"][i])
        th_over_negatives["メロス"].append(negatives["メロス"][i])
        th_over_negatives["セリヌンティウス"].append(negatives["セリヌンティウス"][i])
        th_over_negatives["王"].append(negatives["王"][i])
        th_over_key_phrases.append(key_phrases[i])
mpl.rcParams['font.family']='IPAexGothic'
fig = plt.figure(figsize=(16.0, 10.0))
plt.plot(th_over_positives["メロス"],color="green", label="メロスP")
plt.plot(th_over_negatives["メロス"],color="red", label="メロスN")
plt.plot(th_over_positives["セリヌンティウス"],color="blue", label="セリヌンティウスP")
plt.plot(th_over_negatives["セリヌンティウス"],color="orange", label="セリヌンティウスN")
plt.plot(th_over_positives["王"],color="purple", label="王P")
plt.plot(th_over_negatives["王"],color="yellow", label="王N")
plt.legend(bbox_to_anchor=(1, 1), loc='upper right', borderaxespad=0, fontsize=18)
for i,key_phrase in enumerate(th_over_key_phrases):
    height = (i%5) * (1/4)
    plt.text(i,height,key_phrase,size=10)

かなりの情報を削減でき、また重要な情報だけ残すことが出来たかと思います。これらの感情の値が大きくなっている時のキーフレーズをもとに読書感想文を作成してみましょう。 

img_comprehend-readingimpressions_06
img_comprehend-readingimpressions_06

クリックすると拡大します


読書感想文作成

「走れメロス」 小学二十三年生 呉 和仁

メロスは王の前でも忠誠を誓っていなかった。(メロス Negative 時キーワード抜粋)
それは、王が悪い人間だったためであり、だからこそメロスは地団駄を踏むほかなかったのは十分イメージできる。(王 Negative 時キーワード抜粋 + 適当な修飾 + 感想)
そんなメロスは 16 の妹がいるので、神々の祭壇で祈り、祝宴の席に出て、ゆっくり眠ることが出来た。この時のメロスはきっと今までで最高の安眠だったに違いない。しかし、メロスは王との約束に未練の情を感じずにはいられず、起きて城へ向かうことに。(メロス 弱 Positive + キーフレーズ抜粋 + 適当な修飾 + 感想)
両腕に矢と雨を浴びながら、さらには額に汗をかきながら、二里三里と進み、更には棍棒の一撃などなんのその、山賊三人を振り切って濁流を乗り越え、灼熱の太陽を目眩を起こしながら進むメロスの意思の強さは見習いたいと思った。(メロスの Positive と Negative の入り乱れ + キーフレーズ抜粋 + 適当な修飾 + 感想)
セリヌンティウスも磔になりながらも、メロスとセリヌンティウスが腕を唸らせてしまいながらも微笑む二人の姿に感動した。(セリヌンティウスの Positive と Negative の入り乱れ + キーフレーズ抜粋 + 感想 )
これには王も改心せざるを得なかったのだろう。いい終わり方だと思った。(なんとかまとめる)

なんとか原稿用紙 2 枚程度の感想文を無事作ることが出来ました! 


まとめ

私も読書感想文を書いた後に、確認のため「走れメロス」をちゃんと読んでみたところ、 Amazon Comprehend をつかうことで下記 3 つを達成できたかと思います。

  1. 主要登場人物 3 人をすぐに特定でき、また「走れメロス」というタイトルが無くてもメロスが主人公だと判明する
  2. 「メロスは激怒した」の Negative スタートから、ハッピーエンドの Positive までしっかりと感情を読み取れる
  3. キーフレーズだけでも大まかにストーリーがわかる

これらによって、読まずともなんとか読書感想文も書けたかな、ということにしたいと思います。

今回は小学生の体 (てい) で読書感想文を書きました。せっかく AI を扱ったので、中学生くらいの体 (てい) になる機会があったら、読書感想文の自動生成も挑戦してみたいなぁ、とも思います。

ぜひ、読書感想文の宿題を抱える小学生の親御様でこのブログを読んだ方には、 Amazon Comprehend を使って結果をお子様に見せると、お子様が喜ぶかもしれません。あるいは自由研究のネタにできるかもしれません。

それではよい夏を !

筆者プロフィール

photo_go_kazuhito

呉 和仁 (Go Kazuhito / @kazuneet
アマゾン ウェブ サービス ジャパン株式会社 機械学習ソリューションアーキテクト。

IoT の DWH 開発、データサイエンティスト兼業務コンサルタントを経て現職。
プログラマの三大美徳である怠惰だけを極めてしまい、モデル構築を怠けられる AWS の AI サービスをこよなく愛す。

AWS のベストプラクティスを毎月無料でお試しいただけます

さらに最新記事・デベロッパー向けイベントを検索

下記の項目で絞り込む
絞り込みを解除 ≫
フィルタ
フィルタ
1

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する