Amazon Comprehend で、(キーフレーズ抽出)(エンティティ認識)(構文解析)を試してみる

前投稿で、(言語検出)(感情分析)をやってみたので、今回はその続きで、(キーフレーズ抽出)(エンティティ認識)(構文解析)です。

まず、APIリファレンスです。

APIリファレンス

Comprehend  detect_key_phrasesメソッド (キーフレーズ抽出)

機能   テキスト内に見つかった「重要な言い回し」を検出します。

構文

{
   "LanguageCode": "string",
   "Text": "string"
}

戻り値

{
   "KeyPhrases": [ 
      { 
         "BeginOffset": number,
         "EndOffset": number,
         "Score": number,
         "Text": "string"
      }
   ]
}

構文説明

リクエストは以下のデータを JSON 形式で受け入れます。	
	
[LanguageCode]	
	
	入力ドキュメントの言語。Amazon Comprehend でサポートされる主要言語のいずれかを指定できます。
	すべてのドキュメントは同じ言語である必要があります。
	タイプ: 文字列
	有効な値: en | es | fr | de | it | pt | ar | hi | ja | ko | zh | zh-TW  日本語ja OK!
	指定は必須
	
[Text]	
	
	UTF-8 テキスト文字列。各文字列には、UTF-8 エンコード文字で 5,000 バイト未満です。
	タイプ: 文字列
	長さの制約: 最小長= 1
	指定は必須

戻り値説明

アクションが成功すると、サービスは HTTP 200 レスポンスを返します。	
サービスから以下のデータが JSON 形式で返されます。	
	
[KeyPhrases]	
	
	AmazonComprehendが入力テキストで識別したキーフレーズのコレクション。
	キーフレーズごとに、応答はキーフレーズのテキスト、キーフレーズの開始位置と終了位置、
	およびAmazonComprehendの検出精度である信頼度を提供します。
	タイプ:KeyPhraseオブジェクトの配列

エラー内容

[InternalServerException]	
	
	内部サーバーエラーが発生しました。リクエストを再実行します。
	HTTP ステータスコード: 500
	
[InvalidRequestException]	
	
	要求は無効です。
	HTTP ステータスコード: 400
	
[TextSizeLimitExceedException]	
	
	入力テキストのサイズが制限を超えています。小さなドキュメントを使用する。
	HTTP ステータスコード: 400
	
[UnsupportedLanguageException]	
	
	Amazon Comprehend は入力テキストの言語を処理できません。
	ユーザー定義エンティティ認識 API の場合、英語、スペイン語、フランス語、イタリア語、ドイツ語、またはポルトガル語のみが
	受け入れられます。
	HTTP ステータスコード: 400

Comprehend  detect_entitiesメソッド (エンティティ認識)

機能  文章から、人名、地名、社名といった固有名詞や日付などの情報を抽出します。

構文

{
   "EndpointArn": "string",
   "LanguageCode": "string",
   "Text": "string"
}

戻り値

{
   "Entities": [ 
      { 
         "BeginOffset": number,
         "EndOffset": number,
         "Score": number,
         "Text": "string",
         "Type": "string"
      }
   ]
}

構文説明

リクエストは以下のデータを JSON 形式で受け入れます。	
	
[EndpointArn]	
	
	カスタムエンティティ認識モデルに関連付けられているエンドポイントの Amazonリソースネーム。
	Amazon Comprehend で使用されるデフォルトモデルではなく、独自のカスタムモデルを使用してエンティティを検出する場合は、
	エンドポイントを指定します。
	エンドポイントを指定すると、Amazon Comprehend はカスタムモデルの言語を使用し、リクエストで指定した言語コードは無視されます。
	タイプ: 文字列
	長さの制約: 最大長=256
	パターン: arn:aws(-[^:]+)?:comprehend:[a-zA-Z0-9-]*:[0-9]{12}:entity-recognizer-endpoint/[a-zA-Z0-9](-*[a-zA-Z0-9])*
	指定は必須ではない
	
