Treasure Data Analytics 第4回 〜ブックレビューデータセットによるデータ解析入門(実践編1)〜

 

はじめに

準備編ではデータセット:Book-Crossing Dataset を用意し, Treasure Data のツールベルト一式を導入した上でインポートし,簡単なクエリを実行するところまで行いました。本シリーズでは Treasure Data のデモアカウントが必要になりますのでまだの方は準備編の方を先に参照下さい。

今回は「データを俯瞰する」をテーマに,解析対象としているデータセットがどのような姿をしているのかを視野広く眺めることにしましょう。このフェーズでは全く難しいことは行いません。ここでのキーポイントは

  • セグメント:ノードやアクションのステータスから様々なセグメントを作成しその分布を眺める

というステップを地道に行う事にあります。それによってどの「切り口」でデータを深掘りしていけば良いかが見えてくるのです。

 

データを俯瞰する

データ解析は解析対象とするデータセットの概要を知ることから始まります。ここではこのフェーズを「データを俯瞰する」と呼ぶことにし,以下の 2 の基本行程を指すことにします。

  • (a) 数や平均などの基本情報の確認
  • (b) ノード・アクションの持つステータスに基づくセグメントの分布の観察

※ ノードという言葉は準備編の Property Graph の文脈に基づいたもので,ユーザーやモノなど,アクションの主体または対象となる概念を意味します。

(a) 基本情報は「どれくらいの数のユーザー・ブックが登録されているのか」,「その中でアクティブな数(評価しているユーザー,評価されているブック)がいくつなのか」などの,主に各々の項目の数と平均を表す最も基本的な情報です。

(b) ステータスに基づくセグメントの分布とは例えば「ユーザーの年代による人数分布」,「ブックの出版年ごとの登録数」など,年齢や出版年というステータスに基づくセグメントごとの分布を指します。

※ 次回は様々なセグメントの分布を眺めた上で有効であろういくつかの代表セグメントを用いてデータを分析している事例を紹介します。

 

td query について

実際に td query を実行していく前にいくつかの注意点を挙げ,準備としてスキーマ定義を行っておきます。

td query におけるカラムの指定は v['book_rating'] の様にカラム名を v[ ] で囲って使用します。また,全てのカラムはデフォルトでは string として扱われることに注意して下さい。これを事前にスキーマ定義しておき, book_rating のような指定方法でかつ book_rating を int 型として初めから扱うようにしておくと記述の簡潔性,安全性,処理効率の面でメリットがあります。

そこで今回使用するカラムにもスキーマを設定しておくことにしましょう。

$ td schema:set book_crossing_dataset users   user_id:string age:string  country:string location1:string location2:string
$ td schema:set book_crossing_dataset books   user_id:string isbn:string year_of_publication:int book_title:string
$ td schema:set book_crossing_dataset ratings user_id:string isbn:string book_rating:int publisher:string

このコマンドによって指定されたカラムは以後 v[ ] で囲むこと無く,かつ指定した型で扱うことができます。 

それではここから実際に「データを俯瞰する」作業を開始していきましょう。以下,全ての解析クエリは gist に掲載していますのでぜひ手を動かして見て下さい。

 

1. 基本情報

1.1 登録ユーザー数,アクティブユーザー数

まずは今回のデータセットにはどれくらいのユーザーが含まれていて,かつ少なくとも 1 冊以上のブックに対して評価を行っているユーザー(アクティブユーザー)がどれだけいるのかを見ていきましょう。

Query 1.1.1

Result     :
+-----------+--------------+-------------+
| all_users | active_users | active_rate |
+-----------+--------------+-------------+
| 278858    | 105283       | 38          |
+-----------+--------------+-------------+

28 万登録ユーザーに対し,10 万人のアクティブユーザーでアクティブ率は 38% であることがわかります。

ただし後の登録ブック数の方を見てもらえばわかりますが,必ずしも登録ユーザー (users テーブルに存在するユーザー)がアクティブユーザー(rating テーブルに存在するユーザー)を包含するとは限りません。そこで次に,users テーブルのみに含まれるユーザー,rating ユーザーのみに含まれるユーザー,両方のテーブルに含まれるユーザーを計算してみましょう。

