Azure Cognitive ServicesのText Analyticsを日本語で使ってみた

DA事業本部の貞松です。
最近、自然言語処理関連で何か使えるものはないかと調査しています。
その一環で、Azureの自然言語処理系サービスが日本語でどれぐらい使えるか調べてみるかということになり、手始めにAzure Cognitive Servicesというサービス群に含まれるText Analyticsなるサービスについて色々試してみました。

Azure Cognitive Servicies

Azure Cognitive Servicies は、Azure上のサービス群の一つで、機械学習・AI関連のSaaSです。
APIで提供され、各機能単位でAPIキーを発行して、そのキーを使ってAPIにアクセスすることでサービスを利用できます。
料金体系は従量課金が多いようです(xxリクエストごとに◯◯円など)
月額固定+従量課金のケースもあります(月xxリクエストまでで◯◯円、超過分△△リクエスト毎に●●円など)

Azure Cognitive Serviciesの価格

言語処理系以外にも幾つかサービスがあり、以下のようなラインナップとなっています。

視覚

  • Computer Vision:画像の分類、シーンおよびアクティビティ認識、有名人とランドマークの認識、OCR
  • Face:画像内の顔検出、人物の特定、感情認識
  • Video Indexer:ビデオのビジュアル チャネルとオーディオ チャネルの完全な解析、顔、オブジェクト、キーフレーム認識、OCR、および文字起こしを実行
  • Custom Vision:カスタマイズ可能な画像認識(手持ちのデータを学習データとして投入し、学習させたモデルで画像認識を実行できる)

音声

  • Speech Services:カスタマイズ可能なモデルを使用した自動的な音声テキスト変換文字起こし 、カスタム音声フォントを使った自然なテキスト読み上げ、リアルタイムの音声翻訳

言語

  • Text Analytics:言語の自動検出、エンティティの認識、重要なフレーズを抽出、テキストの感情分析(ネガポジ)←本記事での対象はコレ
  • Translator Text:言語の自動検出、テキストの自動翻訳、カスタマイズ可能な翻訳
  • QnA Maker:非構造化テキストからの Q&A 抽出、Q&A のコレクションからのナレッジ ベースの作成、ナレッジ ベースのためのセマンティック マッチング
  • Language Understanding:コンテキストに応じた言語理解

決定

  • Content Moderator:不快感を与えかねない画像や好ましくない可能性のある画像の検出、卑罵語や不適切な表現が使われているテキストのフィルター、ビデオ内のアダルト コンテンツや人種差別的なコンテンツのモデレート、最善の成果を得るための組み込みのレビュー ツールの使用

Text Analyticsを実際に使ってみる

Text Analyticsを実際に使用するには、各機能ごとに用意されているREST APIを単純に呼び出して使用する方法とSDKを使用してAPIにアクセスする方法の2種類が用意されています。

REST API

単純なREST API呼び出しによってText Analyticsの機能を利用できます。 APIキーを発行し、規定のエンドポイントを指定してAPIにアクセスします。 単純なAPI呼び出しなので、ほとんどのプログラミング言語で利用可能です。

https://docs.microsoft.com/ja-jp/azure/cognitive-services/text-analytics/quickstarts/python

SDK

Text Analytics SDKを使用してText Analyticsの機能を利用できます。 APIキーを発行し、規定のエンドポイントを指定してAPIにアクセスします。 REST APIと違って、JSON をシリアル化および逆シリアル化することなく、アプリケーションに対して簡単にサービスを統合することができます。 対応言語は以下の通りです。

  • C#
  • Python
  • Go
  • Ruby
  • Node.js

https://docs.microsoft.com/ja-jp/azure/cognitive-services/text-analytics/quickstarts/python-sdk

APIキーの取得

Text Analyticsのページにある「Text Analytics API を試す」からAPIキーの発行処理に進めます。

既存のMicrosoftアカウント(Azureのサインアップ済)で発行する他にゲスト利用(7日間の試用)も可能です。

ゲスト利用では、Microsoftアカウントの他にFacebook、LinkedIn、GitHubのアカウントが使用可能です。

既存のMicrosoftアカウントで発行

既存のMicrosoftアカウントを選択した場合は、AzureポータルのText Analyticsサービス作成画面に飛ばされるので、必要な情報を入力して作成します。 Pricing tier については、Cognitive Services の価格 – Text Analytics API を参照してください。

作成が完了すると、作成済みのText Analyticsサービスのメニューで「Quick start」を開くと、発行されたAPIキーとエンドポイントのURLを確認することができます。

SDKを使ってText Analyticsの機能を利用してみる

今回はPythonのSDKを使ってText Analyticsの各機能を使ってみました。

