Summarinの月次・四半期ニュース分析では、キーワード同士のつながりを図にした「共起ネットワーク」を公開しています。見慣れない方も多いと思うので、この記事では考え方と読み方、そして実際の作り方を説明します。

頻出語ランキングだけでは分からないこと

ニュースの傾向を知りたいとき、まず思いつくのはよく出てくる単語を数えることです。トレンドのページで公開しているのが、まさにこれにあたります。

しかし、この方法には限界があります。上位に並ぶ単語を見ても、それらがどう関係しているのかが分かりません。 「値上げ」と「電気」が両方上位にあったとして、同じ話題なのか、まったく別の文脈なのかは判断できないのです。

共起とは「同じ場所に一緒に現れること」

そこで使うのが共起という考え方です。共起とは、2つの単語が同じ文章の中に一緒に現れることを指します。

  • 「電気」と「値上げ」が同じ記事に何度も一緒に出てくる → 関係が強い
  • 「電気」と「野球」がたまたま1回だけ同じ記事に出た → 関係は弱い

この「一緒に出てくる度合い」を単語のすべての組み合わせについて計算し、関係の強いものだけを線で結ぶと、単語のつながりが図として見えてきます。これが共起ネットワークです。

図の読み方

  • 丸(ノード) が単語です。よく出てくる単語ほど大きく表示されます
  • 線(エッジ) が単語同士のつながりです。一緒に出てくる度合いが強いほど太くなります
  • 線でつながった単語の集まりが、その期間の話題のかたまりになります

共起ネットワークの例。「選手」「大会」「決勝」「試合」「代表」などサッカー関連の単語が密に結ばれ、ひとつのかたまりを作っている

上の図では、「選手」「大会」「決勝」「試合」「代表」「ゴール」「得点」といった単語が互いに太い線で結ばれ、左側にひとつのかたまりを作っています。この期間はサッカーの大会が大きな話題だったことが、記事を読まなくても分かります。「スペイン」「イラン」といった国名がそのかたまりにぶら下がっているので、対戦相手まで推測できます。

一方、右下の「発表」「結果」「中国」は、このかたまりとは別の線でつながっています。同じ期間に動いていた別の話題です。

離れた場所にある小さなかたまりは、その期間の中では独立した話題だったことを示します。逆に、多くの単語とつながっている大きな単語は、その期間の話題全体に関わっていたと読めます。図では「日本」がそれにあたり、スポーツの話題にも、それ以外の話題にも線が伸びています。

Summarinでの作り方

ここからは実装の話です。記事を単語に分け、つながりを計算し、図として描くまでを順に説明します。

1. 単語に分ける(形態素解析)

形態素解析にはJanome(janome.tokenizer.Tokenizer、バージョンは0.5.0)を使っています。MeCabのように辞書を別途用意する必要がなく、Janome内蔵のIPADICをそのまま使えるため、辞書を外から指定する処理は書いていません。

集計に使うのは表層形ではなく原形(token.base_form)です。「値上げし」と「値上げする」のような活用の違いを、同じ単語として数えるためです。

解析の対象は、各記事のタイトルと本文を連結したテキストです。

2. 対象にする単語を絞る

対象は名詞だけです。そのうえで、次のものを除外しています。

  • 品詞細分類が「数」「非自立」「接尾」「代名詞」の名詞
  • 1文字の単語
  • ストップワード21語(「こと」「もの」「さん」「ニュース」「速報」「午前」「今回」「明らか」など)

ニュース記事には「速報」「午前」のように、話題と関係なく繰り返し現れる語があります。これらを残すと、どの期間の図にも同じ単語が居座ってしまいます。

さらに、出現回数(延べ数)の上位75語だけをノードにしています。すべての単語を載せると線が絡まって読めなくなるため、上限を設けています。

3. つながりの強さを計算する(Jaccard係数)

共起の強さにはJaccard係数を使っています。

Jaccard = 共起記事数 ÷ (w1の出現記事数 + w2の出現記事数 − 共起記事数)

共起を数える単位は1記事です。各記事に含まれる単語を集合(set)にして重複を除き、同じ記事に出たペアを1回と数えます。同じ記事の中で何度も隣り合っていても、1回として扱います。

単純な共起回数ではなくJaccard係数を使うのは、出現回数の多い単語が有利になりすぎるのを防ぐためです。よく出てくる単語はあらゆる語と共起してしまうので、回数そのままでは「何にでもつながる単語」が中心に居座ります。

なお、ノードの大きさに使う count は延べ出現回数ですが、Jaccardの計算には出現記事数を使っています。数える単位が違う点に注意してください。

4. 線を引く閾値を決める

Jaccard係数が閾値以上のペアにだけ線を引きます。閾値は分析する期間に応じて使い分けています。

期間閾値
月次0.12
四半期0.09

統計的な基準やエッジ数の指定から自動で決めるような処理は入れておらず、図を見ながら手で調整した値です。期間が長くなるほど記事数が増えて共起が薄まるため、四半期では低めに設定しています。

5. 図を描く(vis-network)

描画はブラウザ側で行っています。使っているのはvis-network(vis.jsのネットワーク描画ライブラリ)です。

流れはこうです。

  1. バッチ処理が、ノードとエッジをまとめたJSONをCloud Storageへ書き出す
  2. ブラウザからの要求を受けて、サーバーがそのJSONを中継して返す(ブラウザから直接取得するとCORSで弾かれるため)
  3. 受け取ったJSONを vis-network に渡して描画する

主な設定は次のとおりです。

  • ノード は円(dot)で、出現回数に応じて直径15〜45の範囲で大きさが変わります。色も出現回数に応じて3段階の青にしています
  • エッジ はJaccard係数を太さに反映させ、灰色の半透明にしています。線が多くても背景に沈むようにするためです
  • 配置 は物理シミュレーションに任せています(forceAtlas2Based)。つながりの強い単語同士が引き合い、関係のない単語は離れていくので、話題のかたまりが自然に分かれて見えるのがこの方式の利点です
  • 1,000回の反復で配置を安定させてから表示し、その後はドラッグやズームで動かせます

配置を座標として固定していないので、同じデータでも表示するたびに向きや位置は変わります。図の上下左右には意味がなく、意味を持つのは「どの単語が近いか」だけです。

月次・四半期という単位にした理由

日単位では、単語の組み合わせが少なすぎて図になりません。逆に年単位では、話題が多すぎて線が絡まり読めなくなります。1か月から3か月という単位が、ちょうど話題のかたまりが見える粒度でした。

実際に見てみる

月次・四半期ニュース分析で、実際の共起ネットワークを公開しています。期間を切り替えると、話題のかたまりが移り変わっていく様子が見えます。ノードはドラッグで動かせるので、絡まって見えるときは引っ張って確かめてみてください。

日単位の分析はAI日次ニュース分析に、頻出語のランキングはトレンドにあります。