[LanguageCode]	
	
	入力ドキュメントの言語。Amazon Comprehend でサポートされる主要言語のいずれかを指定できます。
	すべてのドキュメントは同じ言語である必要があります。
	リクエストにカスタムエンティティ認識モデルのエンドポイントが含まれている場合、
	Amazon Comprehend はカスタムモデルの言語を使用し、ここで指定した言語コードは無視されます。
	タイプ:文字列
	有効な値: en | es | fr | de | it | pt | ar | hi | ja | ko | zh | zh-TW 日本語ja OK!
	指定は必須ではない
	
[Text]	
	
	UTF-8 テキスト文字列。各文字列には、UTF-8エンコード文字で 5,000バイト未満です。
	タイプ: 文字列
	長さの制約: 最小長= 1
	指定は必須

戻り値説明

アクションが成功すると、サービスは HTTP 200 レスポンスを返します。	
サービスから以下のデータが JSON 形式で返されます。	
	
[Entities]	
	
	入力テキストで識別されたエンティティのコレクション。
	応答は、エンティティごとに、エンティティテキスト、エンティティタイプ、エンティティテキストの開始位置と終了位置、
	およびAmazonComprehendが検出した信頼度を提供します。
	
	リクエストでカスタムエンティティ認識モデルが使用されている場合、
	Amazon Comprehendは、モデルが認識するようにトレーニングされているエンティティを検出します。
	それ以外の場合は、デフォルトのエンティティタイプを検出します。
	
	タイプ:エンティティオブジェクトの配列

エラー内容

[InternalServerException]	
	
	内部サーバーエラーが発生しました。リクエストを再実行します。
	HTTP ステータスコード: 500
	
[InvalidRequestException]	
	
	要求は無効です。
	HTTP ステータスコード: 400
	
[ResourceUnavailableException]	
	
	指定されたリソースは使用できません。リソースを確認して、リクエストを再度試みてください。
	HTTP ステータスコード: 400
	
[TextSizeLimitExceedException]	
	
	入力テキストのサイズが制限を超えています。小さなドキュメントを使用する。
	HTTP ステータスコード: 400
	
[UnsupportedLanguageException]	
	
	Amazon Comprehend は入力テキストの言語を処理できません。ユーザー定義エンティティ認識 API の場合、
	英語、スペイン語、フランス語、イタリア語、ドイツ語、またはポルトガル語のみが受け入れられます。
	HTTP ステータスコード: 400

Comprehend  detect_syntaxメソッド (構文分析)

機能  文書内のテキストの構文と単語の品詞を調べます。

構文

{
   "LanguageCode": "string",
   "Text": "string"
}

戻り値

{
   "SyntaxTokens": [ 
      { 
         "BeginOffset": number,
         "EndOffset": number,
         "PartOfSpeech": { 
            "Score": number,
            "Tag": "string"
         },
         "Text": "string",
         "TokenId": number
      }
   ]
}

構文説明

リクエストは以下のデータを JSON 形式で受け入れます。	
	
[LanguageCode]	
	
	入力ドキュメントの言語コード。Amazon Comprehend でサポートされる言語のいずれかを指定できます。
	ドイツ語 (「de」)、英語 (「en」)、スペイン語 (「es」)、フランス語 (「fr」)、イタリア語 (「it」)、ポルトガル語 (「pt」)。
	タイプ: 文字列
	有効な値: en | es | fr | de | it | pt 日本語ja NG!(2021.7.9)
	指定は必須
	
[Text]	
	
	A UTF-8 文字列。各文字列には、UTF エンコード文字で 5,000 バイト未満です。
	タイプ: 文字列
	長さの制約: 最小長=1
	指定は必須

戻り値説明

アクションが成功すると、サービスは HTTP 200 レスポンスを返します。	
サービスから以下のデータが JSON 形式で返されます。	
	
[SyntaxTokens]	
	
	テキストを説明する構文トークンのコレクション。 
	応答は、トークンごとに、テキスト、テキストの開始位置と終了位置、およびAmazon Comprehend が信頼度を提供します。
	タイプ:SyntaxTokenオブジェクトの配列

