Help us understand the problem. What is going on with this article?

D3.js で文書の特徴となる語彙を可視化する

More than 5 years have passed since last update.

今回は前回の記事で青空文庫の作品から抽出した語彙を D3.js を利用して可視化してみます。

完成形のデモアプリケーションはこちらから閲覧できます。
(うまく表示されない場合はブラウザをリロードしてみてください)

テキストデータを可視化する

これまでテキストデータの扱いを中心に、フィードの使い方だとか、大量の文書から興味関心のある話題をベイジアン分類で抽出する方法、また文書群から TF-IDF を指標として特徴となる語彙を抽出する方法などを説明してきました。

前回の最後に述べたとおり、このように抽出した結果は単に文字列のようなデータとして見せるよりも、可視化ライブラリを使ったほうがよく伝わります。

D3.js で表示するためのデータを作る

過去に D3.js を利用したインタラクティブな可視化デモを作りましたが、同じ要領でアプリケーションを実装し Heroku で動かしてみます。

まずは語彙群をキーとし、その重みを数値で表します。

require 'json'
require 'codecs'

def write_json_data(dic):
    """ 結果を JSON に書き出す関数 """
    arr = [] # JSON 内に 2次元のベクトルを作るのでまずは配列を用意
    for k, v in dic.items():
        for w, s in v:
            # スコアを適当に調整しつつ配列に追加していく
            arr.append([w, str(round(s * 10000 + 100, 2))])

        # Python で日本語を含む辞書を JSON 化するときは
        # このように ensure_ascii を False にすると化けない
        hash = json.dumps({'values': arr},
                          sort_keys=True,
                          ensure_ascii=False,
                          indent=2,
                          separators=(',', ': '))
                          # セパレータも明示してキレイな JSON に

        # ファイルを出力するには codecs.open で
        f = codecs.open(os.path.join(output_dir, k),
                            "w", "utf-8")
        f.write(hash) # 書き出す
        f.close() # ちゃんと閉じる

生成される JSON は、先頭だけ表示するとこんな感じです

{
  "values": [
    [
      "後ろ姿",
      "199.26"
    ],
    [
      "クセ",
      "299.26"
    ],

このように配列の中にキーと値の配列がある二次元配列になります。

D3.js で可視化する

筆者は正直 JavaScript に強くないというかだいぶ苦手なので識者の皆様からの教示を仰ぎたいところです。ひとまず表示さえできれば良いという目標でゴリゴリと書いていきます。

// ノードを追加する
var svg = d3.select("body")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  // JSON データのバインディング
  d3.json('../json/novel_name.json', function(error, data) {
    data.values.forEach(function(d) {
      d.word = String(d[0]); // キー
      d.score = d[1]; // 値
    });
  force
    .nodes(data.values)
    .start();

  var node = svg.selectAll("g.node")
    .data(data.values)
    .enter()
    .append("g")
    .attr("class", "node")
    .call(force.drag);
  // 円の大きさを値をもとに決定する
  // また値に応じて色も変化させる
  node.append("circle")
    .attr("r", function(d) { return d.score * .1; })
    .attr("opacity", .67)
    .attr("fill", function(d){
      if (d.score <= 300) {
        return "#449944"
      } else if (d.score > 300 && d.score <= 500) {
        return "#33AA33"
      } else if (d.score > 500 && d.score <= 750) {
        return "#22CC22"
      } else if (d.score > 750 && d.score <= 1000) {
        return "#11DD11"
      }
    });
  // 語彙、またその値を追加していく
  node.append("text")
    .text(function(d){ return d.word; })
    .attr('fill', '#fff')
    .attr('font-size', 24)
    .attr('dx', -16)
    .attr('dy', -5);
  node.append("text")
    .text(function(d){ return d.score; })
    .attr('fill', '#fff')
    .attr('dx', -25)
    .attr('dy', 15);
  // 演出
  force.on("tick", function() {
    node
    .attr('transform', function(d) {
      return 'translate('+ Math.max(20, Math.min(width-20, d.x)) + ','
        + '' + Math.max(20, Math.min(height-20, d.y)) + ')'; }); 
  });
})

デモアプリケーションの完成

あとは Heroku に git push すれば完成です。

heroku create myapp
git push heroku master
heroku open

D3.js デモアプリケーション
http://d3js-data-clips.herokuapp.com/

まとめ

今回は D3.js を使って得られた特徴を可視化し Heroku で動かしました。

この時点で文書を特徴づける単語の羅列と数値が得られていますから、他のデータソースと突き合わせたり、複数の文書間での関連性を調べたりといった風に応用していくこともできるかと思います。

dts
コンサルティングから設計、開発、HW/SWの選定、運用、保守までシステムをサポートする総合情報サービス企業です。
http://www.dts.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away