ライブラリのインストールとインポート

まずはpipで必要なライブラリのインストール。

pip install --upgrade azure-cognitiveservices-language-textanalytics

次にAPIを呼び出して使用するPythonのコードを書きます。

必要なライブラリをインポートし、発行したAPIのKeyとエンドポイントを指定します。

from azure.cognitiveservices.language.textanalytics import TextAnalyticsClient
from msrest.authentication import CognitiveServicesCredentials

subscription_key = {発行したAPI Key}
credentials = CognitiveServicesCredentials(subscription_key)

text_analytics_url = {発行したAPIのエンドポイントURL}
text_analytics = TextAnalyticsClient(endpoint=text_analytics_url, credentials=credentials)

ここで一点注意が必要です。 APIのエンドポイントURLについて、コンソールの画面上では、

https://hogehoge.cognitiveservices.azure.com/text/analytics/v2.1

という感じで、~.com/ 以降の記述が表示されているのですが、実際にコードの中で指定する際には、

https://hogehoge.cognitiveservices.azure.com/

で指定しないと実行時に Resource Not Found のエラーが返ってきます。ちょっとした罠ですね。

言語の判別

言語の判別には detect_language() を使用します。

documents = [
    {
        "id": "1",
        "text": "Was sind überhaupt Expeditionen? Expeditionen sind eine neue PvE-Aktivität, die mit Episode 1 ins Spiel kam."
    },
    {
        "id": "2",
        "text": "Episode 1's narrative content is now available to those pass holders, as is the Heatwave apparel event, which allows players to amass 40 summer-themed items. "
    },
    {
        "id": "3",
        "text": "先日のタイトルアップデート4では、以下の不具合が修正されました。 "
    }
]

response = text_analytics.detect_language(documents=documents)

for document in response.documents:
    print("Document Id: ", document.id, ", Language: ",
          document.detected_languages[0].name)

実行結果は以下の通りです。

$ python azure_text_analytics_sample_1.py
Document Id:  1 , Language:  German
Document Id:  2 , Language:  English
Document Id:  3 , Language:  Japanese

問題なく判別できています。

キーフレーズ抽出

キーフレーズ抽出には key_phrases() を使用します。

documents = [
    {
        "id": "1",
        "language": "ja",
        "text": """Amazon Web Services(アマゾン ウェブ サービス、AWS)とは、
        Amazon.comにより提供されているクラウドコンピューティングサービス(ウェブサービス)である。
        クラウドのタイプとしてはIaaSに分類される。これらのサービスは全世界で18の地域に提供されている。"""
    }
]

response = text_analytics.key_phrases(documents=documents)

for document in response.documents:
    print("Document Id: ", document.id)
    print("\tKey Phrases:")
    for phrase in document.key_phrases:
        print("\t\t", phrase)

実行結果は以下の通りです。

$ python azure_text_analytics_sample_2.py
Document Id:  1
    Key Phrases:
         ウェブサービス
         アマゾン ウェブ サービス
         クラウドコンピューティングサービス
         提供
         Amazon Web Services
         AWS
         IaaS
         タイプ
         世界
         地域

これも概ね問題なく抽出できているようです。

感情分析

感情分析には sentiment() を使用します。

documents = [
    {
        "id": "1",
        "language": "ja",
        "text": "今日は天気が良く、とても気分の良い日だった。"
    },
    {
        "id": "2",
        "language": "ja",
        "text": "俺はもう駄目かもしれない。"
    },
    {
        "id": "3",
        "language": "ja",
        "text": "全体的には良かったが、最後のシーンは正直良くなかった。"
    },
    {
        "id": "4",
        "language": "ja",
        "text": "昨日は地元のお祭りがあった"
    }
]
response = text_analytics.sentiment(documents=documents)

for document in response.documents:
    print("Document Id: ", document.id, ", Sentiment Score: ",
          "{:.2f}".format(document.score))

実行結果は以下の通りです。

$ python azure_text_analytics_sample_3.py
Document Id:  1 , Sentiment Score:  0.60
Document Id:  2 , Sentiment Score:  0.40
Document Id:  3 , Sentiment Score:  0.49
Document Id:  4 , Sentiment Score:  0.50

スコアが1に近ければポジティブ(肯定的)、0に近ければネガティブ(否定的)なテキストということになります。
あからさまにポジティブなid1の文章で0.60、逆にあからさまにネガティブなid2の文章で0.40となっており、ちょっと精度が低いように見えます。

そこで、複数のポジティブ・ネガティブな文をくっつけて、少し長めのテキストにしてみました。