エラー内容

[InternalServerException]	
	
	内部サーバーエラーが発生しました。リクエストを再実行します。
	HTTP ステータスコード: 500
	
[InvalidRequestException]	
	
	要求は無効です。
	HTTP ステータスコード: 400
	
[TextSizeLimitExceedException]	
	
	入力テキストのサイズが制限を超えています。小さなドキュメントを使用してください。
	HTTP ステータスコード: 400
	
[UnsupportedLanguageException]	
	
	Amazon Comprehend は入力テキストの言語を処理できません。
	ユーザー定義エンティティ認識 API の場合、英語、スペイン語、フランス語、イタリア語、ドイツ語、ポルトガル語のみが受け入れられます。
	HTTP ステータスコード: 400

③文書内のエンティティを認識するプログラム  detect_key_phrase1.py

import boto3
import json
comprehend = boto3.client('comprehend', 'ap-northeast-1')
text = "炭治郎は自分を鼓舞した。\
「頑張れ炭治郎頑張れ!! 俺は今までよくやってきた!! 俺はできる奴だ!! そして今日も!! これからも!! 折れていても!! \
俺が挫けることは絶対に無い!!」\
でも、戦いが終われば、敵である鬼に対しても、慈悲の気持ちを表した。\
「殺された人たちの無念を晴らすため、これ以上被害者を出さないため…\
勿論俺は容赦無く鬼の頸に刃を振るいます。だけど鬼であることに苦しみ、\
自らの行いを悔いている者を踏みつけにはしない。鬼は人間だったんだから。\
足をどけてください。醜い化け物なんかじゃない。鬼は虚しい生き物だ。悲しい生き物だ。」"
result = comprehend.detect_key_phrases(Text=text, LanguageCode='ja')
print(json.dumps(result, indent=4))
report = {}
for phrase in result['KeyPhrases']:
    txt, score = phrase['Text'], phrase['Score']
    report[txt] = '{:<018} {}'.format(score, txt)
for line in sorted(report.values(), reverse=True):
    print(line)
