* この投稿は米国時間 7 月 20 日、Developer Advocate である Sara Robinson によって投稿されたもの(投稿はこちら)の抄訳です。

テキストから意味のあるデータを簡単に抽出して分析したいと思ったことはありませんか? 今はそれが可能です。新しい Google Cloud Natural Language API には、API を 1 つ呼び出すだけで、テキストからエンティティ(人、場所、出来事など)を抽出できる機能があります。

最近のニュース記事から取り出してきた次の文を使って試してみましょう。

LONDON — J. K. Rowling always said that the seventh Harry Potter book, “Harry Potter and the Deathly Hallows,” would be the last in the series, and so far she has kept to her word.
(ロンドン発 ─ J. K. Rowling 氏は常々、ハリー・ポッター シリーズは 7 冊目の『ハリー・ポッターと死の秘宝』が最後になると述べており、今まではその言葉に従ってきました)

この文で触れられている人や場所を探すアルゴリズムを独自に書けないわけではありませんが、容易ではないでしょう。さらには、同じエンティティに対する表現方法の違い(たとえば、“Rowling” と “J. K. Rowling”)を考慮に入れながら、触れられている個々のエンティティに関するデータを集めようとすれば、あるいは数千もの文の中でエンティティを分析しようとすれば、より難しくなります。

Cloud Natural Language API を使用すれば、上の文は analyzeEntities メソッドで分析できます。

API は、2 人の人(実在の人と虚構の人)と 1 つの場所が言及されていることを教えてくれます。また、個々のエンティティに関して、対応する Wikipedia URL を返します。さらには、“Rowling”、“J.K. Rowling”、あるいは “Joanne Kathleen Rowling” と書かれていたとしても、同じエンティティのことだと判断します。

実際に API の応答を見てみましょう。
"entities": [
   {
     "name": "Rowling",
     "type": "PERSON",
     "metadata": {
       "wikipedia_url": "http://en.wikipedia.org/wiki/J._K._Rowling"
     },
     "salience": 0.58328295,
     "mentions": [
       {
         "text": {
           "content": "J. K.",
           "beginOffset": -1
         }
       },
       {
         "text": {
           "content": "Rowling",
           "beginOffset": -1
         }
       }
     ]
   },
   {
     "name": "LONDON",
     "type": "LOCATION",
     "metadata": {
       "wikipedia_url": "http://en.wikipedia.org/wiki/London"
     },
     "salience": 0.13440432,
     "mentions": [
       {
         "text": {
           "content": "LONDON",
           "beginOffset": -1
         }
       }
     ]
   },
   {
     "name": "Harry Potter",
     "type": "PERSON",
     "metadata": {
       "wikipedia_url": "http://en.wikipedia.org/wiki/Harry_Potter"
     },
     "salience": 0.05211971,
     "mentions": [
       {
         "text": {
           "content": "Harry Potter",
           "beginOffset": -1
         }
       },
       {
         "text": {
           "content": "Harry Potter",
           "beginOffset": -1
         }
       }
     ]
   }]

トップ ニュースのトレンド分析

API で 1 つの文を分析できるというのは素晴らしいことですが、経時的にテキストに含まれるエンティティを分析できればもっとよいのではないでしょうか。しかも、ニュースにはエンティティがたくさん含まれています。そう考えた私は、ニューヨーク・タイムズの Top Stories API を使って最新ニュースのデータを集めることにしました。

Top Stories API を呼び出し、タイトルと要約を Natural Language API に送ってエンティティを分析し、記事とエンティティ データを Google BigQuery テーブルに挿入しました。BigQuery のエンティティ データを使えば、トップ ニュースで触れられているエンティティを分析するクエリを実行し、結果を Google Data Studio でビジュアライズできます。

API の analyzeEntities メソッドをもう少し深く掘り下げてみましょう。

私たちの例では、記事の要約のテキストを使って Natural Language API のエンティティ分析要求を組み立てます。
var requestUrl = 
"https://language.googleapis.com/v1beta1/documents:analyzeEntities?key=MY_API_K
EY"

var requestBody = {
   "document": {
       "type": "PLAIN_TEXT",
       "content": nytText
   }
}

var options = {
   url: requestUrl,
   method: "POST",
   body: requestBody,
   json: true
}