Query 1.1.2

Result     :
+-----------------+--------+
| type            | cnt    |
+-----------------+--------+
| both            | 105283 |
| only in ratings | 0      |
| only in users   | 173575 |
+-----------------+--------+

この結果を持って初めて ratings テーブルに存在する全ユーザーが,users 登録ユーザーに含まれている(i.e. アクティブユーザーのステータスが取得できる)事が言えます。

f:id:doryokujin:20120629144844p:plain

図1:ユーザー集合に関するベン図。rating テーブルに含まれるユーザーは全て users テーブルに含まれています。

1.2 登録ブック数,アクティブブック数

同じく登録されているブック数とその中で 1 回でも評価を受けたことのあるブック(アクティブブック)数を確認します。

Query 1.2.1 

Result     :
+-----------+--------------+-------------+
| all_books | active_books | active_rate |
+-----------+--------------+-------------+
| 271376    | 340556       | 125         |
+-----------+--------------+-------------+

ratings テーブルに現れるユニークなブックの方が book テーブルの登録ブックより多いようです。

(この原因としてはデータセットの取得された背景が考えられます。このデータセットは 2004 年 8, 9 月 にクローリングによって取得された局所的なデータであることが記されています。今回は具体的な取得方法およびプログラムなどは知ることができませんので,これ以上深掘りできません。)

先ほどと同じように,books テーブルのみ,rating テーブルのみ,両方に存在するブック数を求め,ベン図にしてみます。片方のテーブルのみにしか含まれないブックがいくらか存在するようです。今回の主なデータ解析の目的では,主に双方に含まれるブック(ステータスを取得できるブック)集合が解析の対象になります。

Query 1.2.2

Result     :
+-----------------+--------+
| type            | cnt    |
+-----------------+--------+
| only in books   | 1209   |
| both            | 270167 |
| only in ratings | 70389  |
+-----------------+--------+

f:id:doryokujin:20120629144901p:plain

図2:ブック集合に関するベン図。rating テーブルに含まれるブックの方が多く,books テーブルをほぼ包含しています。

1.3 総評価数,有効評価数,平均評価値

データセットが取得された期間内に全部で何回の評価が行われたのかを確認してみます。この項目:評価の値に関しては 0 〜 10 の値をとるのですが,値 0 は有効な評価が得られなかったという意味で他の値 [1,10] とは扱いが異なることには以後注意する必要があります。

評価平均を計算する場合などは有効な値として評価値を [1,10] に絞って考える方が良さそうです。ここでも有効評価数および平均評価値は [1,10] の値を持つレコードに絞って集計しています。

Query 1.3

Result :

+-------------+-------------------+----------------+
| all_reviews | valid_reviews     | avg_of_reviews |
+-------------+-------------------+----------------+
| 1149780     | 433671            | 7.6            |
+-------------+-------------------+----------------+

全評価数は115 万件にも及びます。ただし,その中で評価値 [1, 10] の値を得られている有効なレコードは 43 万件に過ぎません。有効なレコード全体での評価平均は 7.6 となっています。後ほど評価平均については様々なセグメントから掘り下げられることになります。

 

2. ユーザーステータスに基づくセグメント分布

2.1 ユーザーの居住国分布

ユーザーの居住国による分布を数の多い国TOP20に絞って見てみます。さらに全体の 50% 以上のシェアを持つ居住国:usa ユーザーについて,さらに居住地域の分布を見てみます。

Query 2.1.1

f:id:doryokujin:20120629002148p:plain

図3:ユーザーの居住国の分布。usa に住むユーザーが全体の半分以上を占めています。

Query 2.1.2

f:id:doryokujin:20120629002217p:plain

図4:usa に住むユーザーの,地域ごとの分布を表しています。カリフォルニア州に住むユーザーが多いですが,それを除いて各地域の全体に占める割合は 10% 以下と小さくなっています。なお,ユーザーステータスにはさらにもう一段階詳細な地域 ("location2") の情報を持っています。

2.2 ユーザーの年代分布

次にユーザーの年齢に基づいた 5 歳区切りの年代分布を見てみます。 11歳〜15歳に属するユーザーは generation=15,16歳〜20歳に属するユーザーは generation=20という切り上げベースのセグメントにしていることに注意して下さい。