PS C:\Users\mikol\comprehend> python detect_key_phrase1.py
{
    "KeyPhrases": [
        {
            "Score": 0.9998185634613037,
            "Text": "\u70ad\u6cbb\u90ce",     炭治郎
            "BeginOffset": 0,
            "EndOffset": 3
        },
        {
            "Score": 0.9988521337509155,
            "Text": "\u81ea\u5206",        (自分)
            "BeginOffset": 4,
            "EndOffset": 6
        },
        {
            "Score": 0.9895590543746948,
            "Text": "\u70ad\u6cbb\u90ce",     (炭治郎)
            "BeginOffset": 16,
            "EndOffset": 19
        },
        {
            "Score": 0.9987995624542236,
            "Text": "\u4ffa",            俺
            "BeginOffset": 25,
            "EndOffset": 26
        },
        {
            "Score": 0.9984912872314453,
            "Text": "\u4ffa",            俺
            "BeginOffset": 40,
            "EndOffset": 41
        },
        {
            "Score": 0.9945422410964966,
            "Text": "\u5974",           (奴)
            "BeginOffset": 45,
            "EndOffset": 46
        },
        {
            "Score": 0.9536038637161255,
            "Text": "\u4eca\u65e5",        (今日)
            "BeginOffset": 53,
            "EndOffset": 55
        },
        {
            "Score": 0.9983626008033752,
            "Text": "\u4ffa",            俺
            "BeginOffset": 76,
            "EndOffset": 77
        },
        {
            "Score": 0.9997751116752625,
            "Text": "\u6226\u3044",        (戦い)
            "BeginOffset": 95,
            "EndOffset": 97
        },
        {
            "Score": 0.9943884015083313,
            "Text": "\u6575",            (敵)
            "BeginOffset": 103,
            "EndOffset": 104
        },
        {
            "Score": 0.9493768215179443,
            "Text": "\u9b3c",            鬼
            "BeginOffset": 107,
            "EndOffset": 108
        },
        {
            "Score": 0.996557891368866,
            "Text": "\u6148\u60b2\u306e\u6c17\u6301\u3061",  (慈悲の気持ち)
            "BeginOffset": 114,
            "EndOffset": 120
        },
        {
            "Score": 0.9971917867660522,
            "Text": "\u4eba\u305f\u3061\u306e\u7121\u5ff5",  (人たちの無念)
            "BeginOffset": 130,
            "EndOffset": 136
        },
        {
            "Score": 0.9944612979888916,
            "Text": "\u3053\u308c",         (これ)
            "BeginOffset": 143,
            "EndOffset": 145
        },
        {
            "Score": 0.9927535057067871,
            "Text": "\u88ab\u5bb3\u8005",      (被害者)
            "BeginOffset": 147,
            "EndOffset": 150
        },
        {
            "Score": 0.9969915151596069,
            "Text": "\u4ffa",             (俺)
            "BeginOffset": 160,
            "EndOffset": 161
        },
        {
            "Score": 0.9978446960449219,
            "Text": "\u9b3c\u306e\u9838",      (鬼の頸)
            "BeginOffset": 166,
            "EndOffset": 169
        },
        {
            "Score": 0.9972043633460999,
            "Text": "\u5203",             (刃)
            "BeginOffset": 170,
            "EndOffset": 171
        },
        {
            "Score": 0.9984999895095825,
            "Text": "\u9b3c",              鬼
            "BeginOffset": 181,
            "EndOffset": 182
        },
        {
            "Score": 0.9989050626754761,
            "Text": "\u81ea\u3089\u306e\u884c\u3044",  (自らの行い)
            "BeginOffset": 192,
            "EndOffset": 197
        },
        {
            "Score": 0.9989950060844421,
            "Text": "\u8005",              (者)
            "BeginOffset": 203,
            "EndOffset": 204
        },
        {
            "Score": 0.9999489784240723,
            "Text": "\u9b3c",               鬼
            "BeginOffset": 215,
            "EndOffset": 216
        },
        {
            "Score": 0.9876834750175476,
            "Text": "\u4eba\u9593",           (人間)
            "BeginOffset": 217,
            "EndOffset": 219
        },
        {
            "Score": 0.9998825788497925,
            "Text": "\u8db3",               (足)
            "BeginOffset": 227,
            "EndOffset": 228
        },
        {
            "Score": 0.9775259494781494,
            "Text": "\u5316\u3051\u7269\u306a\u3093\u304b",  (化け物なんか)
            "BeginOffset": 239,
            "EndOffset": 245
        },
        {
            "Score": 0.9998785257339478,
            "Text": "\u9b3c",              鬼
            "BeginOffset": 250,
            "EndOffset": 251
        },
        {
            "Score": 0.998601496219635,
            "Text": "\u751f\u304d\u7269",       生き物
            "BeginOffset": 255,
            "EndOffset": 258
        },
        {
            "Score": 0.9991565942764282,
            "Text": "\u751f\u304d\u7269",       (生き物)
            "BeginOffset": 263,
            "EndOffset": 266
        }
    ],
    "ResponseMetadata": {
        "RequestId": "11676764-31a7-464b-a957-4f9943f08f71",
        "HTTPStatusCode": 200,
        "HTTPHeaders": {
            "x-amzn-requestid": "11676764-31a7-464b-a957-4f9943f08f71",
            "content-type": "application/x-amz-json-1.1",
            "content-length": "2228",
            "date": "Thu, 08 Jul 2021 10:39:25 GMT"
        },
        "RetryAttempts": 0
    }
}
  0.9998825788497925 足
  0.9998785257339478 鬼
  0.9997751116752625 戦い
  0.9991565942764282 生き物
  0.9989950060844421 者
  0.9989050626754761 自らの行い
  0.9988521337509155 自分
  0.9978446960449219 鬼の頸
  0.9972043633460999 刃
  0.9971917867660522 人たちの無念
  0.9969915151596069 俺
  0.9965578913688660 慈悲の気持ち
  0.9945422410964966 奴
  0.9944612979888916 これ
  0.9943884015083313 敵
  0.9927535057067871 被害者
  0.9895590543746948 炭治郎
  0.9876834750175476 人間
  0.9775259494781494 化け物なんか
  0.9536038637161255 今日