documents = [
    {
        "id": "1",
        "language": "ja",
        "text": "今日は天気が良く、とても気分の良い日だった。晩ご飯も美味しかった。明日も良いことがありそうだ。"
    },
    {
        "id": "2",
        "language": "ja",
        "text": "俺はもう駄目かもしれない。もうどうしようもない。全てが悪い方向に向かっている。"
    }
]

実行結果。

$ python azure_text_analytics_sample_3.py
Document Id:  1 , Sentiment Score:  0.76
Document Id:  2 , Sentiment Score:  0.22

今度は少し強めの傾向を示すスコアになりました。
どうやら一文ではスコアが上がらないようで、複数の文からなる長めのテキストに対して、トータルでポジティブ・ネガティブを判別するようです。
少々使い所を考える必要がありそうですね。

エンティティの検出

名前付きエンティティの検出には entities() を使用します。

documents = [
    {
        "id": "1",
        "language": "ja",
        "text": "マイクロソフトは、アルテア用のBASICのインタプリタを開発・販売する為に、ビル・ゲイツとポール・アレンによって1975年の4月4日に設立された。"
    }
]

response = text_analytics.entities(documents=documents)

for document in response.documents:
    print("Document Id: ", document.id)
    print("\tKey Entities:")
    for entity in document.entities:
        print("\t\t", "NAME: ", entity.name, "\tType: ",
              entity.type, "\tSub-type: ", entity.sub_type)
        for match in entity.matches:
            print("\t\t\tOffset: ", match.offset, "\tLength: ", match.length, "\tScore: ",
                  "{:.2f}".format(match.entity_type_score))

実行結果は以下の通り。

$ python azure_text_analytics_sample_4.py
Document Id:  1
    Key Entities:
         NAME:  マイクロソフト     Type:  Organization     Sub-type:  None
            Offset:  0  Length:  7  Score:  0.96
         NAME:  ビル.ゲイツ  Type:  Person   Sub-type:  None
            Offset:  38     Length:  6  Score:  0.97
         NAME:  ポ-ル.アレン     Type:  Person   Sub-type:  None
            Offset:  45     Length:  7  Score:  0.95

BASICアルテア といったフレーズが抽出されておらず、こちらも若干精度低めという印象です。

ちなみに英語に対して処理を実行すると、

documents = [
    {
        "id": "1",
        "language": "en",
        "text": "Microsoft was founded by Bill Gates and Paul Allen on April 4, 1975, to develop and sell BASIC interpreters for the Altair 8800."
    }
]

response = text_analytics.entities(documents=documents)

for document in response.documents:
    print("Document Id: ", document.id)
    print("\tKey Entities:")
    for entity in document.entities:
        print("\t\t", "NAME: ", entity.name, "\tType: ",
              entity.type, "\tSub-type: ", entity.sub_type)
        for match in entity.matches:
            print("\t\t\tOffset: ", match.offset, "\tLength: ", match.length, "\tScore: ",
                  "{:.2f}".format(match.entity_type_score))
$ python azure_text_analytics_sample_4.py
Document Id:  1
    Key Entities:
         NAME:  Microsoft   Type:  Organization     Sub-type:  None
            Offset:  0  Length:  9  Score:  1.00
         NAME:  Bill Gates  Type:  Person   Sub-type:  None
            Offset:  25     Length:  10     Score:  1.00
         NAME:  Paul Allen  Type:  Person   Sub-type:  None
            Offset:  40     Length:  10     Score:  1.00
         NAME:  April 4     Type:  Other    Sub-type:  None
            Offset:  54     Length:  7  Score:  0.80
         NAME:  April 4, 1975   Type:  DateTime     Sub-type:  Date
            Offset:  54     Length:  13     Score:  0.80
         NAME:  BASIC   Type:  Other    Sub-type:  None
            Offset:  89     Length:  5  Score:  0.80
         NAME:  Altair 8800     Type:  Other    Sub-type:  None
            Offset:  116    Length:  11     Score:  0.80
         NAME:  Altair  Type:  Organization     Sub-type:  None
            Offset:  116    Length:  6  Score:  0.53
         NAME:  8800    Type:  Quantity     Sub-type:  Number
            Offset:  123    Length:  4  Score:  0.80

アルテアBASIC だけでなく、創業日の 1975年4月4日 も検出されています。

まとめ

Azure Cognitive ServicesのText Analyticsを日本語で使ってみました。
SDKを使ってAPIにアクセスすることで非常に簡単に自然言語処理の機能を利用できました。
反面、日本語で使用した場合の精度については今一歩の感もあり、その点は今後のアップデートに期待という感じでした。ニポンゴ ムズカシデスネ。
Azure Cognitive Servicesには、Text Analytics以外にも言語処理系のサービスがあるので、そちらについても試してみたいと思っております。

以上です!