やってみよう分析！第7章： Google Charts Sankey Diagramを使ってデータ可視化

#はじめに

今回も始まりました。[やってみよう分析！シリーズ](http://qiita.com/f81@github/items/78c0855408317e83aa66)

前章まではExcelに着目してきましたが、本章ではデータの可視化に注目してみます。特に[Google Charts Sankey Diagram](https://developers.google.com/chart/interactive/docs/gallery/sankey?hl=ja)を取り上げます。 __Sankey Diagramは簡単に表すと、人や物等の流量を視覚的に表現した図です__。Sankey DiagramはGoogle Charts以外でも描画できるのですが、Javascriptなどに詳しくなくても比較的容易にSankey Diagramを扱えると思われるのがGoogle Charts Sankey Diagramです。

本章で取り扱う項目は以下のものです。

* Sankey Diagramとは
* Google Charts Sankey Diagram 
* データ準備例(Excelを使う)

では早速始めましょう！

##Sankey Diagramとは
Google Analyticsを使ったことのある方ならばユーザーフローで下記のような図を見たことがあるかもしれません。

![fig01.png](https://qiita-image-store.s3.amazonaws.com/0/40982/7e1bd3a9-e070-e2fd-d57b-50814ff0a0fb.png)

例えばGoogle Analyticsでは、ユーザがあるウェブページから別のウェブページにどれくらいの人数が遷移したかを視覚的にフローの方向とフローの太さで表現されています。このように、ある遷移状態を流量とともに表現した図を一般に __Sankey Diagram__と呼ぶそうです。

Sankey Diagramは本章で紹介する[Google Charts Sankey Diagram](https://developers.google.com/chart/interactive/docs/gallery/sankey?hl=ja)以外にも[javascript library](http://tamc.github.io/Sankey/)や[D3.js](http://bost.ocks.org/mike/sankey/)でも扱うことが可能です。一方で、Google ChartsのSankey Diagramは扱いが簡潔で詳しいjavascriptの知識がなくても使うことが可能です。本章はGoogle Charts Sankey Diagramを紹介します。

##Google Charts Sankey Diagram
とりあえず、細かいことは抜きに下記のHTMLをhtml形式でエディタ等に保存して、それをブラウザで開いてみましょう( __HTML5が動作する環境で実行してください__)。

```html
<html>
<head>
<script type="text/javascript"
  src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1.1','packages':['sankey']}]}">
</script>

<div id="sankey_basic" style="width: 900px; height: 300px;"></div>

<script type="text/javascript">
   google.setOnLoadCallback(drawChart);

   function drawChart() {
    var data = new google.visualization.DataTable();
    data.addColumn('string', 'From');
    data.addColumn('string', 'To');
    data.addColumn('number', 'Weight');
    data.addRows([
		[ 's' , 'a', 5 ],
		[ 's' , 'b', 3 ],
		[ 's' , 'c', 2 ],
		[ 'a' , 'd', 2 ],
		[ 'a' , 'e', 5 ],
		[ 'b' , 'd', 1 ],
		[ 'c' , 'e', 1 ],
		[ 'c' , 'd', 1 ],
    ]);
    
    // Set chart options
    var options = {
      width: 500,
      sankey:	{ node: { nodePadding: 80, 
      					label : {	fontName: 'Times-Roman',
      								fontSize: 14,
      								color: '#871b47',
      								bold: true,
      								italic: true } } },
    };
    // Instantiate and draw our chart, passing in some options.
    var chart = new google.visualization.Sankey(document.getElementById('sankey_basic'));
    chart.draw(data, options);
   }
</script>
</head>
</html>
```

うまく動作すれば、本記事最上部の図が出力されるはずです。
以下、上記HTMLの意味を解説していきたいと思います(最低限のHTMLの使い方は理解しているとします)。

####基本の枠をhtmlファイルに用意する
最低限のhtmlファイル構成として次のものを準備します。

```html
<html>
<head>

</head>
</html>
```

このheadタグの中にGoogle Charts APIの呼び出しなどの命令を記述していきます。

####google charts apiのSankey Diagramを呼び出す
Sankey Diagramを呼び出すために下記のscriptを挿入します。これは呼び出すための決まった命令文です。

```html
<script type="text/javascript"
  src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1.1','packages':['sankey']}]}">
</script>
```

####フローを描画する領域を準備
ブラウザ上にSankey Diagramを表示するための領域をdiv要素で準備します。

```html
<div id="sankey_basic" style="width: 900px; height: 300px;"></div>
```

####scriptタグ内にSankey Diagramを描画する命令を書いていく
scriptタグを準備して、直下にsetOnLoadCallbackメソッドでページが読み込まれた時にdrawChart関数(以下で定義される)が呼び出されるようにする。

```html
<script type="text/javascript">
   google.setOnLoadCallback(drawChart);
```

次に呼び出されるdrawChart()関数を定義します。

```html
   function drawChart() {
    var data = new google.visualization.DataTable();
    data.addColumn('string', 'From');
    data.addColumn('string', 'To');
    data.addColumn('number', 'Weight');
    data.addRows([
        [ 's' , 'a', 5 ],
        [ 's' , 'b', 3 ],
        [ 's' , 'c', 2 ],
        [ 'a' , 'd', 2 ],
        [ 'a' , 'e', 5 ],
        [ 'b' , 'd', 1 ],
        [ 'c' , 'e', 1 ],
        [ 'c' , 'd', 1 ],
    ]);

    // Set chart options
    var options = {
      width: 500,
      sankey:   { node: { nodePadding: 80, 
                        label : {   fontName: 'Times-Roman',
                                    fontSize: 14,
                                    color: '#871b47',
                                    bold: true,
                                    italic: true } } },
    };
    // Instantiate and draw our chart, passing in some options.
    var chart = new google.visualization.Sankey(document.getElementById('sankey_basic'));
    chart.draw(data, options);
   }
```

この関数が実行している命令を書き出すと次のようになります。

* data変数にフローを描画するためのデータを格納するテーブル(オブジェクト)を代入します。
* dataオブジェクトのaddColumnメソッドでカラムのデータ型とデータ種類を`data.addColumn(データ型, データ種類)`のように定義します。
* データ種類は始点`'From'`、終点`'To'`、フローの幅`'Weight'`で指定します。
* ノード始点を('string', 'From')、ノード終点を('string', 'To')、フローの太さを('number', 'Weight')でテーブルに指定。
* addRowsメソッドでデータを挿入。 __多次元配列(ここでは行数×3列の配列)を渡します__。
* 列はadColumnメソッドで定義したように左からノード始点(From)、終点(To)、フローの太さ(Weight)とデータが並んでいます。
* option変数に表示オプションを記憶させる。widthは画面表示された時の図の幅を指定しています。
*  __sankeyオプションは省略可能__。ここではノードのラベルフォントや広がりを指定しています。
* ここまではSankey Diagramに入力するデータとオプションの準備。
* id="sankey_basic"のdiv要素を見つけ、そこにSankey Diagramを表示することをchart変数に覚えさせます。
* chartのdrawメソッドで、data, optionを引数に渡してフローを表示。

最後に`</script>`でscriptタグを閉じます。

##データ準備例(Excelを使う)
実際にGoogle Charts Sankey Diagramを使った感じですと、データを挿入するaddRowsメソッドに渡している配列の部分以外はほとんど固定です(オプションも頻繁には変更しないと思われます)。言い換えればaddRowsメソッドの配列部分を用意する処理を何らかの方法で準備できれば、Sankey Diagramが簡単に出力されます。このためHTMLやJavaScriptに詳しくない方でもSankey Diagramを描画させることができると思います。

ここで非常に簡単なデータを使ってSankey Diagram用のデータをExcelで作ってみます。使うテストデータは下記のものです。

uu|seq|To|flag
|---|---|---|---|
uu1|0|a|1
uu1|1|a|1
uu1|2|a|1
uu1|3|a|1
uu1|4|b|1
uu2|0|b|1
uu2|1|a|1
uu2|2|b|1
uu2|3|b|1
uu2|4|b|1
uu3|0|b|1
uu3|1|a|1
uu3|2|b|1
uu3|3|a|1
uu3|4|b|1
uu4|0|b|1
uu4|1|b|1
uu4|2|a|1
uu4|3|b|1
uu4|4|b|1
uu5|0|b|1
uu5|1|b|1
uu5|2|a|1
uu5|3|a|1
uu5|4|a|1

このデータは5人のユーザ`uu1`から`uu5`が2つのクリエイティブ(バナー広告)`a`, `b`を見たデータを時系列で並べたものと仮定しています。見た状態をflag=1で表しています。このデータから`a`と`b`のクリエイティブを見たユーザ数が時間とともにどのように推移しているかsankey diagramで可視化してみましょう。

まず上記のデータを下記の図のようにExcelに貼り付けます。

![fig03.png](https://qiita-image-store.s3.amazonaws.com/0/40982/4d080c93-0d62-364b-961e-a3afc9059635.png)

セル`D1`に`From`ラベルを記入。セル`D3`に`=IF(A2=A3,C2,IF(B3=0,"",C3))`と数式を挿入してセル`D26`までコピーペーストします。この処理はD列に1つ前に見た`To`のクリエイティブをラベリングするためのものです。これによって`seq>0`の行に対してユーザごと1区間あたり始点から終点への遷移状態を表すことができます(例えば`uu1`が`a`を見て`a`を見たというイベントが1回発生ということがわかります)。seqごとにflagの数をカウントすることで`event(t-1) ==> event(t)`のペアが何回起きたか集計できます。この数値をsankey diagramに表示することができれば、ユーザフローを可視化することができます。これを実行するために、上記のデータを更にpivotで集計してみます。

![fig04.png](https://qiita-image-store.s3.amazonaws.com/0/40982/5cd21b4c-2c38-7eb9-196b-8e769a0db989.png)

セル`A1`からセル`E26`を選択してpivotします。ここでは便宜上、同一セル上にピボットテーブルを表示しました。 __行には`seq`, `From`, `To`の順に上からフィールドを設定します__ (順番に注意してください)。∑値にはflagの合計を設定します。更に`From`と`To`にフィルターを掛けて空白とラベルなしのもののチェックを外します。これによって下記のようなテーブルが表示されます。

![fig05.png](https://qiita-image-store.s3.amazonaws.com/0/40982/5f1b85e1-d148-6c61-0b33-f58d6c6422fd.png)

ピボット領域のセル`H2`からセル`K14`までを選択してセル`H18`から貼付けします。`seq`や`From`の列の空白は空白から上にさかのぼって空白ではないセルのラベルをコピーペーストします。

![fig06.png](https://qiita-image-store.s3.amazonaws.com/0/40982/3fa7b633-1068-1cc0-4267-7605b64d0593.png)

つぎにセル`M18`に`=$H18&"_"&I18`をセル`N18`に`=($H18+1)&"_"&J18`を入力します。入力したら数式をそれぞれセル`M30`, `N30`までコピーペーストします。

![fig07.png](https://qiita-image-store.s3.amazonaws.com/0/40982/3de7d1c0-9ba5-ef92-3a40-ec7bfe8ee8b0.png)

最後にセル`P18`に`=CONCATENATE("[","'",M18,"'",",","'",N18,"'",",",K18,"]",",")`と入力し、セル`P30`までコピーペーストします。

![fig08.png](https://qiita-image-store.s3.amazonaws.com/0/40982/1ea4e4fe-9b4a-4391-f571-572acfdbeb5b.png)

上記で出来たデータをHTMLサンプルのaddRowsメソッドに下図のようにコピーして挿入します。

![fig11.png](https://qiita-image-store.s3.amazonaws.com/0/40982/4a349379-bb94-c91e-23a3-b95067cea315.png)


これを保存してブラウザで表示すると下図のようなSankey Diagramが表示されます。

![fig02.png](https://qiita-image-store.s3.amazonaws.com/0/40982/536c22d5-56c4-f0d3-f1d4-b2f27016b978.png)

この例では2つのクリエイティブ`a`, `b`を扱いました。しかしフローを描くときのラベルには`1_a`のように先頭に __何回目の閲覧なのか明確化させていました__。 __これは、Google Charts Sankey Diagramのページによると、下記のようにサイクリックなラべリングではうまく図が表示されないからです__。
`Avoid cycles in your data: if A links to itself, or links to B which links to C which links to A, your chart will not render.`

####addRowsメソッドに同時挿入可能な行数
厳密に調査していませんが、自分が挿入可能なデータ行数を調べてみたところ、どうやらaddRowsメソッドに __800行程度__以上データを挿入しようとするとGoogle Charts Sakey Diagramが表示されなくなるようでした。

##まとめ
本章ではGoogle Charts Sankey Diagramを紹介してきました。Sankey Diagramを使うと人や物の流量を視覚的に表示することが可能です。Google Charts Snakey Diagramは扱えるデータに上限があるものの、記述するスクリプトの量も少なく使い方も簡単で、定められた形式にデータを加工するとすぐにSankey Diagramを表示させれることが魅力でした。データを上手く要約することでちょっとしたユーザ行動ログの可視化なんかに使えそうです。ここで紹介したデータ下処理をExcelではなく別の言語で処理して自動化してみるなんてのも応用の可能性が広がりそうですね。皆さん、ぜひいろいろ試してみてください！

===========================================

##こちらもよろしくおねがいいたします。

* [目次](http://qiita.com/f81@github/items/78c0855408317e83aa66)

###入門編

###第1部イントロダクション
* [第1章：分析技術の活用～ビジネス視点から～](http://qiita.com/msano/items/2f39517b4cd65e14003e)
* [第2章：分析手法を眺めてみよう！](http://qiita.com/msano/items/bfdb3c04d59992c7ebcb)

###第2部エクセルで学ぶ分析入門 
* [第3章：ExcelとMySQLの連携](http://qiita.com/msano/items/fdcc0cbb8e41b988ce2d)
* [第4章：ExcelとMySQLの連携2 csvデータのimport ](http://qiita.com/msano/items/7dff8bc241799875b7e9)
* [第5章：Excelの分析ツールとソルバーの活用(回帰、最小2乗法)](http://qiita.com/msano/items/dc96da37ce8ddd4a7c1d)
* [第6章：Excelソルバーの応用(ポートフォリオ最適化)](http://qiita.com/msano/items/46d92aadbfcb1423e1ec)

==================
# お知らせ：Fringe81エンジニアチームでは仲間を募集しています！
　<img src="http://www.fringe81.com/images/common/logo_fringe81.png" border="0"><br>
　チームの雰囲気や採用情報については下記ページをご覧下さい。<br>

- [Fringe81エンジニアチームのページ](http://www.fringe81.com/tech.html)
- [採用情報ページ](http://www.fringe81.com/recruit/)