結果の順位一覧を見てもよくわからない。もういっちょ!

text = "彼こそが真の長距離打者だと感じます。また、大谷選手は素晴らしいピッチャーです。\
大リーグの常識を変えた唯一無二の存在です。\
今後もファンの方々や少年たちの夢を背負い、シーズンを乗り切って欲しいと思います。"

テキストだけ変えた!

PS C:\Users\mikol\comprehend> python detect_key_phrase2.py
{
    "KeyPhrases": [
        {
            "Score": 0.9991952776908875,
            "Text": "\u5f7c",   (彼)
            "BeginOffset": 0,
            "EndOffset": 1
        },
        {
            "Score": 0.9917044043540955,
            "Text": "\u771f\u306e\u9577\u8ddd\u96e2\u6253\u8005", (真の長距離打者)
            "BeginOffset": 4,
            "EndOffset": 11
        },
        {
            "Score": 0.5408477187156677,
            "Text": "\u3001",
            "BeginOffset": 20,
            "EndOffset": 21
        },
        {
            "Score": 0.7279067635536194,
            "Text": "\u5927\u8c37\u9078\u624b\u306f\u7d20\u6674\u3089\u3057\u3044", 大谷選手は素晴らしい
            "BeginOffset": 21,
            "EndOffset": 31
        },
        {
            "Score": 0.5462606549263,
            "Text": "\u30d4\u30c3\u30c1\u30e3\u30fc",  ピッチャー
            "BeginOffset": 31,
            "EndOffset": 36
        },
        {
            "Score": 0.9978181719779968,
            "Text": "\u5927\u30ea\u30fc\u30b0\u306e\u5e38\u8b58",  (大リーグの常識)
            "BeginOffset": 39,
            "EndOffset": 46
        },
        {
            "Score": 0.8959624171257019,
            "Text": "\u552f\u4e00\u7121\u4e8c\u306e\u5b58\u5728",  ( 唯一無二の存在)
            "BeginOffset": 50,
            "EndOffset": 57
        },
        {
            "Score": 0.9995926022529602,
            "Text": "\u4eca\u5f8c",  (今後)
            "BeginOffset": 60,
            "EndOffset": 62
        },
        {
            "Score": 0.9985405802726746,
            "Text": "\u30d5\u30a1\u30f3\u306e\u65b9\u3005\u3084\u5c11\u5e74\u305f\u3061\u306e\u5922",  (ファンの方々や少年たちの夢)
            "BeginOffset": 63,
            "EndOffset": 76
        },
        {
            "Score": 0.9997205138206482,
            "Text": "\u30b7\u30fc\u30ba\u30f3",  (シーズン)
            "BeginOffset": 81,
            "EndOffset": 85
        }
    ],
    "ResponseMetadata": {
        "RequestId": "8d98cc94-2e3a-4686-936d-47527a9bc94f",
        "HTTPStatusCode": 200,
        "HTTPHeaders": {
            "x-amzn-requestid": "8d98cc94-2e3a-4686-936d-47527a9bc94f",
            "content-type": "application/x-amz-json-1.1",
            "content-length": "891",
            "date": "Thu, 08 Jul 2021 10:39:52 GMT"
        },
        "RetryAttempts": 0
    }
}
  0.9997205138206482 シーズン
  0.9995926022529602 今後
  0.9991952776908875 彼
  0.9985405802726746 ファンの方々や少年たちの夢
  0.9978181719779968 大リーグの常識
  0.9917044043540955 真の長距離打者
  0.8959624171257019 唯一無二の存在
  0.7279067635536194 大谷選手は素晴らしい
  0.5462606549263000 ピッチャー
  0.5408477187156677 、

やっぱり、良くわからない?

