Treasure Data Analytics 第5回 〜ブックレビューデータセットによるデータ解析入門(実践編2)
前回の続きです。
5. 複数のノード・アクションをまたいだ分析
前回までは主に個々のノード・アクションのセグメント分析を行ってきましたが,ここからは,複数のノード・アクション(Query 的には複数のテーブルをまたがった記述に)をまたいだ解析を行っていきます。
5.1 過小/過大評価ユーザーおよび怠惰なユーザー(外れ値)の特定
ここではあるステータスから導かれる,外れ値とみなせるサンプルを特定してみましょう。
今回のようなレビューデータセットでは,例えば 10 段階評価の付け方であっても悪い評価を付けたがらないユーザーもいますし,めったに高評価を付けない辛口なユーザーもいます。もちろんこれらのユーザーは例外では無く,こういった多様性を考慮した上で解析を行っていくことは重要です。
ただ評価の付け方があまりにも偏っているユーザーに関しては外れ値として考慮した方が良いケースもあります。今回は以下の評価の付け方を持つユーザーを外れ値と見なして特定し,それを一種のセグメントと見なした上での解析を行って行くことにします。ここでは,
- そもそも偏ったユーザー(外れ値)が全体に関してどれくらいいるのか
- それらのユーザーの影響を大きく受け,過小/過大評価されていたブックの特定
を行ってみることにします。
まずは「怠惰な」ユーザーを特定するために,以下で定義を与えておきます。
- 通算 5 回以上の評価を行っているユーザーで,毎回同じ評価値しかつけないユーザーを「怠惰な」ユーザーと呼ぶ。
つまり 1〜10 までの評価レンジがあるのにも関わらずいつも 5 や 7 といった同じ評価値しか付けないユーザーは真剣に「評価」を行っていない外れ値サンプルとみなすということです。
また,常に一定の評価値以上/以下しかつけないユーザーも注目に値します。その定義として,ここでは
- 常に 9 以上の評価値しかつけないユーザーを「過大評価」ユーザー,
- 常に 5 以下の評価値しかつけないユーザーを「過小評価」ユーザー
と呼ぶことにします。
上記の定義で「9 以上」「5 以下」という閾値を決めるための手段としては 4.2 で見た「ユーザ当たりの評価平均の分布」を見るのが有効です。
図1:ユーザー当たりの評価平均値の分布。全体平均 7.6 を峰の中心とした正規分布に近い形を取ります。
この図を見ればわかるように,まずは平均的に 5 以下の評価を付けているユーザーはほとんどいないことがわかります。
ましてや「平均」ではなく,「常に」 5 以下を付けているユーザーとなればさらにマイノリティになります。平均的に 9 以上の評価値を付けているユーザーは結構いますが,さらに「常に」9 以上付けているユーザーも同様の考え方です。
それでは上記の 3 種類の偏った評価をするユーザーの人数を調べてみましょう。
Result : +-------------+-----+ | rating_type | cnt | +-------------+-----+ | ∀Const | 137 | | ∀Over 9 | 137 | | ∀Under 5 | 64 | +-------------+-----+
1 行目が常に同じ評価値をつけるユーザー,次が常に 9 以上の評価値をつけるユーザー,最後が常に 5 以下の評価値をつけるユーザーです。1.1 よりアクティブユーザーは 105,283 人でしたので,割合としては高々 0.1 % 前後です。
(a)「怠惰なユーザー」
さて,まず毎回同じ評価しかつけない「怠惰な」ユーザーはいつもどの評価値をつけているのか,またそこに傾向があるのかが気になる所です。さっそく確認してみましょう。結果を見ると面白いことに 5 と 10 の評価値に大きく偏っていることがわかります。
中間値である 5 と最高値である 10 につく傾向は,評価レンジが変わったときにもこの 2 点に偏るのかどうかは関心のあるところです。
Result : +-------------+-----+ | book_rating | cnt | +-------------+-----+ | 5.0 | 53 | | 6.0 | 1 | | 7.0 | 3 | | 8.0 | 8 | | 9.0 | 4 | | 10.0 | 68 | +-------------+-----+
図2:「怠惰な」ユーザーが付ける評価値の分布。面白い事に 5 と 10 に偏っていることがわかります。
次に「怠惰な」ユーザーの年代別の割合を見てみます。評価を面倒くさがるユーザーは特定の年代に偏っているかもしれない,という仮説は検討の余地はありそうということで。
Result : +------------+-----+-----------+------+ | generation | cnt | total_cnt | rate | +------------+-----+-----------+------+ | 15 | 2 | 5543 | 0.04 | | 20 | 12 | 17323 | 0.07 | | 25 | 11 | 25913 | 0.04 | | 30 | 12 | 26348 | 0.05 | | 35 | 12 | 22995 | 0.05 | | 40 | 11 | 17258 | 0.06 | | 45 | 9 | 13756 | 0.07 | | 50 | 4 | 12142 | 0.03 | | 55 | 3 | 10377 | 0.03 | | 60 | 3 | 7219 | 0.04 | | 65 | 3 | 3982 | 0.08 | +------------+-----+-----------+------+
結果テーブル 2 列目が年代別の人数ですが,主要な年代(20〜40)では同じくらいの人数であるように見えます。本来は,『年代別で「怠惰な」ユーザーのいる割合が異なるのか』という問題はテストを持って比較すべきですが,今回は各年代の全体数に関してサンプルが少なすぎる(多くても 0.08% しかない)という意味で妥当な比較は困難です。(テストの実践については改めて別の機会に紹介するつもりです。)
(b)「過小/過大評価ユーザー」
次の例として上述の過小/過大評価のユーザーからの評価をたくさん受けたために,その評価平均が過小/過大評価気味になっているブックを特定してみましょう。
※ なお,先ほどの評価が「常に 9 以上」「常に 5 以下」のユーザーでは少しサンプル数が少ないので「常に 8 以上」「常に 6 以下」の影響を取り除いたブックの平均評価値というのを考えることにします。
Result : +-------------+-----+ | rating_type | cnt | +-------------+-----+ | ∀Over 8 | 544 | | ∀Under 6 | 115 | +-------------+-----+
図3:上から順に過大評価ユーザーの影響を強く受けていたブックを並べています。青いバーが影響を除いた後の(低くなった)評価値,黄色が元の評価値との差分。
次に毎回 6 以下の評価しかしないユーザーの影響を強く受け,他のブックと比較して相対的に低めの値となっているブック TOP20 を算出してみましょう。
図4:上から順に過小評価ユーザーの影響を強く受けていたブックを並べています。青いバーが影響を除く前の(低かった)評価値,黄色が影響を除いた場合を加味することによる増加分。
5.2 評価数の多いブックに関する分析
評価数の多いブックは良くも悪くも話題性のあったブックで有り,かつそれなりの販売数が出ているものと推測できます。これらの本を特定し,その傾向(かっこよく言えば話題性/販売数の増加をもたらした原因)を見いだすのは自然な行為でしょう。
まずは評価数の多かったブックトップ 20 をリストアップしましょう。
Result : +------------+------------------------------------------------------------------+------+------------+------+--------+ | isbn | title | year | rating_cnt | avg | stddev | +------------+------------------------------------------------------------------+------+------------+------+--------+ | 0316666343 | The Lovely Bones: A Novel | 2002 | 707 | 8.19 | 1.53 | | 0971880107 | Wild Animus | 2004 | 581 | 4.39 | 2.38 | | 0385504209 | The Da Vinci Code | 2003 | 487 | 8.44 | 1.67 | | 0312195516 | The Red Tent (Bestselling Backlist) | 1998 | 383 | 8.18 | 1.69 | | 0060928336 | Divine Secrets of the Ya-Ya Sisterhood: A Novel | 1997 | 320 | 7.89 | 1.63 | | 059035342X | Harry Potter and the Sorcerer's Stone (Harry Potter (Paperback)) | 1999 | 313 | 8.94 | 1.43 | | 0142001740 | The Secret Life of Bees | 2003 | 307 | 8.45 | 1.49 | | 0446672211 | Where the Heart Is (Oprah's Book Club (Paperback)) | 1998 | 295 | 8.14 | 1.45 | | 044023722X | A Painted House | 2001 | 281 | 7.34 | 1.79 | | 0452282152 | Girl with a Pearl Earring | 2001 | 278 | 7.98 | 1.44 | | 0316601950 | The Pilot's Wife : A Novel | 1999 | 272 | 7.5 | 1.74 | | 0671027360 | Angels & Demons | 2001 | 269 | 8.1 | 1.6 | | 067976402X | Snow Falling on Cedars | 1995 | 256 | 7.81 | 1.87 | | 0316769487 | The Catcher in the Rye | 1991 | 243 | 7.69 | 2.22 | | 0786868716 | The Five People You Meet in Heaven | 2003 | 242 | 8.02 | 1.79 | | 0743418174 | Good in Bed | 2002 | 236 | 8.05 | 1.33 | | 0345337662 | Interview with the Vampire | 1993 | 230 | 7.78 | 1.73 | | 0375727345 | House of Sand and Fog | 2000 | 229 | 7.33 | 1.63 | | 0312278586 | The Nanny Diaries: A Novel | 2002 | 226 | 7.54 | 1.74 | | 0156027321 | Life of Pi | 2003 | 226 | 8.03 | 1.79 | +------------+------------------------------------------------------------------+------+------------+------+--------+
上記の結果で面白いのは,評価数 TOP20 の多くが全体平均と同じかやや高い平均値を持っている中で,2 位の「Wild Animus」だけが 4.39 という低評価を持っていることです。今度は平均値では無く分布を見てみることにしましょう。ここでは 2 位を含む TOP5 に限定します。
図5:評価数の多いブック TOP5 の評価分布をシンメトリックなエリアチャートにて表現しています。それぞれ 評価値の最頻値は異なりますが TOP2 だけは明らかに分布の形が異なることがわかります。
この TOP2 の「Wild Animus」,Amazon のレビューを見てもひどい評価をたくさんもらっていることがわかります。今回のデータセットにはコメントなどの評価の内容を知るデータは含まれておりませんので,このデータ単体ではネガティブとなった原因までは追及できませんが,Amazon などのレビューコメントデータとは isbn で join できますので,それと併せてテキスト解析にまで持ち込むのも面白いかもしれません。
5.3 評価平均値の高いブックに関する分析
さて,5.2 と同じ枠組みで今度は評価平均値が高いブックを特定することも容易です。50 以上の評価数を持つブックを条件に,最も平均評価値の高い TOP20 を紹介しましょう。
Result : +------------+----------------------------------------------------------------------------------+------+------+-----+--------+ | isbn | title | year | avg | cnt | stddev | +------------+----------------------------------------------------------------------------------+------+------+-----+--------+ | 0345339738 | The Return of the King (The Lord of the Rings, Part 3) | 1986 | 9.4 | 77 | 1.09 | | 0439139597 | Harry Potter and the Goblet of Fire (Book 4) | 2000 | 9.26 | 137 | 1.23 | | 043936213X | Harry Potter and the Sorcerer's Stone (Book 1) | 2001 | 9.21 | 53 | 1.15 | | 0345339711 | The Two Towers (The Lord of the Rings, Part 2) | 1986 | 9.12 | 83 | 1.21 | | 0439136369 | Harry Potter and the Prisoner of Azkaban (Book 3) | 2001 | 9.08 | 133 | 1.25 | | 0064400557 | Charlotte's Web (Trophy Newbery) | 1974 | 9.07 | 68 | 1.18 | | 0439136350 | Harry Potter and the Prisoner of Azkaban (Book 3) | 1999 | 9.04 | 141 | 1.43 | | 043935806X | Harry Potter and the Order of the Phoenix (Book 5) | 2003 | 9.03 | 206 | 1.33 | | 0156528207 | The Little Prince | 1968 | 8.98 | 51 | 1.32 | | 0590353403 | Harry Potter and the Sorcerer's Stone (Book 1) | 1998 | 8.98 | 119 | 1.46 | | 0441172717 | Dune (Remembering Tomorrow) | 1996 | 8.97 | 75 | 1.41 | | 0439139600 | Harry Potter and the Goblet of Fire (Book 4) | 2002 | 8.95 | 110 | 1.3 | | 0446310786 | To Kill a Mockingbird | 1988 | 8.94 | 214 | 1.37 | | 059035342X | Harry Potter and the Sorcerer's Stone (Harry Potter (Paperback)) | 1999 | 8.94 | 313 | 1.43 | | 0439064864 | Harry Potter and the Chamber of Secrets (Book 2) | 1999 | 8.92 | 126 | 1.38 | | 055321313X | Anne of Green Gables (Anne of Green Gables Novels (Paperback)) | 1982 | 8.91 | 53 | 1.51 | | 0440498058 | A Wrinkle In Time | 1998 | 8.88 | 81 | 1.16 | | 0345348036 | The Princess Bride: S Morgenstern's Classic Tale of True Love and High Adventure | 1987 | 8.84 | 74 | 1.54 | | 0345339703 | The Fellowship of the Ring (The Lord of the Rings, Part 1) | 1986 | 8.84 | 131 | 1.65 | | 0812550706 | Ender's Game (Ender Wiggins Saga (Paperback)) | 1994 | 8.84 | 117 | 1.33 | +------------+----------------------------------------------------------------------------------+------+------+-----+--------+
ハリーポッター,ロードオブザリングシリーズがこぞってランクインしているのが面白いところです。今回も TOP5 の評価値の分布を見てみることにしましょう。
図6:評価平均が最も高かったブック TOP5 の分布。
5.4 評価平均値の高いブックに関する分析(出版年別)
Result : +------+----------------------------------------------------------------------------+------+-----+--------+ | year | title | avg | cnt | stddev | +------+----------------------------------------------------------------------------+------+-----+--------+ | 2004 | The Curious Incident of the Dog in the Night-Time (Vintage Contemporaries) | 8.59 | 51 | 1.24 | | 2003 | Harry Potter and the Order of the Phoenix (Book 5) | 9.03 | 206 | 1.33 | | 2002 | Harry Potter and the Goblet of Fire (Book 4) | 8.95 | 110 | 1.3 | | 2001 | Harry Potter and the Sorcerer's Stone (Book 1) | 9.21 | 53 | 1.15 | | 2000 | Harry Potter and the Goblet of Fire (Book 4) | 9.26 | 137 | 1.23 | | 1999 | Harry Potter and the Prisoner of Azkaban (Book 3) | 9.04 | 141 | 1.43 | | 1998 | Harry Potter and the Sorcerer's Stone (Book 1) | 8.98 | 119 | 1.46 | | 1997 | Tuesdays with Morrie: An Old Man, a Young Man, and Life's Greatest Lesson | 8.62 | 200 | 1.55 | | 1996 | Dune (Remembering Tomorrow) | 8.97 | 75 | 1.41 | | 1995 | Ishmael: An Adventure of the Mind and Spirit | 8.46 | 94 | 1.58 | | 1994 | Ender's Game (Ender Wiggins Saga (Paperback)) | 8.84 | 117 | 1.33 | +------+----------------------------------------------------------------------------+------+-----+--------+
図7:評価平均が最も高かったブックTOP1の出版年別分布。年別に見るとTOP1のブックの評価分布が各々特徴を持っているのがおもしろい。
- (ブック1,ブック2)
- (ブック1,ブック3)
- (ブック2,ブック3)
Result : +----------------------------------------------------+-------+------+----------------------------------------------------+-------+------+--------------+---------------------+ | title1 | year1 | cnt1 | title2 | year2 | cnt2 | intersection | simpson | +----------------------------------------------------+-------+------+----------------------------------------------------+-------+------+--------------+---------------------+ | The Firm | 1992 | 529 | The Pelican Brief | 1993 | 523 | 200 | 0.3824091778202677 | | The Pelican Brief | 1993 | 523 | A Time to Kill | 1992 | 517 | 184 | 0.35589941972920697 | | A Time to Kill | 1992 | 517 | The Firm | 1992 | 529 | 160 | 0.30947775628626695 | | The Da Vinci Code | 2003 | 883 | Angels & Demons | 2001 | 586 | 181 | 0.30887372013651876 | | Wild Animus | 2004 | 2502 | The Firm | 1992 | 529 | 130 | 0.24574669187145556 | | Angels & Demons | 2001 | 586 | Wild Animus | 2004 | 2502 | 137 | 0.23378839590443687 | | The Lovely Bones: A Novel | 2002 | 1295 | The Secret Life of Bees | 2003 | 615 | 143 | 0.23252032520325203 | | The Pelican Brief | 1993 | 523 | Wild Animus | 2004 | 2502 | 120 | 0.2294455066921606 | | Interview with the Vampire | 1993 | 506 | Wild Animus | 2004 | 2502 | 116 | 0.22924901185770752 | | Where the Heart Is (Oprah's Book Club (Paperback)) | 1998 | 585 | Divine Secrets of the Ya-Ya Sisterhood: A Novel | 1997 | 732 | 134 | 0.22905982905982905 | | The Lovely Bones: A Novel | 2002 | 1295 | The Pilot's Wife : A Novel | 1999 | 568 | 129 | 0.22711267605633803 | | Wild Animus | 2004 | 2502 | House of Sand and Fog | 2000 | 552 | 124 | 0.2246376811594203 | | A Time to Kill | 1992 | 517 | Wild Animus | 2004 | 2502 | 116 | 0.22437137330754353 | | The Joy Luck Club | 1994 | 519 | The Lovely Bones: A Novel | 2002 | 1295 | 115 | 0.22157996146435452 | | House of Sand and Fog | 2000 | 552 | The Lovely Bones: A Novel | 2002 | 1295 | 122 | 0.2210144927536232 | | Wild Animus | 2004 | 2502 | The Da Vinci Code | 2003 | 883 | 195 | 0.22083805209513024 | | Girl with a Pearl Earring | 2001 | 526 | The Lovely Bones: A Novel | 2002 | 1295 | 116 | 0.22053231939163498 | | Where the Heart Is (Oprah's Book Club (Paperback)) | 1998 | 585 | The Lovely Bones: A Novel | 2002 | 1295 | 129 | 0.2205128205128205 | | The Lovely Bones: A Novel | 2002 | 1295 | Divine Secrets of the Ya-Ya Sisterhood: A Novel | 1997 | 732 | 161 | 0.21994535519125682 | | The Lovely Bones: A Novel | 2002 | 1295 | The Red Tent (Bestselling Backlist) | 1998 | 723 | 159 | 0.21991701244813278 | +----------------------------------------------------+-------+------+----------------------------------------------------+-------+------+--------------+---------------------+
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 冊以上のブックに対して評価を行っているユーザー(アクティブユーザー)がどれだけいるのかを見ていきましょう。
Result : +-----------+--------------+-------------+ | all_users | active_users | active_rate | +-----------+--------------+-------------+ | 278858 | 105283 | 38 | +-----------+--------------+-------------+
28 万登録ユーザーに対し,10 万人のアクティブユーザーでアクティブ率は 38% であることがわかります。
ただし後の登録ブック数の方を見てもらえばわかりますが,必ずしも登録ユーザー (users テーブルに存在するユーザー)がアクティブユーザー(rating テーブルに存在するユーザー)を包含するとは限りません。そこで次に,users テーブルのみに含まれるユーザー,rating ユーザーのみに含まれるユーザー,両方のテーブルに含まれるユーザーを計算してみましょう。
Result : +-----------------+--------+ | type | cnt | +-----------------+--------+ | both | 105283 | | only in ratings | 0 | | only in users | 173575 | +-----------------+--------+
この結果を持って初めて ratings テーブルに存在する全ユーザーが,users 登録ユーザーに含まれている(i.e. アクティブユーザーのステータスが取得できる)事が言えます。
図1:ユーザー集合に関するベン図。rating テーブルに含まれるユーザーは全て users テーブルに含まれています。
1.2 登録ブック数,アクティブブック数
同じく登録されているブック数とその中で 1 回でも評価を受けたことのあるブック(アクティブブック)数を確認します。
Result : +-----------+--------------+-------------+ | all_books | active_books | active_rate | +-----------+--------------+-------------+ | 271376 | 340556 | 125 | +-----------+--------------+-------------+
ratings テーブルに現れるユニークなブックの方が book テーブルの登録ブックより多いようです。
(この原因としてはデータセットの取得された背景が考えられます。このデータセットは 2004 年 8, 9 月 にクローリングによって取得された局所的なデータであることが記されています。今回は具体的な取得方法およびプログラムなどは知ることができませんので,これ以上深掘りできません。)
先ほどと同じように,books テーブルのみ,rating テーブルのみ,両方に存在するブック数を求め,ベン図にしてみます。片方のテーブルのみにしか含まれないブックがいくらか存在するようです。今回の主なデータ解析の目的では,主に双方に含まれるブック(ステータスを取得できるブック)集合が解析の対象になります。
Result : +-----------------+--------+ | type | cnt | +-----------------+--------+ | only in books | 1209 | | both | 270167 | | only in ratings | 70389 | +-----------------+--------+
図2:ブック集合に関するベン図。rating テーブルに含まれるブックの方が多く,books テーブルをほぼ包含しています。
1.3 総評価数,有効評価数,平均評価値
データセットが取得された期間内に全部で何回の評価が行われたのかを確認してみます。この項目:評価の値に関しては 0 〜 10 の値をとるのですが,値 0 は有効な評価が得られなかったという意味で他の値 [1,10] とは扱いが異なることには以後注意する必要があります。
評価平均を計算する場合などは有効な値として評価値を [1,10] に絞って考える方が良さそうです。ここでも有効評価数および平均評価値は [1,10] の値を持つレコードに絞って集計しています。
Result :
+-------------+-------------------+----------------+ | all_reviews | valid_reviews | avg_of_reviews | +-------------+-------------------+----------------+ | 1149780 | 433671 | 7.6 | +-------------+-------------------+----------------+
全評価数は115 万件にも及びます。ただし,その中で評価値 [1, 10] の値を得られている有効なレコードは 43 万件に過ぎません。有効なレコード全体での評価平均は 7.6 となっています。後ほど評価平均については様々なセグメントから掘り下げられることになります。
2. ユーザーステータスに基づくセグメント分布
2.1 ユーザーの居住国分布
ユーザーの居住国による分布を数の多い国TOP20に絞って見てみます。さらに全体の 50% 以上のシェアを持つ居住国:usa ユーザーについて,さらに居住地域の分布を見てみます。
図3:ユーザーの居住国の分布。usa に住むユーザーが全体の半分以上を占めています。
図4:usa に住むユーザーの,地域ごとの分布を表しています。カリフォルニア州に住むユーザーが多いですが,それを除いて各地域の全体に占める割合は 10% 以下と小さくなっています。なお,ユーザーステータスにはさらにもう一段階詳細な地域 ("location2") の情報を持っています。
2.2 ユーザーの年代分布
次にユーザーの年齢に基づいた 5 歳区切りの年代分布を見てみます。 11歳〜15歳に属するユーザーは generation=15,16歳〜20歳に属するユーザーは generation=20という切り上げベースのセグメントにしていることに注意して下さい。
また,age カラムは必ずしも数値が入っているわけでは無く(不明のものは "NULL" ),かつ正確な値が記入されていない事がわかります。 generation=0 の数は年齢不詳の人数,generation=65* は65歳以上の人数とし,このどちらも有効で無い値として扱うことにします。
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歳までのユーザーで全体の半分のシェアを持っていることがわかります。
図5:ユーザーの年代分布(ヒストグラム)。赤線は10歳からの累積割合を表しており,generation=30 でほぼ 50%,つまり 10 - 30 歳のユーザーが全体の半数を占めていることがわかります。
3. ブックステータスに基づくセグメントの分布
3.1 出版年別の分布
続いて同様にブックステータスに基づくセグメントの分布を見ていきましょう。このデータセットは 2004年の8, 9 月に取得されたものなのでそれ以降の出版年があればそれは正しい値では無いと考えられます。また1970年以前の出版年のブックもここでは有効でないと考えることにします。
Result : +-------+-------+ | year | cnt | +------ +-------+ | 1970* | 459 | | 1971 | 540 | | 1972 | 772 | ... | 2003 | 14358 | | 2004 | 5839 | | 2005* | 72 | +-------+-------+
1970* は1970年以前のブック,2005* は2005年以降のブックで少ないですが存在していることがわかります。有効な出版年を [1970, 2004] として,これらのブックを除外した分布を改めてヒストグラムと共に見てみましょう。
図6:出版年をセグメントにした分布。2000年に至るまではほぼ単調増加となっています(ここではそれほど意味を持たないかも)。2004年はデータセットがこの年の9月までなので数は少なくなっています。
図7:出版年を上三桁(1970,1980,...,2000)と下一桁(0,...,9)に分けた 2 つのセグメントでの分布を改めて見ています。図はグリッド上に配置したバブルチャートであり,横に見る事で10年毎のデータ推移,縦に見る事で1年毎の推移が確認できます。このような年(時間軸)を分解したクロスセグメントは他にも(年,季節)の組での周期性を確認したい場合などにも有効です。
3.2 出版社別の分布
出版年の次は出版社の分布です。数の多い上位 10 数件の分布を表示しています。
図8:出版社ごとに見るブック数の分布。特定の出版社に過度に偏っていないことがわかります。
4. 評価ステータスに基づくセグメントの分布
評価(review)というアクションの持つステータス(今回は評価値)もまた,セグメント分布をみるための有効な材料となります。
4.1 評価数の分布
まずは,ユーザ当たりの評価数の平均を確認します。
Result : +-----+ | avg | +-----+ | 11 | +-----+
もちろんこの 11 という平均評価回数はあくまで全体をおしなべた値であり,実際分布デ見てみるとさらに多くの情報を得られることができます。あらゆる値は平均だけでなく分布としてその姿を確認することは常に大切です。次にユーザー当たりの評価回数についての分布を確認してみます。この分布は評価回数が 0 のユーザーは含んでいないことに注意してください。
図9:ほとんど(50%以上)の評価経験のあるユーザーは 1 回しか評価をしていないことがわかります。さらに 90% のユーザーは平均値である 11 以下にとどまっていることもわかります。しかしながら,それ以降もヒストグラムが長い尾を持っていることからわかりますように,数少ないながらたくさんの評価を行っているユーザーに引っ張られる形で平均が 11 となっているのです。
4.2 評価平均の分布
ユーザー当たり評価平均についても同じように分布を見る事にします。ちなみに(ユーザを区別しない)全体の評価平均は 1.3 で書いたように 7.6 となっています。
以下の結果が示すように,ユーザー当たりの評価平均は 7.6 を中心に単峰の山を持っています。評価という行動においては,評価値範囲の中心値(=5)のまわりにばらつくのではなく,それよりもずっと大きな値の周りでばらついていることがわかります。
逆に言えば平均的に 5 以下の評価を付けるユーザーはかなりのマイノリティであると言えます。彼らはいわゆる「辛口レビュアー」というクラスタに分類することができそうです。これに関しては次回でもう少しだけ深掘りしていくことにしましょう。
図10:元がどのような分布であってもその平均の値の分布はサンプル数が十分に大きいところでは漸近的に正規分布に従います(中心極限定理)。評価平均の分布もまた平均値 7.6 を中心にした正規分布の姿を持っていますが,評価値が [1, 10] の範囲に限定されているため右側は 10 で打ち切られた分布となっています。
4.3 評価平均×年代による分布
最後に先ほどの評価平均という分布を,ユーザーの年代ごとに確認してみましょう。図10 のヒストグラムが年代ごとに作られるイメージです。これによって年代間で評価の付け方に傾向があるのかがわかるかもしれません。傾向とは,例えば「20台は比較的高評価をつけがちだが,40台は辛口評価である」といったものです。
結果を評価値を行,年代を列としたピボットテーブルとして表したものが下になります。各セルにはユーザー数が入っています。表だけではわかりにくいのですね。
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)。
図12:各ラインが年代となっているライングラフ。このグラフは 2,3 のラインでかつそれらの傾向が異なる場合はグラフはその違いをよく表現してくれますが,今回のようにラインの数が多くかつ似たような傾向を持っている場合には多くがかさなってしまい,傾向を捉えるにはそれほど向いているとは言えません。
図13:図12 の改善策の1つとして,次元を増やすという方法が考えられます。図13ではラインの数が奥行きに変換されて表現されています。3D 以上のグラフについては,図の視点および順番をすぐに変更する事のできるインタラクティブな環境を利用している場合には年代間の分布を良く眺めることができます。
図14:こちらは平面性を維持しながらも,新しい軸をバブルの色および半径によって表現しています。こちらの例はバブルの半径と色が連動していますが,独立に考えればx,y軸の他に2軸追加できることになります。また,縦と横という2つの意味の推移を同時に参照できるという意味で(グリッド上の)バブルチャートはかなり有効な可視化手段であることが伺えます。(今回の例では年代間の傾向の違いを確認しにくいですが)これより generation = 40 と generation = 50 の分布はかなり似ている様に見えます。また,generation = 20 と generation = 30 は少し傾向が違うようにも見えます。(今回はテストは行いません。)
図15:100に正規化されたスタックバーをそれぞれの評価値について並べた図。各評価値(縦軸)において,もしどの評価値においてもブロックの面積が同じような年代ペアがあればそれらは似た分布を持っていると言えそうです。この図は面白いですが,スタック表現によるブロックのずれが比較をしにくくしています。
図16:もっとシンプルに表現してみましょう。それぞれの年代においてヒストグラムを書いて並べれば良いのです。ただ,ここではバーではなくエリアとして分布を表現して年代間の比較をしやすくしています。それぞれの山の峰の数,最高点の位置などが比較しやすくなっています。
図17:図16で表現されていた山をシンメトリックに表現し,形状の違いをより鮮明に映し出すチャートを最後に紹介します。これも今回の比較というゴールのもとではその役割を十分果たしてくれています。
さて,本来ならばこれらの傾向の違いは今まで数回取り上げてきたテストを持って判断すべきですが,文字数が足りなくなってしまったので今回はここまでとします。
(ブックレビューのデータ解析はもう1回続きます。)
Treasure Data Analytics 第3回 〜ブックレビューデータセットによるデータ解析入門(準備編)〜
はじめに
前回まで Treasure Data Cloud Warehouse の紹介をしていましたが,今回からはパブリックデータを利用したデータ解析のユースケースを紹介して行きます。またこの紹介を持って td コマンドの使い方にも慣れてもらえればと思っています。
Book-Crossing Dataset
今回は Web 上に公開されているパブリックデータセット:Book-Crossing Dataset を扱います。Book-Crossing Dataset には以下の 3 テーブルからなるブックレビューデータです:
- (S-1) "users": ユーザーデータ(user_id, age, country,...)
- (S-2) "books": ブックデータ(isbn, book_title, authour, year_of_publication,...)
- (A-1) "ratings": レビューデータ(user_id, isbn, book_rating)
※ (S-1) や (S-2) の S は"Status",(A-1) の A は"Action" を意味しています。
これらの生データは以下の様になっています(実際にインポートするデータはカラム名および項目数を変更してあります):
# users "UserID";"Location";"Age" "1";"nyc, new york, usa";NULL "2";"stockton, california, usa";"18" # books "ISBN";"BookTitle";"BookAuthor";"YearOfPublication";"Publisher";"ImageURLSizeS";"ImageURLSizeM";"ImageURLSizeL" "0195153448";"Classical Mythology";"Mark P. O. Morford";"2002";"Oxford University Press";"http://images.amazon.com/images/P/0195153448.01.THUMBZZZ.jpg";"http://images.amazon.com/images/P/0195153448.01.MZZZZZZZ.jpg";"http://images.amazon.com/images/P/0195153448.01.LZZZZZZZ.jpg" "0002005018";"Clara Callan";"Richard Bruce Wright";"2001";"HarperFlamingo Canada";"http://images.amazon.com/images/P/0002005018.01.THUMBZZZ.jpg";"http://images.amazon.com/images/P/0002005018.01.MZZZZZZZ.jpg";"http://images.amazon.com/images/P/0002005018.01.LZZZZZZZ.jpg" # ratings "UserID";"ISBN";"BookRating" "276725";"034545104X";"0" "276726";"0155061224";"5"
これらのデータセットに対してより明白な見通しを事前に立てておくために,「ステータス」と「アクション」という分類を考えてみることにします。
- ステータスログ:ユーザーやモノの「状態」を表すログ
- アクションログ:ユーザーやモノの「行動」を表すログ
ステータスログとは,ユーザーやモノの現在の状態を表す情報を持ったテーブルを指します。今回の Book-Crossing Dataset におけるステータスログは "users" と "books" テーブルとなります。前者はユニークID: "user_id" 持つユーザーの情報を含むテーブルで,「年齢 ("age")」「居住国 ("country")・地域 ("location1","location2")」というステータスを持っています。後者はユニークID: "isbn" を持つブックの情報を持つテーブルで「タイトル("book_title")」「出版年 ("year_of_publication")」「著者 ("book_author")」「出版社 ("publisher")」などといったステータスを持っています。
一方アクションログとは「登録」や「購入」「評価する」「メッセージを送る」といった行動に関するテーブルです。また,アクションもステータスを持っている場合があります。今回は "rating" テーブルがそれに該当し,(カラムに明示してないですが)「評価する」という1種類のアクションが内在しています。このアクションには行動主体となるユーザーの "user_id" と対象となるブックの "isbn" の他に「評価ポイント ("book_rating")」というステータスを持っています。
一般にアクションログには 行動主体(ユーザー)と対象(モノ・ユーザー,行動主体と同じ場合もある)が存在し,オプションとしてステータスが付与されています。
Data Set と Property Graph
(※ 余談なので読み飛ばして問題ありません)
解析対象となる一連のデータセットの多くは,上記の「アクション」「ステータス」「行動主体」「対象」という概念を利用して "Property Graph" によるグラフ表現が可能です。「行動主体」と「対象」になり得るユーザーやモノはノード,各アクションはエッジで表現します。ノードの持つ属性情報がステータスに当たります。また前述の通りエッジにも属性を持たせることができ,これもステータスと呼ぶことができます。
図1:Book-Crossing Dataset の Property Graph による表現。ノードとエッジおよびそれらの属性を表す key-value 集合から構成されます。図1では "user" と "book" という2種類のノードがあり, "user" (行動主体)からの "review" というアクションを介して "book" (対象)とつながっています。また "user", "book" はそれぞれステータスを持っており,"review" というエッジにも "book_rating" ( = 評価ポイント∈ [0,10])と呼ばれるステータスを持っています。
図2:複数のアクションを持つ Property Graph の例。この場合は "user" と "book" のステータスを表すテーブルに加え,"add_to_list", "review", "buy", "comment" というアクションを表すテーブルが解析対象となるデータセットとなります。
Property Graph はデータセットの構造をわかりやすく表現する事に加えて,一連のデータ操作:「検索」「判別・分類」「推薦」といったものをグラフ上の操作にマッピングして扱うことができます。この特徴に関しては他の機会で紹介します。
準備
Treasure Data Storage に Book-Crossing Dataset をインポートし,データ解析を行うための準備を行いましょう。
1.サインアップ
何よりもまず Tresure Data のデモアカウントが必要です。まだ持っていない方は以下より登録してアカウントを取得してください。
signup および上の画像をクリックすると登録ページに移ります。
2. Treasure Data Toolbelt のインストール
新しく登録された方は Quickstart Guide に進んで下さい。最低でも Treasure Data Toolbelt のインストールを完了する Step3 まで進んでおいて下さい。もし「Step 2: Install Treasure Data Toolbelt」で OS や Ruby のバージョンなどの問題が起こる場合は 状況を報告頂けますと助かります。
Treasure Data Toolbelt および上の画像をクリックすると登録ページに移ります。
3. データセットのダウンロード
Treasure Data Storage へアップロードするために加工したデータを Google Drive に置いておりますので,以下の各リンクよりダウンロードして下さい。
4. データインポート
ここまで,あなたのコマンドラインから "td" とコマンドを打つと以下の様なヘルプが表示されていることを前提とします。
$ td usage: td [options] COMMAND [args] ...
データをインポートしていきましょう。今回は table:import コマンドを利用してあなたの Treasure Data Storage 上に Book-Crossing Dataset をアップロードします。ダウンロードディレクトリに移動して以下のコマンドを実行してください。
# db の作成 $ td db:create book_crossing_dataset # table の作成 $ td table:create book_crossing_dataset users $ td table:create book_crossing_dataset books $ td table:create book_crossing_dataset ratings # table:import $ td table:import book_crossing_dataset users --format msgpack -t time BX-Users.msgpack.gz $ td table:import book_crossing_dataset books --format msgpack -t time BX-Books.msgpack.gz $ td table:import book_crossing_dataset ratings --format msgpack -t time BX-Ratings.msgpack.gz # 確認 $ td tables +------------------------------+---------------------------------+------+-----------+ | Database | Table | Type | Count | +------------------------------+---------------------------------+------+-----------+ | book_crossing_dataset | books | log | 271376 | | book_crossing_dataset | ratings | log | 1149780 | | book_crossing_dataset | users | log | 278858 | +------------------------------+---------------------------------+------+-----------+
いくつかの注意点として,import 対象となるファイルの各レコードには必ず timestamp が含まれている必要があり,table:import 時には -t オプションで timestamp となるキーを指定する必要があります。
また,--format オプションも必須で,ここは msgpack または json の指定が可能です。どちらも(全体では無く)1行1行が msgpack または JSON 形式に変換され保存されているファイルとなります。また,msgpack 形式ではその gz 圧縮ファイルも扱うことができ,この圧縮ファイルが最もファイルサイズが小さく効率的に import できますのでこちらの利用をお勧めします。
※ user テーブルに入るデータの JSON ver. は以下の様になっています。
{"user_id": "1", "country": "usa", "age": "NULL", "location2": "nyc", "location1": "new york", "time": 1340292218} {"user_id": "2", "country": "usa", "age": "18", "location2": "stockton", "location1": "california", "time": 1340292218} {"user_id": "3", "country": "russia", "age": "NULL", "location2": "moscow", "location1": "yukon territory", "time": 1340292218}
5. データアクセス
さて,インポートが完了しましたらデータの方にアクセスしてみましょう。最新のレコードの確認には, Hive で Select クエリを発行する他に table:tail コマンドが使えます。
$ td table:tail book_crossing_dataset users -n 1 -P { "user_id":"44642", "age":"23", "country":"usa", "location1":"alaska", "location2":"palmer", "time":1340292244, } $ td table:tail book_crossing_dataset books -n 1 -P { "isbn":"1877988219", "book_title":"The Best Places to Kiss in the Northwest: (And the Canadian Southwest)", "book_author":"Stephanie Bell", "publisher":"Pub Group West", "year_of_publication":"1997", "image_url_size_l":"http://images.amazon.com/images/P/1877988219.01.LZZZZZZZ.jpg", "image_url_size_m":"http://images.amazon.com/images/P/1877988219.01.MZZZZZZZ.jpg", "image_url_size_s":"http://images.amazon.com/images/P/1877988219.01.THUMBZZZ.jpg", "time":1340289965 } $ td table:tail book_crossing_dataset ratings -n 1 -P { "time":1340290583, "user_id":"263418", "book_rating":"0", "isbn":"0446527750" }
それでは簡単な Hive クエリを実行してみましょう。クエリの実行は "td query" コマンドを利用します。ヘルプを見るには以下のコマンドを実行します。以下では必要な項目だけ抽出しています。
$ td query usage: $ td query options: -d, --database DB_NAME use the database (required) -w, --wait wait for finishing the job -o, --output PATH write result to the file -f, --format FORMAT format of the result to write to the file (tsv, csv, json or msgpack)
コマンドライン上に結果を出力する場合は "-w -d dbname" のみを使います。csvファイルに書き出したい場合は "-w -d dbname -o output_filename -f csv " のオプションを使用します。
# users テーブルよりデータを 5 件取得
td query -w -d book_crossing_dataset " SELECT * FROM users LIMIT 5 " ... Result : +---------+------+----------------+----------------+---------------+------------+ | user_id | age | country | location1 | location2 | time | +---------+------+----------------+----------------+---------------+------------+ | 44632 | NULL | spain | n/a | arrecife | 1340292244 | | 44633 | NULL | usa | north carolina | durham | 1340292244 | | 44634 | 37 | united kingdom | england | ryde | 1340292244 | | 44635 | 36 | usa | new york | mount vernon | 1340292244 | | 44636 | 24 | japan | n/a | tokyo | 1340292244 | +---------+------+----------------+----------------+---------------+------------+
# データ件数の確認
td query -w -d book_crossing_dataset " SELECT COUNT(*) AS cnt FROM users " ... Result : +--------+ | cnt | +--------+ | 278858 | +--------+
さて,準備は整いましたので次回の実践編では簡単なデータ解析を行っていきましょう。今回はここまでとします。
※ msgpack 形式のログのインポート時に警告が出る方へ
1行1行をmsgpack形式とする場合はJSON形式と違って行毎に改行する必要はありません。逆に改行していると,行間に余計な行が挟まり
skipped: record must be a Hash: 10
のような警告が発せられます。msgpack形式のファイルがtd:importで問題が無いかを確認するには,ファイル名を f として,
$ ruby -rmsgpack -e "File.open('f') {|f| MessagePack::Unpacker.new(f).each {|r| p r } }"
と打ってみてください。問題のある場合はレコード間に'10'が挟まっており,
{'time'=>12345678, …} 10 {'time'=>12345678, …} 10 ...
この行をインポートしようとして失敗・スキップされ,上記の警告が出ることになります。
Treasure Data Analytics 第2回 〜Treasure Data Cloud Warehouse について(後編)〜
はじめに
Treasure Data Cloud Warehouse(前編)では,サービスの概観を紹介しました。第2回では,実践的なデータ・アナリティクスを行う上で解決しなければならない問題をTreasure Dataではどのように解決しているのか,具体的に述べていきたいと思います:
- データ収集の問題:様々な種類のログをどのようにデータを集約・収集して,横断的な解析を可能にするか?
- ストレージの問題:増え続けていく大量のログを,どこに,どのようなフォーマットで,解析可能な状態のまま保管していくか?
- 解析結果の活用に関する問題:ログを解析した結果を,どのように可視化するか。あるいはどのように既存のシステムに統合・フィードバックしていくのか?
1. データ収集の問題
図1: fluentd はログ解析の前段,ログ収集における問題を解決してくれる
「解析対象のログを収集してくる」という作業は本質的では無いと思われるかもしれませんが,実践的なデータ・アナリティクスを始めるためには極めて重要なフェーズです。そのためにはアクセスログをはじめ,データベースに書き込まれるユーザーの行動ログ,プログラムから書き出されるカスタムログ(アプリケーションログ),CPU使用率などのシステムメトリクスなど,様々なデータソースから統一的にログを収集してくる必要があります。実際の解析フェーズにおいては,これらの複数のデータソースを同時に参照・結合することによって有用な結果を得られるケースも多々あります。
1-1. アクセスログの収集
多くのWebサービスではサーバの負荷分散を行っているため,アクセスログの収集もまた複数のサーバにまたがって行わなければなりません。場合によっては数十台〜数百台のサーバからログを収集する必要があります。旧来の方法では,1日に1回ログが特定のディレクトリにローテートされるのを待って,そのテキストログを転送するという方法が一般的に行われていましたが,この方法には次に挙げるように多くの問題があります:
- 多数のサーバからログを転送する特定の時間に,ネットワーク負荷が集中して発生する
- 最短でも1日ごとにしか集計を行えないため,解析結果の鮮度が落ちる
- 複数のサーバーから収集するためのスクリプトの開発・管理が必要
- 集計を行う際にテキストログのパースが必要になる
上記の問題に対して Treasure Data では,ログ収集ツールである「fluentd」(インストールパッケージ名:td-agent)を利用します:
- アクセスログがファイルに書かれるたびに追従してストリーミング転送を行うことで,ネットワーク負荷のピーク値を軽減する
- ログを書き出してから数分後には集計が可能になる
- あらかじめ用意されたスクリプトを使うだけでアクセスログを収集可能
- アクセスログを読み取った際にログの構造化処理を行う
fluentd には Tail Plugin というプラグインが用意されています。これを利用することで所定のログファイルを継続的に読み出し,構造化したログをストリーミング転送することが可能になります。
これらの詳細に関してはドキュメントおよび有志の皆様のブログを参考にしていただければと思います:
- fluentd の公式ページ
- 作者古橋のスライド,ブログ
- Subsonic+Nginxのアクセスログをfluentdを利用してMongoDBに入れてみた
- EC2インスタンス上でnginxのログをfluentd経由でS3へ飛ばしてみる
Apache のアクセスログを収集するのであれば,各Webサーバーに以下の様な fluentd の設定ファイルをインストールしておけば,ログの集約が可能になります。
type tail path /var/log/httpd-access.log tag apache.access format apache
1-2. 多種多様のデータソースからの収集
fluentd では,アクセスログに限らず,プラグイン機能によって様々なデータソースからログを収集できます。プラグインの導入および使用は非常に簡単で,かつプログラムを書く必要も無く設定ファイルの簡単な記述だけで済みます。
公式サイトのプラグインリストには,ダウンロード回数順に非常に多くのプラグインがリストアップされています。特にダウンロード回数上位である MongoDB と fluentd はフロント側では共に同じ JSON での受け渡しが可能であるという事から fluentd のインプット/アウトプットとして,シームレスな連携が可能です。
他にも fluentd でログを転送しながら中継点で集計を行っていくようなストリーミング処理もプラグインによって実現することができます。これと node.js などとの連携によってほぼリアルタイムなカウンターをWeb上に実装することも可能です。
また,fluentd は各言語向けに用意された fluentd-logger ライブラリ(例: fluent-logger-ruby )を使用することによって,プログラム内から出力されるログを fluentd に乗せてストリーミング転送することが可能になります。今まで log4j などのライブラリから独自フォーマットログを出力・解析していた場合はそのライブラリを fluent-logger へ置き換え,それを用いてコード内の該当箇所から Post してやれば良いことになります。
fluent-logger は,その活用方法によっては非常に強力で柔軟なデータ解析を実現することができます。例えば Social Gaming Analytics においてはユーザーのアクセス履歴にはそれほど意味は無く,有用なのは個々のユーザーのアクション(ログイン・登録・メッセージの書き込み・アイテムの購入・友達とカード交換…)履歴であり,これらを取得することが重要になってきます。fluent-logger はこのための最適なツールと言うことができます。
1-4. Heroku Add-on
また,Heroku などの PaaS プラットフォーム上でアプリケーションを構築・運用している場合には,Treasure Data のサービスをアドオンという非常に簡潔な方法で活用すことができます。
Treasure Data Heroku Add-on を使用した場合には,アプリケーションのアクセスログは自動で収集され,かつ Treasure Data Storage に自動的に蓄積されていきます。また,前述した logger ライブラリの利用によって構造化されたカスタムログを簡単に Treasure Data Storage に流すことが可能です。Heroku を活用されている方は是非一度導入してみてください。使い方は非常にシンプルです。ドキュメントはこちらです。
また Heroku の他,Treasure Dataでは EngineYard との連携も行なっており,近く同社顧客向けの Treasure Data サービスも開始される予定です。EngineYard ユーザの皆様は,是非ご期待ください。
図2: Treasure Data Hadoop は現在 Public Beta として運用中です
2. ストレージの問題
「先月のデータと比較したい」あるいは「去年の冬のデータと比較したい」といった要求は,データ・アナリティクスを実践的に活用していく上では一般的なニーズです。
このため収集されたログは,常に解析可能な状態で保管・管理しておかなければ,その価値が失われます。しかし,ここにも問題があります:
- 大容量のストレージが必要になる
- 障害に備えてバックアップしたりレプリケーションしておく必要がある
- ストレージ・ミドルウェアの永続的な運用は困難
- 数年後でも読み出せるように,データフォーマットを設計しなければならない
単純な記録メディアの価格は下がり続けていますが,データを継続的かつ適切に管理し続けるコストは,依然として高く付きます。
大容量のログデータを保持する方法としては,HDFS などのミドルウェアを使用する方法がありますが,HDFS の永続的な管理は容易ではなく,あくまで分散処理を行うための一時的な保管場所になります。
Treasure Data では,ログデータを Amazon S3 上に保管します。S3 はクラウド上に構築されたオブジェクト・ストレージで,安価でありながら高い堅牢性と可用性が担保されています。自前でストレージサーバーを管理するという神経質な作業から解放されるという点で,S3 は現状より良いストレージと言えるでしょう。
さらに Treasure Data では,Amazon S3 上に独自の列指向型データベースを構築しました。これによって,ログを「構造化されていない生のログファイル」ではなく,「構造化されたテーブル」として保持します。つまり,fluentd を使って収集した構造化されたデータを,そのままの状態でTreasure Data Storage に保存しておくことが可能です。このデータベースに保存されているログには,いつでも解析クエリを発行することができます。
つまり Treasure Data では,データの管理をすべてクラウド側で行うことによってストレージにまつわる問題を解決し,実践的なデータ・アナリティクスに集中できるようにしています。
図3: Treasure Data Cloud Warehouse のアーキテクチャ(再掲)
3. 解析結果の活用に関する問題
最後に,解析された結果をどのように既存のシステムに統合・フィードバックし,活用していくかについて紹介します。
Treasure Data では,解析結果を「MySQLなどの各種データベースに書き出す機能」を提供しています。また,その解析を定期的に行うスケジューリング機能も提供しています。例えば,最新のランキング集計の結果を常に表示しておきたいというケースでは,ランキング集計を行う解析クエリをスケジュールに登録しておきます。Webアプリケーションは,その結果が書き出されるMySQLを参照していれば,その結果は定期的に自動更新されます。
またお客様の要望に応じて,解析結果の可視化を行うダッシュボードの提供も可能です。このダッシュボードでは,分〜年単位でのインターバルで定期的にSQLクエリを実行し,その結果をテーブル・ピボットおよび多種のグラフによって可視化することができます。
Treasure Data Analytics 第1回 〜Treasure Data Cloud Warehouse について(前編)〜
はじめに
Treasure Data Analytics シリーズは,Treasure Data の提供するクラウドサービス上で実行可能な様々なデータアナリティクスのユースケースなどを紹介して行く長いシリーズです。第1回および第2回では「Treasure Data」とは何か,またその特徴およびメリットは何かについて紹介する予定です。
第1回では Treasure Data の提供する Cloud Data Warehouse サービスのイントロダクションを,第2回では「データアナリティクスを行うための Platform とは」という観点で Treasure Data の魅力をお伝えできればと思っています。
※ なお Treasure Data は高度なインフラ・ソフトウェアテクノロジーを駆使しておりますが,本シリーズはデータアナリティクスを主眼においており,このサービスを支えるインフラ基盤技術に関しては詳しく言及していきませんのでご注意ください。Treasure Data の提供するインフラ基盤に強い関心のある方,そこにコミットしたいと思われている方は,是非僕まで別途ご連絡ください。当社では、多様な人材を日米両国にて絶賛募集中です。)
"Big Data Analytics Platform As a Service"
(図1)
Treasure Data は米国および日本市場を中心にデータ解析基盤をクラウドサービスとして提供するべく,データ処理の基盤技術周辺のオープンソースコミュティリーダーやトップエンジニア,オープンソースビジネスのプロが集まって設立された企業です。本社はシリコンバレーの Los Altos にある他,東京にも開発拠点を設け,日米両国にて積極的に製品開発及び事業開発を行なっています。
Treasure Data の主な使命はクラウド上で ”Big Data Warehouse & Analytics Platform” を提供し,その上で誰もがデータアナリティクスの力を入手でき,そのデータの力を持ってしてビジネス改善を図っていけるようにすることにあります。
実は「データアナリティクス」という言葉は,多くの人々が持っているイメージよりもはるかに複雑で,敷居の高いものです。簡単に言ってしまえば「ログを解析しそれによって導かれた結果を活用してビジネスを改善に導くもの」と言えるのかもしれません。しかし実際には
- 複数の種類のログが様々な場所に点在する場合,それらをどのようにして解析サーバーに集めてくるのか?(データ収集の問題)
- 日々増え続けるログをどこにどのようなフォーマットで保管していくのか?(データストレージの問題)
- 解析のための計算リソースの確保をどうするか?(計算リソースの問題)
- 解析した結果をどこに書き出し,どう活用していくのか?(解析結果の活用に関する問題)
といったログ収集から活用までにいたるあらゆるステップで問題が立ち塞がります。
データアナリティクスをきちんと始めるには,それぞれのステップで上記のような問題を解決してくれる専門家やリソース,インテグレーションのための長い時間が必要となるでしょう。Hadoop やデータベース系をきちんと運用していけるインフラ技術者,日々増え続けるデータをストレージするためのストレージサーバーの確保とそのセキュリティと可用性の担保,実際に解析を行うための計算リソース…,これらを持ってして初めてデータアナリティクスを始める事ができるのです。
(図2:データアナリティクスの前に立ちはだかる様々な技術・リソースの壁)
ではデータアナリティクスを始めるに当たって,全ての企業またはサービスにおいてこれらの人・モノのリソースおよび時間が絶対に必要なのでしょうか?
答えは「No」です。
そもそもデータアナリティクスのゴール:本当に専念すべき事は「データから有意義(かつアクショナブル)な結果を導いた上で,それらを活かしビジネスを改善していく」という部分にあって,本質的には「リソースを確保すること」でも「技術を習得すること」でも無いはずです。それらはあくまで手段・ツールであり,ここには世界中には様々な選択肢がふんだんに用意されているのですから,それらを活用しない手はありません。
Amazon Web Service はインフラ周辺の技術および種々のサーバリソースをクラウド上で提供してくれたことによって,今や誰もが簡単に Web Service を運用できる素晴らしい時代を切り拓いてくれました。
それと同じくデータアナリティクスもまた,必要な専門家やリソースはクラウド上から利用可能になり,誰もが簡単にアナリティクスの力を手に入れることができる時代がまさに今,切り拓かれていこうとしているのです。
Treasure Data もこの来るべき新しい時代の真のリーダーになるべく,先進的なサービスを世界に打ち出して行こうとしています。
Treasure Data の Cloud Data Warehouse について
(参考ドキュメント:Architecture Overview )
(※ 本章を読み始めるに当たって,まずはこちらの 3分間のチュートリアルビデオを見てもらえると良いと思います。)
Treasure Data の提供する Cloud Data Warehouse とは非常に簡単に言ってしまえば,クラウド上での
- 大規模データストレージの提供
- 大規模集計を行うための計算リソースの提供
という,データアナリティクスにおける2つの大きな柱を提供するサービスです。このサービスを活用すれば誰もが,PCとインターネットさえつながる環境にさえあれば(セキュリティの担保された)自身のクラウドストレージ上の任意のデータに対するアクセス,および大規模な集計ジョブを走らせることが可能になるのです。例えば昼下がりの喫茶店でコーヒーを飲みながら,Macbook Air から数百GBのデータに対して集計を走らせて結果を取得する,といった事が容易に行えるようになります。
もちろん,既に多くの企業が類似の製品やサービスを提供しています。その中における差別化要因として重要なポイントは,
- いかにこれらの導入の敷居(コスト・スピード)を下げられるか
- いかに自然に,簡単に1. 2.を取り扱うことができるのか
- 1. 2. の周辺技術で付加価値をどうつけていくか
等にあります。
Treasure Data では,各OS向けに用意された「Treasure Data Toolbelt」と呼ばれるツール群を導入するというたった数分の作業のみで 1. 2. のための利用準備を完了させる事ができます。あとは好きなだけ手持ちのデータをインポートし,好きなだけジョブを実行するのみです。そのジョブの実行もまた,SQLライクなクエリを実行することによって非常に簡単に扱うことができます。
(図3:Treasure Data Toolbelt では Linux ( rpm, deb ), MacOS, Windows 向けにパッケージが用意されています)
また Fluentd によるデータ収集,および柔軟な集計結果のエクスポート機能が1.2.の足回りを強力にサポートしてくれています。それでは順に見ていきましょう。
1. 大規模データストレージの提供
(参考ドキュメント:Data Import )
Treasure Data はクラウド上に巨大容量のストレージ(以後 Treasure Data Storage と呼ぶことにします)を構築しており,そこに任意のデータを様々な手段(Fluentd, Bulk Import など)でインポートすることが可能になっています。
例えば Bulk Import を利用すれば仮に数百GBのデータを持っていたとしても,効率良く安全にインポートすることが可能になります。Fluentd を利用すれば既に構造化されたログをストリーミングを通じてほぼリアルタイムに収集することが可能になります。
※ データインポートについては第3回の「クイックスタートガイド」で説明します。
2. 大規模集計を行うための計算リソースの提供
(参考ドキュメント:Data Processing )
一度データをインポートしてしまえば,以後はどこからでもコマンドラインツール ( td-command ) を通じてそれらのデータにアクセスすることができます。またそれらのデータ群に対しては(Hive互換の)SQLライクなクエリによって集計Jobを実行することができます。大規模な集計を走らせたい場合には,この計算リソースを拡充することによって高速に実行する事ができます。もちろんこれらは全てクラウド上の解析プラットフォーム上で実行されますのでローカルのマシンの性能には依存しません。
(図4:Treasure Data サービスの Architecture。Fluentd によるログ収集部分は, td-agent と呼ばれる機能強化版のツールによってまかなわれています。 )
※ さらにTreasure Data の強みは,この1.2.の機能の足回りを強力にサポートしている所にあります。今回は,「3. Fluentd によるログ収集機能の提供」と「4. 集計結果の柔軟なエクスポート機能の提供」について紹介します。
3. Fluentdによるログ収集機能の提供
(参考ドキュメント:Fluentd.org )
Fluentd は様々なデータソースに存在する(または生み出される)ログを,構造化したJSON形式でストリーミング収集することを可能にします。
Fluentd は,様々な場所に散在するあらゆるデータソースのログを JSON によって構造化されたストリームとして,ほぼリアルタイムに特定の場所( 例えば Treasure Data Storage )に集約させ続けることができるオープンソースです。またネットワーク遮断などにおけるデータの再送などの障害が生じた場合でも Fluentd が全て良きに計らってくれます。
※ Fluentdについては次回で詳しく説明する機会を設けます。
(図5:Fluentdにはコミュニティページがあります。)
4. 集計結果の柔軟なエクスポート機能の提供
クラウド上の集計ジョブによって出力された結果データは,様々なフォーマットおよび用途で後に参照されることになります。Treasure Data では,以下の4つのエクスポート手段を提供しています。(※ 一部開発中のものも含みます)
1. CSVファイルとしてローカルへ書き出し
集計結果は EXCEL や R や SPSS に読み込ませ,結果の整理や可視化,およびさらに深い解析を行う必要があるかもしれません。その場合にはCSVやTSV等のファイル形式でローカルに保存する機能を使用することができます。
2. MySQLやNoSQLへのデータベース書き出し
(参考ドキュメント:Result Output )
一方で hourly, dailyで定期的に集計 job を走らせる処理も多々あるでしょう。Treasure Data ではそれらの定期ジョブをスケジューラを利用して管理することができます。さらにそれらの job の実行結果を,任意の MySQL または DynamoDB やMongoDB,Redis といった NoSQL へ書き出すことも可能になっております。
(※ データベースの書き出し先は今後さらに拡充していく予定です)
3. Amazon S3への書き出し
他方,集計というよりもフィルタリングやクレンジングといった前処理を行った上で(来るべき時にすぐに活用できるよう),永続的なストレージに貯めておくという用途もあるでしょう。その場合に備えてAmazon S3への書き出しをサポートしています。
4. JDBC を介したフロントエンドツールへとの連携
(参考ドキュメント:Treasure Dat 3rd Party Tools )
また,Treasure Data 専用のJDBCドライバ(ベータ版として無償配布中)を用意していますので,JDBCドライバを通じて接続可能なあらゆるフロントエンドツール(解析ツール,レポートツール,ダッシュボードなど)とシームレスに連携することも可能です。また,今後 ODBC ドライバの提供も行っていく予定です。
まとめ
今回はTreasure Data の提供する Cloud Data Werehouse サービスのイントロダクションとして,いくつかの特徴を紹介しました。現在 Treasure Dataでは Sign Up Page よりトライアルアカウントを作成することが可能になっています。興味を持たれた方は是非ともトライアル申請を行った上で Quickstart Guide に進んでみてください。また本シリーズでもより丁寧なクイックスタートガイドを紹介していくつもりです。
※ ご質問・お問い合わせは support[at]treasure-data.com までお願いします。または Twitter や Facebook などを通じて僕の方にコンタクトしてくれても構いません。
コンプガチャの数理 -ガイドラインに基づいたゲームデザイン その1-
目次
1. 『コンプガチャの数理 -コンプに必要な期待回数の計算方法について-』
3. 『コンプガチャの数理 -ガイドラインに基づいたゲームデザイン その1-』
4. 『コンプガチャの数理 -ガイドラインに基づいたゲームデザイン その2-』
5月25日にコンプリートガチャガイドラインが策定され,コンプガチャに関して新しい規定が策定されたようだ。その中で現在可能なゲームデザインは以下に限定された。
『有料ガチャアイテムを含む特定の2つ以上の異なるアイテム等を全部揃えることを条件として、ソーシャルゲーム等で使用することができる景品類たる別のアイテム等を利用者に提供する方式をいう。なお、以下に該当するものを除く。』
- 利用者がアイテム等の種類を選択することによりその組み合わせを完成できるもの
- 異種類のアイテム等の組み合わせではなく、利用者が、同種類のアイテム等を一定個数揃えれば新規のアイテム等の提供を受けるもの
- 1点,2点,5点というように,異なる点数が付与されているアイテム等を利用者に提供し,合計が一定の点数に達すると,点数に応じて利用者が新規アイテム等の提供を受けるもの
今回は上記のガイドライン規定に従う形でコンプガチャに関する数学的ゲームデザインを考えてみようと思う。ところで数学的ゲームデザインとは,
『ある数学モデルのレールに沿ったゲームをデザインすることである。それによって,その背景にある種々の数学的性質を活用して優位な戦略を立てることが可能になる。 』
と定義し,全てのルールと確率値を公開し,確率操作を行わない,フェアなゲームの下で考えられるものであった。
はじめに
まず,ガイドラインに 3. の許可がきちんと明記されていることは重要である。これが無ければ,点数を集めて白いお皿がもらえる春のお楽しみも無くなってしまうからだ。ただし,この問題に関してはあまり面白みが無いので今回は省略する。今回は 1. および 2. に基づいた数学的ゲームデザインを考える。
結論としては,1. については完全コンプを目指さなくても期待回数を大きく増やすようなデザインが可能であることを示す。2. については次回に詳しく紹介する。
1. 部分コンプリートモデル
さて,1. についてはどう解釈すれば良いのかわからないけれども,今回は勝手に以下の様に解釈する。以下に定義するモデルを『部分コンプリートモデル』と呼ぶ。
「全 m 種類のアイテムの中の任意の n (n<m) 種類のみ集めればコンプリートと見なす」
また設定の簡略化のために,とりあえず n 種類のアイテムが集まれば良いものとする。(特定の n 種類に限定するとコンプの確率は低くなる。)また全種類集めるよりも,その一部のみ集めるルールの方がコンプまでの期待回数も少なくなるのは明らかである。
この問題に関しても,前回と同じく「The Coupon Collector's Problem」の枠組みで考えることができる。つまり
- a. 全アイテムで出現確率が等しい場合
- b. アイテムごとに出現確率が異なる場合
で考えることができる。
a. 全アイテムで出現確率が等しい場合
全 m 種類のアイテムの出現確率が等しく 1/m の場合を考える。今, を新たな i 種類目のガチャが出るまでに買わないといけない数であるとする。また,m 種類のガチャを全て得るための回数を とする。コンプまでに必要な期待回数 を求める問題は前回取り上げた問題である。この時の結果は,
である。ここで調和数 と置いている。よって n 種類のアイテムを集めるのに必要な期待回数 は,
で良い。それではこの結果を用いて全20種類のアイテム ( m = 20 ) から,1〜20種類 ( n = 1... 20) コンプするのに必要な期待回数を見てみよう。
左は m = 20,右は m = 100 の時の部分コンプ種類数 n を横軸に,縦軸に期待回数をとった推移図。このように n 種類集めるのに必要な期待回数は n の増加とともに指数的に増加するものの,初めから n/2 程度では期待回数の増加はほぼ線形オーダーでしかない。部分コンプリートモデルでは,全体の半分や1/4 の種類集めれば良いモデルなのでこれはあまり好ましい状況では無い。
例えば前回紹介した AKB48 のポスターコンプモデルでは,44枚全て集めるには192個のCDを買う必要があったが,10枚で良ければCD11個で良い。ゲームをデザインする側としては,あまり刺激の無いモデルとなってしまった。
なお,以上の実験に使ったRコードはエントリー最後に貼ってある。
b. アイテムごとに出現確率が異なる場合
では,出現確率が異なる場合はどうだろう?同じように実験してみよう。それぞれのアイテムの出現確率を とする。ただし,
とする。n = m の場合は完全コンプモデルで,m 種類全てのコンプに必要な期待回数 は,
であった。n 種類の場合は,
と表される。
まず初めに m = 20 に固定し,通常アイテムとレアアイテムが半々ずつ状況を考える。通常とレアアイテムの出現確率の比率を変えた以下の設定における,部分コンプ種類数 n の値ごとのコンプに必要な期待回数のテーブルを示した。
1. レアが 10倍出にくい場合(レア:10個,通常:10個)
(※ 例えば下のテーブルの 6 番目の 7.834 という数字は,6種類のアイテムをコンプするのに必要な期待回数を示している。この場合,期待回数は n の前後で変化は少ない。)
1-5 | 1.000 | 2.091 | 3.293 | 4.627 | 6.126 |
---|---|---|---|---|---|
6-10 | 7.834 | 9.816 | 12.168 | 15.053 | 18.761 |
11-15 | 23.906 | 31.266 | 41.474 | 54.932 | 72.008 |
16-20 | 93.397 | 120.641 | 157.217 | 212.192 | 322.187 |
2. レアが 50倍出にくい場合(レア:10個,通常:10個)
(※ 期待回数テーブルは n = 10, 11 のところで2倍の変化がある。)
1-5 | 1.000 | 2.106 | 3.345 | 4.750 | 6.375 |
---|---|---|---|---|---|
6-10 | 8.298 | 10.653 | 13.690 | 17.961 | 25.215 |
11-15 | 57.885 | 109.104 | 171.658 | 244.307 | 329.277 |
16-20 | 431.274 | 558.773 | 728.773 | 983.773 | 1493.773 |
3. レアが 100倍出にくい場合(レア:10個,通常:10個)
(※ 期待回数テーブルは n = 10, 11 のところで5倍の変化がある。)
1-5 | 1.000 | 2.108 | 3.352 | 4.769 | 6.414 |
---|---|---|---|---|---|
6-10 | 8.374 | 10.798 | 13.973 | 18.575 | 26.989 |
11-15 | 105.131 | 213.687 | 339.513 | 483.760 | 652.091 |
16-20 | 854.091 | 1106.591 | 1443.257 | 1948.257 | 2958.257 |
※ 以上の結果より,n = 10 と 11 のところに期待回数のギャップが存在し,かつレアアイテムの確率が低い ( 2. より3. の方が低い) ほどそのギャップが大きいことが伺える。
2. (上)と 3. (下)における n の値における推移を図示したものが上の図になる。左は全体 n = 1〜20 で,右は n = 8〜12 での局所的な図である。
今度は通常アイテムが 5 個,レアアイテムが 15個という設定を考えて以下の2つの設定を考えてみる。
4. レアが 50倍出にくい場合(レア:15個,通常:5個)
(※ 期待回数テーブルは n = 5, 6 のところで同じく2倍の変化がある。)
1-5 | 1.000 | 2.219 | 3.779 | 5.941 | 9.462 |
---|---|---|---|---|---|
6-10 | 20.708 | 37.410 | 57.170 | 79.103 | 103.161 |
11-15 | 129.655 | 159.098 | 192.223 | 230.080 | 274.247 |
16-20 | 327.247 | 393.497 | 481.830 | 614.330 | 879.330 |
5. レアが 100倍出にくい(レア:15個,通常:5個)
1-5 | 1.000 | 2.234 | 3.843 | 6.155 | 10.273 |
---|---|---|---|---|---|
6-10 | 36.246 | 71.406 | 110.771 | 153.655 | 200.469 |
11-15 | 251.969 | 309.191 | 373.566 | 447.137 | 532.971 |
16-20 | 635.971 | 764.721 | 936.387 | 1193.887 | 1708.887 |
(※ 期待回数テーブルは n = 5, 6 のところで同じく 3.6倍の変化がある。)
※ 以上の結果より n = 5 と 6 のところでも,期待回数のギャップが存在することがわかる。また,ギャップ差も n = 10 と 11 の間よりは多少は下がるが大きな変化が無いことがわかる。
5. (上)と 6. (下)における n の値における推移を図示したものが上図になる。左は全体 n = 1〜20 で,右は n = 3〜7 での局所的な図である。n が早い段階でも期待回数のギャップは起こる。
考察:期待回数のギャップをうまく利用しよう
上記の現象はよく考えてみると特別な事では無い。n = 10, 11 や n = 5, 6 のところのギャップは通常アイテムを全部集めて終わり,いざレアアイテムを(1つでも)集めようというところなのだ。
今回の実験結果は,必ずしも全てのアイテムを集めようとしなくても,レアアイテムの出現確率を十分小さくしておけば,それが1つでも出すためには多くの回数を要することを数値を持って示している。
この結果を受けて提供側が有利となる数学的ゲームデザインは通常アイテム n_a 枚とレアアイテム n_b 枚が存在する設定の下で,
『部分コンプ回数 n は必ず少なくとも1枚のレアアイテムが含まれるようにせよ。i.e. n_a < n に設定せよ。 』
ということである。上の例では「 n = 11 または n = 6 をもってコンプとせよ」ということである。この設定では,ユーザーはコンプまで残り1枚のところまでは非常にスムーズに集まるのに,最後の1枚だけがなかなか集まらないという状況になるだろう。
このゲームデザインにおいては全ての n において期待回数が計算できる。提供側はアイテムの出現確率を調節することによって,部分コンプまでの期待回数を全て計算できることこそが,数学的ゲームデザインの何よりの魅力である。上記の結果も考えてみれば当たり前の事であるが,数値を持って示せるのは非常に強力である。
次回は,2. の『同種類のアイテムを一定数集める』ことによってコンプリートとされるモデルと考える。この問題と同型の数学モデルは「Birthday Paradox」を一般化したものである。この問題に対しては,同種類のアイテムが
- 2 枚集まる(ダブる)
- 3 枚集まる(ダブる)
状況が何回目で起こりやすくなるのか,初めて2枚ダブる期待回数は,などと言った問題を考える。確率の話では例えば365種類のアイテムがあれば,23 回ガチャを回したユーザーの 1/2 はアイテムが2枚ダブっており,89回ガチャを回したユーザーの 1/2 はアイテムが3枚ダブっているといったことが示せる。また,4枚以上集まる状況は定式化ができても数値計算が難しくなってしまうことを紹介する。
※ a. で用いた R のコードはこちら。
※ b. で用いた R のコードはこちら。
A/Bテストの数理 - 第3回 [補足]:仮説検定の概念を改めて考える -
※ 第3回のブログを読んだけども,結局テスト(仮説検定)ってよくわかんないと言われるので,テストの概念をもう少し丁寧に説明することにした。特に「標本平均と母平均」,「帰無仮説を棄却すること」,「帰無仮説が棄却できないと何も言えないこと」について,焦点を当てている。
スケジュール
- 第1回 [読み物]:『人間の感覚のみでテスト結果を判定する事の難しさについて』:人間の感覚のみでは正しくテストの判定を行うのは困難である事を説明し,テストになぜ統計的手法が必要かを感じてもらう。
- 第2回 [読み物]:『「何をテストすべきか」意義のある仮説を立てるためのヒント』:何をテストするか,つまり改善可能性のある効果的な仮説を見いだす事は,テストの実施方法うんぬんより本質的な問題である(かつ非常に難しい)。意義のある仮説を立てるためのヒントをいくつか考える。
- 第3回 [数学]:『テストの基本的概念と結果の解釈方法について』:テストの基本的な数学的概念を説明し,またテスト結果をどのように解釈するのかを説明する。
- 第3回補足 [数学]:『仮説検定の概念を改めて考える』:テストの概念をもう少し丁寧に説明する。
- 第4回 [数学]:『実分野における9個のテストパターンについて』その1,その2:オンラインゲーム解析とキャンペーン事例に見る,テストにおける統計量の計算について説明する。
- 第5回 [数学]:『実際にテストを体感する』:いくつかのテスト事例に対し,サンプルデータを提供し実際に統計量の算出を行ってもらう。新シリーズ:「Treasure Data Analytics」の枠組み内で紹介することになりました。
母集団と標本について
統計学ではほとんどの場合,今手元にあるデータは全て「標本」であると考える。標本とは,「母集団」と呼ばれる全体から抽出された一部分である。例えば完全失業率は,日本国民全体(母集団)の中からランダムに抽出された10万人(標本)に基づいて算出される。A/B テストで得られたAとBのそれぞれのコンバージョン数などのデータもまた標本でしかない。
母平均と標本平均について
「平均」という言葉には実は2種類の意味がある。「母平均」と「標本平均」である。この違いの認識は非常に重要であるが,少なからずの人は「標本平均」を「母平均」と混同しているように思われる。
「母平均」というのはまさに母集団全体から求められた平均であるので,言わば真の平均値であり,かつこれは"定数"である。
一方「標本平均」というのは,母集団から"たまたま"集められた標本による平均であるので,必ずしも母平均とは一致しない。かつ,再度標本を取り直せばその値さえも変わってしまう。つまり標本平均とは "確率変数"である。
例:今,毎回 0 から 9 までの数字が独立かつランダムに選ばれるプログラムから,5個の数字を取ってくるという行為を2回行うとする。この時,
- 1回目は { 1, 4, 8, 3, 1 },
- 2回目は { 5, 8, 2, 7, 0 }
であったとする。この場合(母集団 { 0,1,2,3,4,5,6,7,8,9 } に対して),
- 母平均: (0+1+2+3+4+5+6+7+8+9) / 10 = 4.5
- 1回目の標本平均: (1+4+8+3+1) / 5 = 3.4
- 2回目の標本平均: (5+8+2+7+0) / 5 = 4.2
となり,これら3つの平均はいずれも異なっている。
ただ僕たちは経験的に,標本数が大きければその標本平均は母平均にかなり近くなること(大数の弱法則)を知っている。また「多数の標本を抽出して標本平均を求める」試行を 1 セットとすると,これを数セット行ったときには,多くの標本平均が母平均の近くに密集するであろうこと(中心極限定理)も何となく知っている。
標本抽出における重要なルール:「同一」・「独立ランダム」
ところで,母集団から標本を得る際には,忘れてはいけない重要な仮定がある。それは「同一」かつ「独立ランダム」に標本を抽出してくることである。
- 「同一」というのは同じ母集団から抽出してくるということである。
- 「ランダム」に抽出するというのは,母集団から偏り無くまんべんなく抽出してくることである。そうでない場合というのは,例えば労働調査では,特定の県に偏って標本を取得することに該当する。この場合,母集団を良く代表する標本平均が得られたとは言いにくい。
- 「独立に」抽出するというのは,標本同士が無関係であるということである。層で無い場合というのは,例えば労働調査では,まず最初に選んだ人に次の人を紹介してもらう,といった形で標本を取得していくことに該当する。独立で無い標本というのは傾向がどうしても似通ってしまうので,これも全体を良く代表する標本平均は得られにくい。
「AとBの母平均に差があるか」という問題に対するアプローチ
A/Bテストにおいて「AとB に違いがあるか」という問題は,「AとBの母平均に差があるか」という問題である。これに対するアプローチは,まず十分な数の標本からの標本平均を計算し,これを母平均の替わりをさせようとするところから始まる。
しかし,標本平均は"確率変数"であったので同じテストを複数回行うならば,標本平均 と はだいたい各母平均の近くにばらつくものの,その位置関係・距離関係は毎回異なるのである。
- 左図は母平均が同じ(ここではあくまで母平均の違いについて関心があるので,分散は異なっていても良い)場合。A, Bの標本数が十分に大きければ,得られる各標本平均は同じ値の母平均の近くでばらつくので標本平均間の距離も小さくなる傾向がある。
- 中図は母平均が異なる場合。得られるA, Bの標本平均は,各母平均の近くでばらつくので,標本平均の距離は自然と離れている傾向がある。
- しかし右図のように母平均が異なる場合でも,"たまたま" A, Bの標本平均の距離が小さくなるようなケースが得られる場合もある。また逆に,母平均が同じ場合でも,"たまたま"標本平均の距離が離れる場合もある。この場合は厄介である。
では,どのようにしてAとBの真の「違い」を判断すれば良いのであろうか?A, B の標本平均がどれくらいの距離内におさまっていれば良いのだろうか?
帰無仮説を持って棄却する,というアプローチ
ここから前に進む方法は,まずは「母平均が等しい」と置いてみることから始まる。そのように仮定することで,2つの標本平均から新しい統計量 T を作ることができるのだ。この T もまた実験の度に変動する確率変数であるが,T は母平均が等しいという仮説の下で,平均 0,分散1の標準正規分布に従う。しかしこの仮定が不適切な場合は T はこの分布のはるか両端に追いやられることになる。つまり統計量 T への変換は「標本平均の差」が元々大きければ大きいほど両端遠くへ,小さければ小さいほど母平均値 0 の近くにばらつくようにする変換なのである。
また,T の従う分布は言わば「母平均が 0 であるという帰無仮説の支持率」を示す診断と考えて良い。「有意水準」というのは「この値以下の支持率なら帰無仮説を疑う」任意の値である。有意水準 0.05 というのは,「T の支持率が5%以下ならば帰無仮説を受け入れない」ことを意味する。
A,B の母平均が同じ場合
- Case1 は母平均が同じで,共に母平均周りに標本平均がとれた場合。この場合,変換後の T は 0 の近くに移動する。この時の帰無仮説の支持率は非常に大きくなる。
- Case2, Case3 では"たまたま"いずれかの標本平均がその母平均から離れた値であった場合だ。この場合は標本平均の差は大きくなり,変換後では両端にとばされてしまい,支持率は低いと見なされてしまう。(第一種の誤り)
A,B の母平均が異なる場合(μ_A < μ_B)
A, B の母平均が異なり,かつ μ_A < μ_B の場合である。
- Case4 の場合はもとの母平均の違いを標本平均が良く表しているために,変換後の T は右端へ追いやられる。これによって帰無仮説の支持率は低くなり「μ_A = μ_B」という帰無仮説は棄却され,「AとBには有意な差がある」と判断できる。
- Case5, Case6 は厄介である。本来母平均が異なっていながら標本平均の差は近くなってしまっている場合だ。この場合は帰無仮説を支持し,棄却できないという「第二種の過り」を犯してしまうことになる。
A,B の母平均が異なる場合(μ_A > μ_B)
A, B の母平均が異なり,かつ μ_A > μ_B の場合である。
- Case8, Case9 は先ほどと同じく,「第二種の過り」を犯してしまう例である。
A,B の母平均が異なる場合(μ_A < μ_B):片側検定
実は片側検定という考え方がある。AとBが単純に「違いがある」という対立仮説を作るのでは無く,「母平均Bの方がAよりも大きい」という対立仮説を立てる方法である。この場合「μ_A > μ_B」である事は全く関心が無いので,変換後の T が右側に飛ばされることがのみが棄却の動機になる。この場合の有意水準 0.05 というのは棄却域を,今まで両端併せて 5% の領域と考えていたものが,今度は右側だけ考えて全体の 5% の領域となる。同じ値 T でも両側検定と片側検定の場合ではp-値が異なってくる。
「帰無仮説を棄却できない→何も言えない」というロジックについて
さて,帰無仮説を棄却できない場合は「AとBは同じ」と結論づけるのではなく,「何も言えない」という結論をするべきだと何度も行ってきたが,ここで改めてその理由を考えてみよう。
上図の Case5, Case6, Case8, Case9 をもう一度見て欲しい。このケースは本来AとBに差があるのに棄却できなかった第二種の誤りの例であるが,これらがどれくらいの確率で起こりうるのかは全く未知なのである。もし本来異なるのに同じと判断してしまう確率が 30% だったらどうしよう?「同じである」と判断しても,30% で間違っているのだからテストの信憑性は全く無くなってしまう。このように,帰無仮説を容認することは,未知の確率で起こる第二種の誤りを内在することになってしまうので,精神衛生上大変よろしくないである。「何も言えない」という判断は,これよりはむしろ無難な判断をしているといえる。
A/Bテストの数理 - 第4回:実分野における9個のテストパターンについて その2 -
2. Hypothesis-Driven Testing 〜キャンペーン施策を事例に〜
事例6. (A/Bテスト:2つの比率の差のテスト,ただし排反データ)
問『あるメーカーAは新しいビールXを開発した。今,斬新なデザイン1を採用するか無難なデザイン2を採用するかを決めかねている。そこで実際にあるお店で300人の買い物客にどちらのデザインが良いかを選んでももらう実験をした。結果はデザイン1が163人,デザイン2が137人であった。さて一見デザイン1の方が人気のようであるが,優位な差が見られるだろうか』
解:デザイン1の比率を ,デザイン2の比率を とする。n = 300, = 163 / 300 = 0.542, = 137 / 300 = 0.457 である。
帰無仮説:「p_1 = p_2 (= p)」,対立仮説:「p_1 ≠ p_2」
統計量:帰無仮説の下で,
は 標準正規分布 に従う。, を標本比率 , で置き換え,
よって p-値は,pnorm(1.540) = 0.06 > 0.025 。
∴ 帰無仮説は棄却されず,デザインに差があるとは言えない。
事例7. (2つの母平均の差のテスト)
問:『今度はライバルメーカーBのビールYを用意し,220人の客に両者を飲んでもらいそれぞれのビールに 10 段階評価を付けてもらったところ,以下のテーブルを得た。ビールXの方が評価が良さそうであるが,ビールXとYの間には評価に差があると言えるか』
n | ビールXの評価(x_i) | ビールYの評価(y_i) | d(=x_i-y_i) | d^2 |
---|---|---|---|---|
1 | 8 | 6 | +2 | 4 |
2 | 6 | 7 | -1 | 1 |
3 | 9 | 5 | +4 | 16 |
... | ... | ... | ... | ... |
220 | 8 | 6 | +2 | 4 |
計 | - | - | +308 | 1012 |
解:ビールXの平均評価を ,ビールYの平均評価を とし,その差の平均を とする。標本数 n = 220, 標準偏差 とする。
帰無仮説:「 μ_d = 0」,対立仮説:「 μ_d ≠ 0」
統計量:帰無仮説の下で,
は 標準正規分布 に従う。
。
よって p-値は,pnorm(12.74) = 0 < 0.025 。
∴ 帰無仮説は棄却され,ビールの評価には有意な差があると言える。
問:『メーカーA は大規模なイベントを実施し,ブランディング効果の向上を図ろうとした。以下は175人に対して実施した,イベント実施前と後の,ライバル含む 3 メーカーでの好みブランドのアンケート結果である。さてさて,このキャンペーンによって有意な好みの推移が起きたであろうか。』
解:
帰無仮説:「 」
統計量:帰無仮説の下で,
, は最尤推定量。
は に従う。a をカテゴリ数として, である。
, 。
よって p-値は,chisq_(19.2, 3) = 0.03 < 0.05 。
∴ 帰無仮説は棄却され,ブランドの推移があったといえる。
3. その他
事例9. (小標本の母比率の検定)
問:『シーズンも後半にさしかかった頃,最近まで打率 .350 の首位打者であったイチローは,ここにきて20打数3安打と振るわなくなり,首位打者の座が危惧されている。さて最近のイチローの成績はとりわけ悪いといえるだろうか,それともたまたまであろうか』
解:最近の打率を p とする。最近の打席数を n,実現値を t とおく。ここでは n =20, t = 3 となる。標本数が少ないことに注意する。
帰無仮説:「p = p_0 (= 0.35)」,対立仮説:「p < 0.35」
統計量:帰無仮説の下で,
は に従う。今, なので,
は F(8, 34) に従う。
よって p-値は,pf(2.833, 8, 34) = 0.016 < 0.025 。
∴ 帰無仮説は棄却され,イチローは最近とりわけ成績が悪いと言える。
※ 仮に帰無仮説が棄却できなかった時は成績に関して「何もわからない」ことになる。
事例10. (無相関検定,相関と因果)
(「明解演習 数理統計」より,面白い問題があったので利用させてもらった。)
問:『「馬鹿はカゼをひかない」という俗説の信憑性を統計学的に立証しようとよくカゼをひくM君が彼の学友25名を任意抽出して,最近1年間にカゼにかかった回数と数学の成績との相関関係を計算したら,なんと0.41であった。カゼの回数と数学の成績は関係があるといえるか。』
解:母相関係数を ρ とする。
帰無仮説:「ρ = 0」,対立仮説:「ρ ≠ 0」
統計量:帰無仮説の下で,
は に従う。今,n = 25, r = 0.41 なので
よって p-値は, t(2.156, 23)=0.0209 < 0.025 。
∴ 帰無仮説は棄却され,カゼの回数と数学の成績は相関があると言える。
※ しかし,ここで注意すべきはたとえ結果から相関関係は導かれても,因果関係を導いたことにはなっていないということである。相関は言えても因果:「数学の成績が悪い【から】カゼの回数が少ない」i.e.「馬鹿はカゼをひかない」とは言い切れないのである。
そもそもこの問題は因果関係:「馬鹿はカゼをひかない」をいう仮説を,無相関検定のみで立証しようとしたこと(相関関係は因果関係を含意しない )ところに誤りがある。因果関係の妥当性を示すには有意な相関(密接性)と時間性、普遍性、特異性、合理性を示す必要がある。
A/Bテストの数理 - 第4回:実分野における9個のテストパターンについて その1 -
スケジュール
- 第1回 [読み物]:『人間の感覚のみでテスト結果を判定する事の難しさについて』:人間の感覚のみでは正しくテストの判定を行うのは困難である事を説明し,テストになぜ統計的手法が必要かを感じてもらう。
- 第2回 [読み物]:『「何をテストすべきか」意義のある仮説を立てるためのヒント』:何をテストするか,つまり改善可能性のある効果的な仮説を見いだす事は,テストの実施方法うんぬんより本質的な問題である(かつ非常に難しい)。意義のある仮説を立てるためのヒントをいくつか考える。
- 第3回 [数学]:『テストの基本的概念と結果の解釈方法について』:テストの基本的な数学的概念を説明し,またテスト結果をどのように解釈するのかを説明する。
- 第3回補足 [数学]:『仮説検定の概念を改めて考える』:テストの概念をもう少し丁寧に説明する。
- 第4回 [数学]:『実分野における9個のテストパターンについて』その1,その2:オンラインゲーム解析とキャンペーン事例に見る,テストにおける統計量の計算について説明する。
- 第5回 [数学]:『実際にテストを体感する』:いくつかのテスト事例に対し,サンプルデータを提供し実際に統計量の算出を行ってもらう。新シリーズ:「Treasure Data Analytics」の枠組み内で紹介することになりました。
(※ [読み物] は数学知識を前提としない内容で [数学] は数学知識をある程度前提としたおはなし。)
はじめに
様々なテストパターンを,オンラインゲーム解析とキャンペーンの事例で説明する。また前者におけるテストを "Data-Driven"な,後者を"Hypothesis-Driven"なテストと位置づけて,特に前者のテストは日々のデータ解析において「傾向検知」「異常検知」自動アラートの役割を果たしてくれる可能性がある事を説明する。
(ところで,日常のデータ解析にテストを常時活用することを僕は「TDD: Test Driven Data Mining」と呼んでいる。)
全ての問題で共通においている前提
※ 検定方向ついて
以下で紹介するテストは全て両側検定としている。両側検定についてはこちらを参照されたい。両側検定にする理由は,(1) 片側より棄却されにくいこと,(2) 信頼区間を同時に求める際に,棄却域と信頼区間が交わるような矛盾を極力避けるため。(ただし信頼区間についてはここでは取り上げない。)
※ 有意水準について
有意水準は全て 0.05 としている。
※ サンプルサイズについて
計算する統計量とそれの従う分布(特に標準正規分布か t 分布かで)はサンプルサイズによって異なってくる。ここでは「大標本」を n > 100 または n_1 + n_2 > 100 ,それ以外を「小標本」とみなす。ただし,母比率の検定は n > 30 を大標本とする。
結果の解釈方法について
第3回の最後にも紹介したが,テストの思考フレームワークは以下に統一される:
- 棄却を目的として,帰無仮説をこしらえる。
- 帰無仮説の下,標本からある分布(正規分布・t分布・F分布・χ^2分布など)に従う統計量 T を求める。
- 統計量 T がその分布の元で稀なケースかどうかをチェックする。
- 稀なケースであり,帰無仮説を疑う方が妥当であると判断できる場合は帰無仮説を棄却し、対立仮説を採択する。そうでないなら何もわからないと判断する。
この「稀なケース」と判断する手段について,p-値 の役割と共に説明したい。
p-値 とは「帰無仮説の下で実際にデータから計算された統計量よりも極端な(大きな)統計量が観測される確率」で表される。これは例えば p-値が 0.05 の時,「あなたが計算した計算量 T が(仮定する)分布から得られる確率は 0.05 である 」と述べていることになる。テストのスタンスは帰無仮説を棄却する事であった。つまり p-値 が小さければ小さいほど,T がこの分布に従っているという帰無仮説をより強く疑うことができる。
ここでは「稀なケース」と判断する場合には,両側検定では p-値 が 0.025 より小さいときとする。(有意水準 0.05 の両側検定。)
統計量Tにおける p-値 は x>T なる区間の面積。この区間から値が得られるのは「非常に稀」考えられる。標準正規分布においては T=1.96 の時,p-値は 0.025 となるので,T が1.96 より大きければ(あるいは反対側,T が -1.96 より小さければ)この分布において「稀なケース」と判断する。
Hypothesis-Driven Testing と Data-Driven Testing について
テストにはその実施方法において大きく2つに分類できる。「Hypothesis-Driven Testing」と「Data-Driven Testing」である。
Hypothesis-Driven Testing
A/Bテストや実験計画法に代表されるこの方法は,
(1) 仮説を立て,(2) 実験計画を立て,(3) 実験を実施,(4) 結果からテストを行う
というアプローチを取る。このアプローチのメリットは,始めに検証したい仮説がはっきりしているために厳密なテストを行いやすいことである。ブロック化や完全無作為化,あるいは複数の因子があるならばその交互作用も考慮に入れた上での計画が設定でき,系統的な誤差などの影響を受けにくくできる。一方デメリットは,まず何より仮説ありきであること,毎回の実験コストがそれなりにかかることなどによってそれほど気軽に行えないというところである。
Data Driven Testing
一方データ解析からスタートするテストがある。それは,
(1) 解析によって通常とは異なる傾向(異常)を発見する
(2) データに対してテストを行い,有意な違いがあるのかを統計的に確かめる
(3) 有意な違いが見られる場合は,解析によってその原因や要因を追求する
(4) 結論を出す,または解析不十分で仮説レベルにとどまるなら Hypothesis-Driven Testing を実施する
というアプローチである。例えばオンラインゲームの文脈で言えば,今日の課金分布やセグメント間の分布の傾向,過去のそれと異なるか否かをテストによって見つけ,その原因を分析し,結論を導いていく。
この場合のメリットは既に実験結果と見なせるデータが揃っているために,データを得るための実験ステップが無いことが挙げられる。デメリットは正確なテスト(標本のランダム性や独立性が不十分など)が行えない事である。
1. Data-Driven Testing 〜 オンラインゲーム解析を事例に 〜
ユーザー数百万人を誇るあるオンラインゲームがある。このサイトの全ユーザーの中から 1/1000 程度のユーザーの属性情報を独立かつランダムに取得できるとする。また,データベース上の課金テーブルにも自由にアクセスでき,これらサンプルユーザーの課金情報がいつでも参照できる状況にあるとする。
事例1. (母分散未知の母平均テスト)
問:『サンプルユーザー1000人の平均年齢を計算してみると,36.4歳,標本不偏分散は 15.0 であった。日本のゲーム全体でのユーザーの平均年齢が 34歳 であるとするなら,このゲームの全ユーザーの平均年齢は,全ゲーム平均に比べて異なると言えるか。』
解:サンプルユーザーにおける平均を ,標準偏差を とする。また,全ゲームでの平均を μ とする。
帰無仮説:「 」,対立仮説:「 」
統計量:帰無仮説の下で,
は 標準正規分布 に従う。
。
よって p-値は,pnorm(5.06)=2.10e-07 < 0.025。
∴ 帰無仮説は棄却され,全ゲーム平均とは異なると言える。
事例2. (適合度検定)
問:『今度はサンプルユーザーの年齢を,10歳ごとの年代に分けて集計してみると以下のテーブルが得られた(有効数 832人)。こうして眺めて見ると,10代, 20代, 30代, 40代, 50代の人数比が 3 : 3 : 9 : 1 (メンデルの法則)のようになっているように見える。年代によるこの人数比の仮説が妥当かどうか確かめよ。』
カテゴリ | 10代 | 20代 | 30代 | 40代 | 合計 |
---|---|---|---|---|---|
観測個数 | 146 | 163 | 479 | 44 | 832 |
解:以下の様なテーブルを作る。
カテゴリ | 観測個数 n_i | 理論個数 m_i | n_i-m_i | (n_i-m_i)^2 | (n_i-m_i)^2/m_i |
---|---|---|---|---|---|
10代 | 146 | 156 | -10 | 100 | 0.6410 |
20代 | 163 | 156 | 7 | 49 | 0.3141 |
30代 | 479 | 468 | 11 | 121 | 0.2585 |
40代 | 44 | 52 | -8 | 64 | 1.2308 |
計 | 832 | 832 | 0 | - | 2.4444 |
帰無仮説の下でカテゴリ数を a とする。
帰無仮説:「ユーザー数の年代分布の比率は 3 : 3 : 9 : 1 である」
統計量: は自由度 a-1 のχ^2 分布に従う。テーブルより T=2.444 。
よって p-値は,pchisq(2.444,3)=0.485 > 0.05。
∴ 帰無仮説は棄却されず,年代ごとの人数比率は 3 : 3: 9 : 1 に従っているとは言えない。
事例3. (独立性の検定)
問:『年代による分類に加えて,今度はゲームプレイ時間を「1時間以内」「1〜3時間」「3時間以上」と分類し,年代と併せてテーブルを作ってみた(有効数360)。さてさて,年代とプレイ時間に関係があると言えるだろうか』
観測値テーブル n_ij
カテゴリ | 10代 | 20代 | 30以上 | 計 |
---|---|---|---|---|
1時間以下 | 25 | 103 | 52 | 180 |
1~3時間 | 16 | 39 | 17 | 72 |
3時間以上 | 19 | 38 | 51 | 108 |
計 | 60 | 180 | 120 |
360 |
解:
帰無仮説:「年代とプレイ時間は無関係である」
統計量:帰無仮説の下で,以下の期待値(最尤推定値)テーブル m_ij を作る。
カテゴリ | 10代 | 20代 | 30以上 | 計 |
---|---|---|---|---|
1時間以下 | 30 | 90 | 60 | 180 |
1~3時間 | 12 | 36 | 24 | 72 |
3時間以上 | 18 | 54 | 36 | 108 |
計 | 60 | 180 | 120 | 360 |
帰無仮説の下で,カテゴリ数を a×b として
は自由度 (a-1)(b-1) のχ^2 分布に従う。
。
よって p-値は,pchisq(18.349, 4) = 0.001 < 0.05 。
∴ 帰無仮説は棄却され,年代とプレイ時間は関係があると言える。
事例4. (A/Bテスト:2つの比率の差のテスト)
問:『5月は積極的な招待キャンペーンを行っており,特にそれによる招待成功率の向上が期待されていた。結果は 5月が 530人/2000人 = 26.5%で 4月の 230人/1000人 = 23.0%で効果があったように思われる。さて実際,このキャンペーンは成功だったといえるだろうか。つまり4月に比べて5月の招待成功率は高くなったといえだろうか。』
解:(統計量の導出方法は第3回参照)
として,
帰無仮説:「p_1 = p_2 (= p)」,対立仮説:「p_1 ≠ p_2」
統計量:帰無仮説の下で,
は 標準正規分布 に従う。
よって p-値は,pnorm(2.078) = 0.019 < 0.025 。
∴ 帰無仮説は棄却され,前月よりも招待成功率は高くなったと言える。
事例5. (等分散検定)
問:『アイテムA とアイテムB の分布を見ると,平均売上額は同じであるようだが,アイテムAの分布は平均を中心に山を形成しており,逆にアイテムB は平均を中心に凹んだ谷を形成しているようである。今,標本分布の可視化が行えような状況で,アイテムA とアイテムB の違いを導き出すとするならば,どのような仮説のもとでテストを行えば良いだろうか。』
解:平均が同じだからといって,分布の形まで同じとは限らない。ここでのテストはアイテムA の アイテムB の分散が同じであるかどうかのテストを行うのが好ましい。例えばこの問題において,
- | 課金者数 | 平均課金額 | 標準偏差 |
---|---|---|---|
アイテムA | 300 | 1503 | 235 |
アイテムB | 400 | 1492 | 193 |
であったとする。アイテムA の分散を σ_a,標本不偏分散 を U_a,アイテムBの分散を σ_b,標本不偏分散を U_b とおく。
帰無仮説:「σ_a = σ_b 」,対立仮説:「σ_a ≠ σ_2」
統計量:帰無仮説の下で,
は に従う。
。
よって p-値は, pf(1.48383, 299, 399) = 0.0008 < 0.025 。
∴ 帰無仮説は棄却され,両者の分散には差があると言える。
Data-Driven Testingの神髄
データ解析者は日々たくさんのデータを眺め,その中から傾向を見いだし解析につなげるといった事が求められる。しかしながら,多くの種類またはカテゴリを持つあらゆるデータに対してそれを実行するのは極めて困難で有り,また人間の勘によって発見された傾向は,真実における偶然である事も多い。
データ解析の枠組みの中にシステム化され組み込まれたテストは,そういった解析の入り口である「傾向検知」アラートという役割を担う事ができる。
過去のデータの統計値を保存しておけば,本日/本期間の売上・ログイン・イベント参加率などのあらゆるデータに対してテストを自動実行できる。これによって検知された傾向の違いの原因を探り,真実を導くことは,今度は解析者の腕の見せ所である。
また,それは単に平均という1次元の値だけでは無く,適合度検定や独立性検定に見られるようにセグメント間の分布の違いをもテストしてくれる。その結果を持って解析者はまた,数理モデル化という手法を持って事象を記述する。
このように実社会において,テストの持つポテンシャルは多くの人が思っているより大きく,そして革新的である。「Treasure Data Analytics」シリーズのどこかで,この「Test Driven Data Mining」の魅力を,Fluentd と Hive への実装を持って紹介する予定である。
A/Bテストの数理 - 第2回:「何をテストすべきか」意義のある仮説を立てるためのヒント -
※ もはやテストの文脈と少しかけ離れた内容になっております,息抜きの読み物としてお楽しみ下さい…
スケジュール
- 第1回 [読み物]:『人間の感覚のみでテスト結果を判定する事の難しさについて』:人間の感覚のみでは正しくテストの判定を行うのは困難である事を説明し,テストになぜ統計的手法が必要かを感じてもらう。
- 第2回 [読み物]:『「何をテストすべきか」意義のある仮説を立てるためのヒント』:何をテストするか,つまり改善可能性のある効果的な仮説を見いだす事は,テストの実施方法うんぬんより本質的な問題である(かつ非常に難しい)。意義のある仮説を立てるためのヒントをいくつか考える。
- 第3回 [数学]:『テストの基本的概念と結果の解釈方法について』:テストの基本的な数学的概念を説明し,またテスト結果をどのように解釈するのかを説明する。
- 第3回補足 [数学]:『仮説検定の概念を改めて考える』:テストの概念をもう少し丁寧に説明する。
- 第4回 [数学]:『実分野における9個のテストパターンについて』その1,その2:オンラインゲーム解析とキャンペーン事例に見る,テストにおける統計量の計算について説明する。
- 第5回 [数学]:『実際にテストを体感する』:いくつかのテスト事例に対し,サンプルデータを提供し実際に統計量の算出を行ってもらう。新シリーズ:「Treasure Data Analytics」の枠組み内で紹介することになりました。
(※ [読み物] は数学知識を前提としない内容で [数学] は数学知識をある程度前提としたおはなし。)
はじめに
テストはその手法よりも,何をテストするかが重要であるが,そのための意義のある仮説を導くのは容易ではない。かと言ってテストを実施するコストを考えれば,適当な仮説を数打てば良い問題でも無い。良い仮説を立てるためには長年の経験や業務知識が必要であると言えるだろう。ただ,ここではそういった固有知識を必要としない汎用的な仮説を導くためのヒントを紹介する。
「クリックする」という観点から「選択する」という観点へ
例えば A/B テストの仮説と言えば,「リンクの色を変えたら〜」「画像を差し替えたら〜」「ボタンの文言を変えたら〜」といったものがメジャーである。
これらは皆,ユーザーがあなたのサイトのあらゆる場所を「クリックしている」という認識が根底にあり,これより導かれる仮説は,クリックされる物体に対して「目立ちやすさ」や「わかりやすさ」を改善することの効果に期待するものである。
A/Bテストの生事例 蔵出し14パターン一気紹介 (ポイント解説付き)
上記のサイトとはこのような "クリック指向" な仮説に基づく A/B テストの事例がたくさん載っていて非常に参考になる。(ただ p-値などでなく,CTRの変化だけで効果を述べている点で説得力に欠けると思われるのは,第1回に述べた通り。)
あらゆるものを「選択している」という観点で眺める
本ブログでは上記の観点とは異なり,次の様な観点を導入している。ユーザーがあなたのサイトのあらゆる場所・場面で「選択している」と考えるのである。
(例えば,あるWebサイトにアクセスすることや,あるリンクを押すこと,本を選ぶ事などは,「選択可能な集合体からの選択」である。自分のアバターを選ぶこと,アイテムを購入すること,ゲーム内で友達に挨拶することは,「可能な行動対象群の中からの選択」である。)
「選択」の裏には人間の意識が有り,心理がある。人間がどのような心理で「選択」を行うのか,その事がわかれば僕たちは自分たちのサービスを改善していく(または有利に進める)ことができるかもしれない。心理学や行動経済学などは,この人間の選択の心理を追求している学問である。そういった学問から導かれている結果・仮説を持ち込めるこのアプローチはそれなりに意義がありそうだと思う。
以下に挙げる心理学の研究はそれ自身があなたのサービスの改善につながる仮説にマッピングが可能なものとは限らないが,改善のための何かしらのヒントになり,かつ関心のあるものは実施の上テストしてその効果を確認してみてはどうだろう。
マジカルナンバー7±2
George Armitage Miller は,人間の短期記憶可能な物体や事実の数は 7±2 個であることを1956年の論文:「マジカルナンバー7±2:われわれの情報処理処理能力の限界」で述べている。人間はこれ以上の数になると知覚判断に影響を与えてしまうらしい。それは位置情報,音,味,物体の色,明るさといったあらゆる事においてである。
また,この研究は情報をブロック化することによって,知覚判断が改善されることも示唆している。確かにクレジットカードの12桁を覚えるのは難しいが,4桁ずつに区切った番号それぞれを記憶しておくことは前者のそれよりは簡単であろう。
このヒントを受けて,例えば「サイトのメニューの数を項目の削減や,カテゴリ細分化によって,1つのブロックを7個前後にすることでサイトのユーザビリティが向上する。」と考えてみることができる。(ただし,ユーザーは必ずしもメニュー項目を記憶する必要は無いので,この心理学的見地から導かれる実際の仮説はもっと練る必要がある。)
また,オンラインゲームの脈略で考えてみる。オンライン上の仲間とパーティを組み,互いに協力しながらダンジョンクリアを目指すようなゲームがあったとする。ゲーム全体のダンジョンクリア数を増やすことが良いことであるなら,
「常にお互いを認識しあえ,親密度の高いパーティを形成するための最適なパーティ人数はいくらが最適か?」に関するテストを7前後の数字を検証してみるのも。
「最上部」にあることの優位性
「最上部にある,と言うことが確かに他の位置のものよりも選択されやすいという仮説」の研究結果は多くある。著書「The Art of Choosing 」では,選挙の候補者が投票用紙に最上位に記載されている時とそうでない時の得票数の違いを検証し,平均的なアドバンテージが 2 %であることを述べている。
2000年のアル・ゴアとジョージ・ブッシュの選挙における得票数の差はほんの少しであった。多くの州で投票用紙の掲載準備が軽視されていたこの選挙においては,投票用紙の最上部の多くはブッシュであったことが知られているが,もしブッシュの名前が最上位で無かったとしたら,アメリカの社会は今と少し変わっていたのかもしれない。
アンカリング効果
人はあらゆる選択において「初期値」の影響を多大に受けている。
転職面接で前職の給料を聞かれた際に,200万円と答えるのと1000万円で答えるのではおそらく提示される価格は変わってくる可能性は結構ありそうだ。
このように人はアンカー(規準値・初期値)となる数字によって,その後の選択に影響を与えることが知られている。たとえそれが事実でないにせよ,統計的に基づいた意味のあるものでなくても,少なからずそのアンカーに引っ張られた選択を行ってしまう。
例えばあるレストランに対して5段階評価をつけるとする。また,その際に他の人の評価,あるいは全体の平均値が1つ見えているとする。アンカーが星5つの場合と,星1つであった場合では,あなたのつける星の数は変わってしまうかもしれない。
逆に言えば,このアンカーを利用して売り上げの改善が見込める可能性があるかもしれないということだ。
例えばPCを販売するあなたのサイトでは,複数のパーツ(CPU・メモリ・HDD)にグレードがついており,もちろんユーザーには高いグレードの構成にしてもらって購入させたい。もし,初期設定のグレードが全てにおいて最下位のものであったのなら,その初期のグレードを中程度のものに変更してみてはいかがだろう。また個々のパーツでの最適な初期グレードはいくらだろうか。これらを明確にするためのテストが必要だ。
ECサイトを運営するあなたのサイトには検索結果が 10 件,リストとして表示されることになっている。もしこの中でできるだけ高い商品を買ってもらいたいと思うなら,良いアンカーとなりうる商品を一番上に持って来る戦略は有効そうだ。
なぜなら,確かに購入という選択のもとでは単純な「最上位」効果は成立しえないだろうが,一番上の商品を最初に見ることによるアンカリング効果は少なからずあるはずだからである。良いアンカーを見つけるためのテストが必要だ。
情報の鮮明さがもたらす説得力
メアリー・ウィルソンは,論文「Information competition and vividness effects in on-line judgmentsInformation competition and vividness effects in on-line judgments」において情報の鮮明さの影響力の有意性を証明した。
陪審員役となった2グループの参加者は,被害者の最終弁論を収録したビデオを見さされる。ただしビデオはグループ間で弁護の鮮明さが異なっている。
グループA:被害者を弁護する議論が10の鮮明な主張とともに収録されたもの
グループB:同じ10の主張があまりぱっとしない論調で弁護しているもの
この実験では前者の説得には後者の2倍が有り,請求した賠償金額も異なるものであった。この研究に基づくならば,サイトのあらゆる場所の説明文をより具体的に魅力的に表現することは,ユーザーへの印象を高める効果があるということなので,テストする価値があるのかもしれない。
( こちらもおすすめ: Beyond the Obvious: Chronic Vividness of Imagery and the Use of Information in Decition Making )
人に選択してもらう事の有効性
選択肢というものは多くの場合,自分が握っていることに安心感を持つ。しかし,時として他人に「選択してもらう」事の方が良い効果をもたらす場合がある。
この状況に遭遇するもっとも身近なケースは自信の「アバターの選択」である。各パーツ20以上もある選択肢の中から自分を的確に表現してくれるパーツを何度も選ぶことに少なからず負担を感じる人はいるだろう。かといって自分の分身を安易に選択できない。
実際,チュートリアルにおいてこのアバター選択における離脱率は他のステップよりも遙かに高い(もちろん選択肢の多さなど他の要因もあるだろうが)ケースが多い。しかしながら彼女や友人といった他人に選んでもらった場合には,自分に良く似たアバターをすんなりと選んでくれ,かつ満足度の高い結果になることもありうる。
「他人に選択してもらう」というシステムを作るのは必ずしも容易ではないが,それは,そのアクションにおける離脱率を有意に下げることができる可能性を含んでいるのかもしれない。