こんにちは。今日は、Microsoft AzureのText Analyticsサービスを使って日本語の感情分析を行ってみたいと思います。グローバルのクラウドサービスで、日本語に対応したテキスト分析サービスって結構珍しい気がしたので、どれくらい使えるものなのか、確認してみたいと思った次第です。
それでは早速まいります!
Contents
Microsoft Azure Text Analyticsで分析できること
Text Analyticsを利用すると、以下のことができるようになります。以下で、それぞれの機能についてもう少し詳細に確認していきます。
- センチメント分析(感情分析)/意見マイニング
- オピニオンマイニング
- 言語検出
- キーフレーズの抽出
- 名前付きエンティティの認識
また、日本語に対応しているかどうかは、タスクによって異なります。以下のサイトから確認するようにしてください。例えば、2020年10月時点では、感情分析、キーフレーズの抽出、言語検出などは、日本語に対応していますが、オピニオン分析はプレビュー機能で英語のみに対応しているようです。
ここからは、Text Analyticsを利用するまでの手順の流れに沿って解説していきます。
Microsoft Azureアカウントの取得
このステップは割愛します。
Text Analyticsリソースの作成
続いて、Text Analyticsリソースを作成します。Text Analyticsリソースは、「リソースの作成」から、「Text Analytics」で検索すると出てきます。
リソースの作成にあたって特別な設定は特に不要です。下記のような設定のみです。
リソースの作成が完了したら、「キーとエンドポイント」ブレードから、キーとエンドポイントの情報を確認します。この2つの情報が、Text Analytics APIを利用する際に必要な情報となります。
PythonでText Analytics APIを使ってみる
ここからの手順は、公式ページで紹介されているサンプルコードに基づいています。また、実行環境として、Azure Machine Learning StudioのJupyter Labを利用しています。
また、言語はPythonです。
認証
Text Analytics APIを利用するには、はじめに認証が必要です。
key = "xxx"
endpoint = "xxx"
from azure.ai.textanalytics import TextAnalyticsClient
from azure.core.credentials import AzureKeyCredential
def authenticate_client():
ta_credential = AzureKeyCredential(key)
text_analytics_client = TextAnalyticsClient(
endpoint=endpoint,
credential=ta_credential)
return text_analytics_client
client = authenticate_client()
認証が終わったら、いよいよ個別のAPIを試してみます。
感情分析
まずは感情分析です。下の関数で呼び出している、analyze_sentiment関数が、Text Analyticsのメソッドです。language=”ja”と指定することで日本語の感情分析が可能になります。
def sentiment_analysis_example(client):
documents = ["今日の昼食は美味しかった。昨日の夕食は美味しくなかった。一昨日の朝食はおいしかった。"]
response = client.analyze_sentiment(documents=documents,language="ja")[0]
print("Document Sentiment: {}".format(response.sentiment))
print("Overall scores: positive={0:.2f}; neutral={1:.2f}; negative={2:.2f} \n".format(
response.confidence_scores.positive,
response.confidence_scores.neutral,
response.confidence_scores.negative,
))
for idx, sentence in enumerate(response.sentences):
print("Sentence: {}".format(sentence.text))
print("Sentence {} sentiment: {}".format(idx+1, sentence.sentiment))
print("Sentence score:\nPositive={0:.2f}\nNeutral={1:.2f}\nNegative={2:.2f}\n".format(
sentence.confidence_scores.positive,
sentence.confidence_scores.neutral,
sentence.confidence_scores.negative,
))
sentiment_analysis_example(client)
結果はこんな感じです。文章全体の感情スコアと、各文章の感情スコアが得られました。「美味しくなかった」を含む文がneutralとなっている点はちょっと気になりますが、とはいえNegativeスコアは高めに出ており、全体的には感覚から大きくずれたものではなさそうです。
このメソッドから取得できる情報について、もう少し確認しておこうと思います。
documents = ["今日の昼食は美味しかった。昨日の夕食は美味しくなかった。一昨日の朝食はおいしかった。"]
response = client.analyze_sentiment(documents=documents,language="ja")[0]
この戻りはlistになります。中身をみてみると、
- 全体のスコア
- 各文章のスコア
が返ってきていることがわかります。
今回、この感情スコアの妥当性についての詳細な比較検証はしていないですが、今後時間を見つけて、このAPIのスコア算出方法に関する仕様や、手元で作成した辞書ベース/Deep Learningベースの感情分析モデルのスコアとの比較を行ってみたいものです。
オピニオンマイニング
オピニオン分析とは、あるトピックに関する主観意見を取りまとめて、賛成・反対やポジティブ・ネガティブに分類して可視化することができます。
こちらは、2020年10月現在英語のみの対応ですが、以下のような分析が可能です。
def sentiment_analysis_with_opinion_mining_example(client):
documents = [
"The food and service were unacceptable, but the concierge were nice",
"The rooms were beautiful but dirty. The AC was good and quiet, but the elevator was broken"
]
result = client.analyze_sentiment(documents, show_opinion_mining=True)
doc_result = [doc for doc in result if not doc.is_error]
positive_reviews = [doc for doc in doc_result if doc.sentiment == "positive"]
negative_reviews = [doc for doc in doc_result if doc.sentiment == "negative"]
positive_mined_opinions = []
mixed_mined_opinions = []
negative_mined_opinions = []
for document in doc_result:
print("Document Sentiment: {}".format(document.sentiment))
print("Overall scores: positive={0:.2f}; neutral={1:.2f}; negative={2:.2f} \n".format(
document.confidence_scores.positive,
document.confidence_scores.neutral,
document.confidence_scores.negative,
))
for sentence in document.sentences:
print("Sentence: {}".format(sentence.text))
print("Sentence sentiment: {}".format(sentence.sentiment))
print("Sentence score:\nPositive={0:.2f}\nNeutral={1:.2f}\nNegative={2:.2f}\n".format(
sentence.confidence_scores.positive,
sentence.confidence_scores.neutral,
sentence.confidence_scores.negative,
))
for mined_opinion in sentence.mined_opinions:
aspect = mined_opinion.aspect
print("......'{}' aspect '{}'".format(aspect.sentiment, aspect.text))
for opinion in mined_opinion.opinions:
print("......'{}' opinion '{}'".format(opinion.sentiment, opinion.text))
print("\n")
sentiment_analysis_with_opinion_mining_example(client)
文章全体でのNegative/Positiveと、それぞれに判定された各単語を可視化することができます。面白い・・
言語検出
def language_detection_example(client):
try:
documents = ["なんでやねん"]
response = client.detect_language(documents = documents, country_hint = 'us')[0]
print("Language: ", response.primary_language.name)
except Exception as err:
print("Encountered exception. {}".format(err))
language_detection_example(client)
実行結果:
Language: Japanese
名前付きエンティティの認識
こちらは、
def entity_recognition_example(client):
try:
documents = ["I went to travel with my family by car last week."]
result = client.recognize_entities(documents = documents)[0]
print("Named Entities:\n")
for entity in result.entities:
print("\tText: \t", entity.text, "\tCategory: \t", entity.category, "\tSubCategory: \t", entity.subcategory,
"\n\tConfidence Score: \t", round(entity.confidence_score, 2), "\tOffset: \t", entity.offset, "\n")
except Exception as err:
print("Encountered exception. {}".format(err))
entity_recognition_example(client)
実行結果:
Named Entities:
Text: car Category: Product SubCategory: None
Confidence Score: 0.78 Offset: 35
Text: last week Category: DateTime SubCategory: DateRange
Confidence Score: 0.8 Offset: 39
CarはProduct、last weekはDateTimeと認識されました!
一方で、同じ英語を日本語で分析にかけてみると・・・
def entity_recognition_example(client):
try:
documents = ["先週末は家族と車で旅行に出かけた。"]
result = client.recognize_entities(documents = documents,language="ja")[0]
print("Named Entities:\n")
for entity in result.entities:
print("\tText: \t", entity.text, "\tCategory: \t", entity.category, "\tSubCategory: \t", entity.subcategory,
"\n\tConfidence Score: \t", round(entity.confidence_score, 2), "\tOffset: \t", entity.offset, "\n")
except Exception as err:
print("Encountered exception. {}".format(err))
entity_recognition_example(client)
実行結果:
Named Entities:
何も検出されませんでした・・。(日本語のエンティティ検出性能は、もしかするとまだ高くないのかもしれない・・)
キーフレーズの抽出
最後に、キーフレーズの抽出です。ちょっとこのタスクは勉強不足で仕組みに関する理解がなく、コードを流してみるだけですが・・
def key_phrase_extraction_example(client):
try:
documents = ["今日は、朝ご飯を食べた後、公園に散歩に出かけた。天気が良くとても気持ちよかった。"]
response = client.extract_key_phrases(documents = documents,language="ja")[0]
if not response.is_error:
print("\tKey Phrases:")
for phrase in response.key_phrases:
print("\t\t", phrase)
else:
print(response.id, response.error)
except Exception as err:
print("Encountered exception. {}".format(err))
key_phrase_extraction_example(client)
実行結果:
Key Phrases:
公園
天気
気持ち
散歩
以上、Azure Text Analysisサービスで日本語のテキスト分析を試してみました。
AWSやGCPの同様のテキスト分析サービスでできること、日本語対応有無についても調べてみて、比較をしてみたいと思いました。
自然言語処理をもっと学ぶなら・・
Udemyを見てみると、自然言語処理系の講座も結構あるようだったので、もしもっと勉強されたい方がいれば、気になるものを受講してみてはいかがでしょうか。Udemyは自分もよく使うのですが、ボリュームの割に値段も安く、また万が一コンテンツが自分に合わなかった場合は30日の返金保証がある点が魅力で、お勧めです!
自然言語処理とチャットボット: AIによる文章生成と会話エンジン開発 今からでも基礎から学べるPythonによる自然言語処理(NLP):現役データサイエンティストが教える「日本語」文書分類BERTによる自然言語処理を学ぼう! -Attention、TransformerからBERTへとつながるNLP技術-
関連記事
また、自分のブログでは、SNS (Twitter)のテキストデータ抽出や、手動でのテキストマイニング(極性辞書を使う方法)についても試してみていますので、ご興味があればご覧ください!
本日も最後までご覧いただきありがとうございました!
おしまい