また,age カラムは必ずしも数値が入っているわけでは無く(不明のものは "NULL" ),かつ正確な値が記入されていない事がわかります。 generation=0 の数は年齢不詳の人数,generation=65* は65歳以上の人数とし,このどちらも有効で無い値として扱うことにします。

Query 2.2.1

Result     :
+------------+--------+
| generation | cnt    |
+------------+--------+
| 0          | 111178 |
| 5          | 492    |
| 10         | 245    |
| 15         | 5543   |
| 20         | 17323  |
| 25         | 25913  |
| 30         | 26348  |
| 35         | 22995  |
| 40         | 17258  |
| 45         | 13756  |
| 50         | 12142  |
| 55         | 10377  |
| 60         | 7219   |
| 65         | 4087   |
| 65*        | 3982   |
+------------+--------+

年齢が不詳のユーザーがかなり多く,また,65歳以上の人数もそれなりにいることが確認できます。今回は有効な年齢の範囲を (10, 65] と定義し,この間での分布を再確認することにします。以下の結果より11歳〜30歳までのユーザーで全体の半分のシェアを持っていることがわかります。

Query 2.2.2

f:id:doryokujin:20120629002448p:plain

図5:ユーザーの年代分布(ヒストグラム)。赤線は10歳からの累積割合を表しており,generation=30 でほぼ 50%,つまり 10 - 30 歳のユーザーが全体の半数を占めていることがわかります。

 

3. ブックステータスに基づくセグメントの分布

3.1 出版年別の分布

続いて同様にブックステータスに基づくセグメントの分布を見ていきましょう。このデータセットは 2004年の8, 9 月に取得されたものなのでそれ以降の出版年があればそれは正しい値では無いと考えられます。また1970年以前の出版年のブックもここでは有効でないと考えることにします。

Query 3.1.1

Result     :
+-------+-------+
| year  | cnt   |
+------ +-------+
| 1970* | 459   |
| 1971  | 540   |
| 1972  | 772   |
...
| 2003  | 14358 |
| 2004  | 5839  |
| 2005* | 72    |
+-------+-------+

1970* は1970年以前のブック,2005* は2005年以降のブックで少ないですが存在していることがわかります。有効な出版年を [1970, 2004] として,これらのブックを除外した分布を改めてヒストグラムと共に見てみましょう。

Query 3.1.2

f:id:doryokujin:20120629002856p:plain

図6:出版年をセグメントにした分布。2000年に至るまではほぼ単調増加となっています(ここではそれほど意味を持たないかも)。2004年はデータセットがこの年の9月までなので数は少なくなっています。

f:id:doryokujin:20120629002918p:plain

図7:出版年を上三桁(1970,1980,...,2000)と下一桁(0,...,9)に分けた 2 つのセグメントでの分布を改めて見ています。図はグリッド上に配置したバブルチャートであり,横に見る事で10年毎のデータ推移,縦に見る事で1年毎の推移が確認できます。このような年(時間軸)を分解したクロスセグメントは他にも(年,季節)の組での周期性を確認したい場合などにも有効です。

3.2 出版社別の分布

出版年の次は出版社の分布です。数の多い上位 10 数件の分布を表示しています。

Query 3.2

f:id:doryokujin:20120629003023p:plain

図8:出版社ごとに見るブック数の分布。特定の出版社に過度に偏っていないことがわかります。

 

4. 評価ステータスに基づくセグメントの分布

評価(review)というアクションの持つステータス(今回は評価値)もまた,セグメント分布をみるための有効な材料となります。

4.1 評価数の分布

まずは,ユーザ当たりの評価数の平均を確認します。

Query 4.1.1

Result     :
+-----+
| avg |
+-----+
| 11  |
+-----+

もちろんこの 11 という平均評価回数はあくまで全体をおしなべた値であり,実際分布デ見てみるとさらに多くの情報を得られることができます。あらゆる値は平均だけでなく分布としてその姿を確認することは常に大切です。次にユーザー当たりの評価回数についての分布を確認してみます。この分布は評価回数が 0 のユーザーは含んでいないことに注意してください。

Query 4.1.2

f:id:doryokujin:20120629003853p:plain