request(options, function(err, resp, body) {
   if (!err && resp.statusCode == 200) {
       var entities = body.entities;
       for (index in entities) {
           var entity = entities[index];
           console.log(entity);
       }
   } else {
       console.log('NL API error: ', err);
   }
}

応答は、テキストに含まれる個々のエンティティをまとめたオブジェクトです。個々のエンティティについて、name(名前)、type(タイプ)、metadata(メタデータ)、salience(顕著性)、mentions(言及箇所)をまとめたオブジェクトが得られます。先ほどの例文に含まれる 1 つのエンティティを例に、API の応答を見てみましょう。

{
 "name": "Rowling",
 "type": "PERSON",
 "metadata": {
   "wikipedia_url": "http://en.wikipedia.org/wiki/J._K._Rowling"
 },
 "salience": 0.58328295,
 "mentions": [
   {
     "text": {
       "content": "J. K.",
       "beginOffset": -1
     }
   },
   {
     "text": {
       "content": "Rowling",
       "beginOffset": -1
     }
   }
 ]
}
エンティティの type は 8 種類あります(詳細はこちら)。最も多いのは PERSON と LOCATION です。現在の API では、metadata はエンティティの Wikipedia URL です(エントリがある場合)。salience は、そのテキスト内でのエンティティの重要度を 0~1.0 の範囲で示します。mentions は、エンティティがテキストのどこにあるのかを示すインデックスです。

BigQuery を使ったエンティティ トレンドの分析

ニューヨーク・タイムズの個々のトップ ニュースからエンティティを集めることができたので、一歩先に進み、指定された日または週のエンティティのトレンドを BigQuery で探してみましょう。

最初のステップは、個々のエントリの BigQuery テーブルへの挿入です。以下のように、gcloud Node client library を使って BigQuery にアクセスし、初期化します。
var gcloud = require('gcloud')({
 keyFilename: 'your-keyfile.json',
 projectId: 'YOUR-PROJECT-ID'
});

var bigquery = gcloud.bigquery();
var dataset = bigquery.dataset('your-BigQuery-dataset-name');
var table = dataset.table('your-BigQuery-table-name');
次に、エンティティ データと記事の関連メタデータから、エンティティごとに 1 つの行を作ります。


var row = {
   entity_wiki_url: wiki_url,
   entity_name: entity.name,
   entity_type: entity.type,
   article_section: article.section,
   article_created_date: article.created_date,
   article_url: article.url,
   article_abstract: article.abstract
}

table.insert(row, function(error, insertError, apiResponse) {
   if (error || insertErr.length != 0) {
       // Handle error
   } else {
       // Successfully inserted into our table!
   }
});

BigQuery にデータが収まったので、分析に取りかかります。分析には BigQuery のウェブ UI を使います。まず、次のクエリにより、最も言及の多いエンティティを探しましょう。
SELECT entity_wiki_url, COUNT(entity_wiki_url) as entity_count FROM
[sara-bigquery:nytdata.entities_from_abstracts]
GROUP BY entity_wiki_url
ORDER BY entity_count DESC
結果を Google Data Studio でビジュアライズすると、次のようになります。


Natural Language API から返された entity_type で結果をフィルタリングするようにクエリを書き換えれば、最近のニューヨーク・タイムズの記事に最も頻繁に登場する人物と場所がわかります。


Natural Language API を使った感情分析

Natural Language API は、エンティティを抽出するだけでなく、テキスト ブロックの感情分析も行います。analyzeSentiment エンドポイントを使うように要求 URL を書き換えるだけなので、前述の例と同じコードのように見えます。
var sentimentUrl = 
"https://language.googleapis.com/v1beta1/documents:analyzeSentiment?key=MY_API_
KEY";
応答は、polarity(極性)と magnitude(大きさ)の 2 つの値を持つオブジェクトです。

polarity は、内容がポジティブかネガティブかを示す -1.0 から 1.0 までの数値です。magnitude は、polarity にかかわらず、文章に表現されている感情の大きさを 0 から無限大までの数値で示します。評価のウェイトが高い文を集めて長いテキスト ブロックを作ると、magnitude の値も大きくなります。

次の文を Natural Language API で処理してみましょう。

I love everything about Harry Potter.
(私はハリー・ポッターのすべてが好きだ)

次のような応答が API から返されます。
{
 "documentSentiment": {
   "polarity": 1,
   "magnitude": 0.9
 }
}

“love” という単語のおかげで文の polarity は 100 % ポジティブと判定されていますが、magnitude はさほど高くありません。

それに対して次の文では、polarity は一気にネガティブになり、magnitude は小さくなっています。

With a new set of movies on the horizon, some fans worry that Ms. Rowling will make the same mistake that George Lucas did after the three original “Star Wars” films, producing inferior work that detracts from the brilliance of the original.
(新しい映画シリーズが近く公開されるということで、一部のファンは、『スター・ウォーズ』シリーズのオリジナルの 3 本のあとで、その輝きを曇らせる駄作を製作してしまった George Lucas 氏と同じ過ちを Rowling 氏が犯すのではないかと、やきもきしている)

{
 "documentSentiment": {
   "polarity": -1,
   "magnitude": 0.4
 }
}
polarity がマイナスになったのは、ネガティブな単語(“worry”、“mistake”、“inferior”、“detracts”)が多数含まれているからです。これらの単語全体の強さによって magnitude が決まります。

トップ ニュースの感情分析

それでは、エンティティ抽出の例で使用したニューヨーク・タイムズの API から得られたトップ ニュースの要約を Natural Language API に送り、感情分析を行ってみましょう。

この例では、各行が記事の要約と polarity、magnitude からなる別の BigQuery テーブルに結果を挿入します。

次のクエリでは polarity と magnitude を掛けて、すべての記事の平均的な感情を探っています。

SELECT AVG(polarity * magnitude) as avg_sentiment 
FROM [sara-bigquery:nytdata.article_sentiment]

各セクションの平均的な感情を以下のクエリで調べれば、この値と比較できます。
SELECT section, COUNT(section) as num_articles_per_section, ROUND(AVG(polarity 
* magnitude), 2) as avg_section_sentiment 
FROM [sara-bigquery:nytdata.article_sentiment]
GROUP BY section
ORDER BY num_articles_per_section DESC
結果を Data Studio でビジュアライズすると、次のようになります。



このニュース データのサブセットによると、感情値が最も低いのは米国のニュースであり、最も高いのはアートのニュースです。

セクションごとの感情分析だけでなく、特定のエンティティが登場するすべての記事の要約に対して感情分析を行うことも可能です。下のグラフは、“United States” というエンティティが含まれるすべての記事の日ごとの平均感情値を示しています。



そして次へ

この投稿で挙げた例は、Natural Language API でできることのほんの一部に過ぎません。数週間もしくは数か月分のニュース記事、あるいは複数のソースから得られたテキスト データの場合は何かできるのか、想像してみてください(ここではテキスト アノテーションについて触れてさえいないのです)。

独自アプリケーションを使って、ぜひエンティティ分析を試してみてください。感情分析やテキスト アノテーションも使ってみてください。そして、こんなものを作ったというコメントをぜひお寄せください。Twitter の @SRobTweets でもコメントをお待ちしています。

- Posted by Sara Robinson, Developer Advocate