④文章のエンティティを認識するプログラム  detect_entity.py

import boto3
comprehend = boto3.client('comprehend', 'us-east-2')
text = "Today the Tokyo Metropolitan Government confirmed 714 new coronavirus infections. The average in the last seven days exceeded 500 people, and it was 508."
result = comprehend.detect_entities(Text=text, LanguageCode='en')
for entity in result['Entities']:
    print('{:20} {:20} {:<018}'.format(
        entity['Text'], entity['Type'], entity['Score']))
PS C:\Users\mikol\comprehend> python detect_entity.py

Today                DATE                 0.9924750924110413               (DATE:日付、時刻)
Tokyo Metropolitan Government    ORGANIZATION         0.9967338442802429  (ORGANIZATION:組織)
714 new coronavirus infections   QUANTITY             0.8721827268600464  (QUANTITY:数値(金額、パーセンテージ」、数値、バイト数など)

seven                DATE                 0.43877923488616943
days                 QUANTITY             0.7388077974319458
500 people           QUANTITY             0.9913239479064941
508                  QUANTITY             0.9958401918411255

ちなみに、日本語でもOK!!

⑤文章の構文を解析するプログラム  

import boto3
comprehend = boto3.client('comprehend', 'us-east-2')
text = "Today the Tokyo Metropolitan Government confirmed 714 new coronavirus infections. The average in the last seven days exceeded 500 people, and it was 508."
result = comprehend.detect_syntax(Text=text, LanguageCode='en')
for token in result['SyntaxTokens']:
    print('{:20} {:20} {:<018}'.format(
        token['Text'],
        token['PartOfSpeech']['Tag'],
        token['PartOfSpeech']['Score']))
PS C:\Users\mikol\comprehend> python detect_entity.py

Today                NOUN                 0.9799969196319580
the                  DET                  0.9999412298202515
Tokyo                PROPN                0.9996253252029419
Metropolitan         PROPN                0.9992173910140991
Government           PROPN                0.9905853867530823
confirmed            VERB                 0.9994437098503113
714                  NUM                  0.9998207688331604
new                  ADJ                  0.9994088411331177
coronavirus          NOUN                 0.9429358243942261
infections           NOUN                 0.9999315738677979
.                    PUNCT                0.9999971389770508
The                  DET                  0.9999741315841675
average              NOUN                 0.8812488913536072
in                   ADP                  0.9999345541000366
the                  DET                  0.9999885559082031
last                 ADJ                  0.9994642138481140
seven                NUM                  0.9991330504417419
days                 NOUN                 0.9999151229858398
exceeded             VERB                 0.9943482279777527
500                  NUM                  0.9997524619102478
people               NOUN                 0.9999828338623047
,                    PUNCT                0.9999984502792358
and                  CONJ                 0.9999988079071045
it                   PRON                 0.9999908208847046
was                  VERB                 0.9971580505371094
508                  NUM                  0.9998282194137573
.                    PUNCT                0.9999864101409912

ちなみに、日本語はNG!!(2021.7.9)

補足  品詞一覧

Token品詞
ADJ形容詞 
ADPアドポジション 
ADV副詞  通常、動詞を修正する単語。また、形容詞やその他の副詞を変更することもできます。
AUX補助  動詞句の動詞に付随する関数単語。
CCONJコーディネート 
DET限定子 
INTJインタージェクション  感嘆符または感嘆符の一部として使用される単語。
NOUN名詞  人、場所、物、動物、またはアイデアを指定する単語。
NUMNumeral  数を表す単語(通常は限定詞、形容詞、代名詞)。
Oその他 
PART粒子  別の単語や語句に関連付けられた単語を機能させ、意味を与えます。
PRON代名詞 
PROPN固有名詞  特定の個人、場所、または対象の名前である名詞。
PUNCT句読点 
SCONJ従属組み込み  文章の一部をリンクする結合は、それらのいずれかを他方の部分にすること。
SYM記号  ドル記号 ($) や数学記号などの単語に似たエンティティ。
VERB動詞  イベントや行動を示す言葉。