図9:ほとんど(50%以上)の評価経験のあるユーザーは 1 回しか評価をしていないことがわかります。さらに 90% のユーザーは平均値である 11 以下にとどまっていることもわかります。しかしながら,それ以降もヒストグラムが長い尾を持っていることからわかりますように,数少ないながらたくさんの評価を行っているユーザーに引っ張られる形で平均が 11 となっているのです。

4.2 評価平均の分布

ユーザー当たり評価平均についても同じように分布を見る事にします。ちなみに(ユーザを区別しない)全体の評価平均は 1.3 で書いたように 7.6 となっています。

以下の結果が示すように,ユーザー当たりの評価平均は 7.6 を中心に単峰の山を持っています。評価という行動においては,評価値範囲の中心値(=5)のまわりにばらつくのではなく,それよりもずっと大きな値の周りでばらついていることがわかります。

逆に言えば平均的に 5 以下の評価を付けるユーザーはかなりのマイノリティであると言えます。彼らはいわゆる「辛口レビュアー」というクラスタに分類することができそうです。これに関しては次回でもう少しだけ深掘りしていくことにしましょう。

Query 4.2

f:id:doryokujin:20120629003817p:plain

図10:元がどのような分布であってもその平均の値の分布はサンプル数が十分に大きいところでは漸近的に正規分布に従います(中心極限定理)。評価平均の分布もまた平均値 7.6 を中心にした正規分布の姿を持っていますが,評価値が [1, 10] の範囲に限定されているため右側は 10 で打ち切られた分布となっています。

4.3 評価平均×年代による分布

最後に先ほどの評価平均という分布を,ユーザーの年代ごとに確認してみましょう。図10 のヒストグラムが年代ごとに作られるイメージです。これによって年代間で評価の付け方に傾向があるのかがわかるかもしれません。傾向とは,例えば「20台は比較的高評価をつけがちだが,40台は辛口評価である」といったものです。

Query 4.3

結果を評価値を行,年代を列としたピボットテーブルとして表したものが下になります。各セルにはユーザー数が入っています。表だけではわかりにくいのですね。

  2.5 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 9.5 10 合計
15 0 0 0 1 3 3 11 11 23 31 21 24 15 15 8 166
20 0 1 2 1 10 11 43 52 95 114 133 86 64 29 12 653
25 0 2 3 2 19 30 61 115 206 247 260 201 121 41 21 1329
30 0 3 2 9 32 53 99 154 276 361 366 228 126 62 20 1791
35 0 0 4 10 36 61 101 184 275 365 301 199 117 41 16 1710
40 0 1 3 7 27 36 89 136 206 251 237 154 84 35 17 1283
45 1 0 1 4 28 21 59 89 138 163 187 110 69 39 11 920
50 0 2 1 2 16 21 43 49 121 132 124 89 64 17 7 688
55 0 0 2 1 13 18 31 58 83 113 99 68 40 24 5 555
60 0 1 2 0 5 19 32 51 68 70 74 57 46 9 3 437
65 0 0 2 0 3 8 18 15 32 32 36 27 14 9 5 201
合計 1 10 22 37 192 281 587 914 1523 1879 1838 1243 760 321 125 9733

上のピボットテーブルを転置し,各セルの値をユーザー数ではなく列和を 100 としたときの割合として示したテーブルが下になります。2.2 で見たように年代ごとの絶対人数は大きく異なっているので,年代間の比較のためにはこのような正規化した値を参照する必要があります。(転置したのは筆者の都合上で特に意味はありません。)

  15 20 25 30 35 40 45 50 55 60 65
2.5 0 0 0 0 0 0 0.1 0 0 0 0
3.5 0 0.2 0.2 0.2 0 0.1 0 0.3 0 0.2 0
4.0 0 0.3 0.2 0.1 0.2 0.2 0.1 0.1 0.4 0.5 1.0
4.5 0.6 0.2 0.2 0.5 0.6 0.5 0.4 0.3 0.2 0 0
5.0 1.8 1.5 1.4 1.8 2.1 2.1 3.0 2.3 2.3 1.1 1.5
5.5 1.8 1.7 2.3 3.0 3.6 2.8 2.3 3.1 3.2 4.3 4.0
6.0 6.6 6.6 4.6 5.5 5.9 6.9 6.4 6.3 5.6 7.3 9.0
6.5 6.6 8.0 8.7 8.6 10.8 10.6 9.7 7.1 10.5 11.7 7.5
7.0 13.9 14.5 15.5 15.4 16.1 16.1 15.0 17.6 15.0 15.6 15.9
7.5 18.7 17.5 18.6 20.2 21.3 19.6 17.7 19.2 20.0 16.0 15.9
8.0 12.7 20.4 19.6 20.4 17.6 18.5 20.3 18.0 17.8 16.9 17.9
8.5 14.5 13.2 15.1 12.7 11.6 12.0 12.0 12.9 12.3 13.0 13.4
9.0 9.0 9.8 9.1 7.0 6.8 6.5 7.5 9.3 7.2 10.5 7.0
9.5 9.0 4.4 3.1 3.5 2.4 2.7 4.2 2.5 4.3 2.1 4.5
10.0 4.8 1.8 1.6 1.1 0.9 1.3 1.2 1.0 0.9 0.7 2.5

図11:横軸に年代,縦軸に評価平均値を持ったテーブル。各セルの値は各年代のユーザー数を分母とした,評価値を持つユーザーの占める割合です(i.e. 列和が100)。

今回の少し入り組んだ結果の解釈をビジュアライゼーションの力が協力にサポートしてくれる事を理解してもらうために,図11 のテーブルを 6 種類のグラフで表現してみました。列(年代間)の比較を行うというゴールの上ではどのグラフが好ましいでしょうか。

f:id:doryokujin:20120629004055p:plain

図12:各ラインが年代となっているライングラフ。このグラフは 2,3 のラインでかつそれらの傾向が異なる場合はグラフはその違いをよく表現してくれますが,今回のようにラインの数が多くかつ似たような傾向を持っている場合には多くがかさなってしまい,傾向を捉えるにはそれほど向いているとは言えません。

f:id:doryokujin:20120629004114p:plain

図13:図12 の改善策の1つとして,次元を増やすという方法が考えられます。図13ではラインの数が奥行きに変換されて表現されています。3D 以上のグラフについては,図の視点および順番をすぐに変更する事のできるインタラクティブな環境を利用している場合には年代間の分布を良く眺めることができます。

f:id:doryokujin:20120629004156p:plain

図14:こちらは平面性を維持しながらも,新しい軸をバブルの色および半径によって表現しています。こちらの例はバブルの半径と色が連動していますが,独立に考えればx,y軸の他に2軸追加できることになります。また,縦と横という2つの意味の推移を同時に参照できるという意味で(グリッド上の)バブルチャートはかなり有効な可視化手段であることが伺えます。(今回の例では年代間の傾向の違いを確認しにくいですが)これより generation = 40 と generation = 50 の分布はかなり似ている様に見えます。また,generation = 20 と generation = 30 は少し傾向が違うようにも見えます。(今回はテストは行いません。)

f:id:doryokujin:20120629004225p:plain

図15:100に正規化されたスタックバーをそれぞれの評価値について並べた図。各評価値(縦軸)において,もしどの評価値においてもブロックの面積が同じような年代ペアがあればそれらは似た分布を持っていると言えそうです。この図は面白いですが,スタック表現によるブロックのずれが比較をしにくくしています。

f:id:doryokujin:20120629003932p:plain

図16:もっとシンプルに表現してみましょう。それぞれの年代においてヒストグラムを書いて並べれば良いのです。ただ,ここではバーではなくエリアとして分布を表現して年代間の比較をしやすくしています。それぞれの山の峰の数,最高点の位置などが比較しやすくなっています。

f:id:doryokujin:20120629004018p:plain

図17:図16で表現されていた山をシンメトリックに表現し,形状の違いをより鮮明に映し出すチャートを最後に紹介します。これも今回の比較というゴールのもとではその役割を十分果たしてくれています。

 

さて,本来ならばこれらの傾向の違いは今まで数回取り上げてきたテストを持って判断すべきですが,文字数が足りなくなってしまったので今回はここまでとします。

 

(ブックレビューのデータ解析はもう1回続きます。)