RでGoogle Analtyics: 時間帯別グラフ

Rという統計用?言語でData Export Apiを使うscriptを書きました(コードはこちら)

(2010/12/10 追記 )どうやら googleの中の人も R用のライブラリーを出したみたいです。テストもついてるし、サンプル誤差もついてくるので、僕自身もあっちを使うつもり。account系のデータ、ゴールとかも取れるといいなと思う

統計用言語なのですが、グラフ出力も充実しており、latticeというパッケージを使うと分類した上でのグラフ表示が一行でだせます(マニュアル見る時間がかかるけど)。なので、グラフを図示していきます。

下のような感じでデータを取得します。

#認証tokenを取得
auth <- getAuth(email, password)
#アカウント+プロファイル情報を取得
acs <- getAccounts(auth)
>str(acs)
str(ac) 'data.frame': 45 obs. of 4 variables:
$ ac.ids : chr "xxxx";,"xxxx" ...
$ ac.names: chr "名前1" ,"名前2" ...
$ pr.ids : chr "1111111","222222" ...
$ pr.names: chr "xxxx","xxxx", 

#プロファイル名で検索
> ac[grep("abc.*wiki",ac$pr.names),]
ac.ids ac.names pr.ids pr.names
10 188512 abc-analyticsさん 25.... abc-only-wiki-except-me
12 188512 abc-analyticsさん 255xxx... 

#キーワードを取得(デファルトで過去一ヶ月)
data <- getData(auth,id=2551xxxxx,metrics=c("visits"),dimensions=c("keyword"))
[1] "https://www.google.com/analytics/feeds/data?ids=ga:25513728&dimensions=ga:keyword&metrics=ga:visits&start-date=2010-09-03&end-date=2010-10-03"
[1] "visits"
[1] "(1-874)/874"
[1] 2
                                         keyword visits
14                                     (not set)    341
573 googleanalytics タイトル別のコンテンツ index     29
651                                         utma     17
851                        目標到達プロセス 画面     16
36                                     _gaq.push     15
221                         funnel visualization     14
662                                         utmz     11
853                     目標到達プロセスの放棄数      8
316                        google analytics wiki      8
30                                          _gaq      8
> str(data)
'data.frame':    874 obs. of  2 variables:
 $ keyword: chr  "(not set)" "googleanalytics タイトル別のコンテンD
[1] "visits" num 341 29 17 16

それで、時間帯別の表示をlevelplotという機能を使って表示していきたいと思います。

セッション数を時間帯と地域別で取得

data <- getData(auth,id=25513728,
+ metrics=c("visits","goal3Completions"),
+ dimensions=c("date","hour","region"),
+ start.date="2010-08-30",end.date="2010-10-03",
+ max.results=10000)
[1] "https://www.google.com/analytics/feeds/data?ids=ga:25513728&dimensions=ga:date,ga:hour,ga:region&metrics=ga:visits,ga:goal3Completions&start-date=2010-08-30&end-date=2010-10-03&max-results=10000"
[1] "visits"           "goal3Completions"
[1] "(1-10000)/1060"
[1] 5
          date hour region visits goal3Completions
702 2010-09-21   15  Tokyo     11                3
92  2010-09-01   09  Tokyo     11                2
607 2010-09-16   18  Tokyo      9                1
920 2010-09-29   15  Tokyo      8                0
608 2010-09-16   19  Tokyo      8                2
178 2010-09-03   12  Tokyo      8                0
105 2010-09-01   14  Tokyo      8                0
923 2010-09-29   16  Tokyo      7                0
520 2010-09-14   19  Tokyo      7                0
474 2010-09-13   17  Tokyo      7                2
グラフにする。
levelplot(tapply(data$visits,list(data$hour,data$date),sum),  col.regions=colorRampPalette(c("white",  "red"))(256),layout=esuln

2

週末と夜間は空白に近い。

曜日別に傾向があるかもしれない。見てみる。

wdays <- c("a日","b月","c火","d水","e木","g土”) #表示順を揃えるため

levelplot(tapply(data$visits,list(data$hour,wdays[as.numeric(strftime(data$date, "%w"))+1]),sum),  col.regions=colorRampPalette(c("white",  "red"))(256))

3

まあ、なにもない。深夜に起きる人は、木曜くらいから出始めるのか?というか、祝日補正してないせいだろう。

また、サイトによっては、キャンペーンやコンテンツ投入のタイミングが見えるかもしれない。

んじゃ、とりあえず、メディア別にして、期間を長くして平均を見てみる。

d.m <- getData(auth,21600568,metrics=c("visits"),dimensions=c("hour","date","medium"),start.date="2010-01-01",max.results=10000)

d.m.a <- d.m[d.m$medium %in% c("organic","referral","(none)"),]
> levelplot(tapply(d.m.a$visits,list(d.m.a$hour,wdays[as.numeric(strftime(d.m.a$date, "%w"))+1],d.m.a$medium),mean), col.regions=colorRampPalette(c("white",  "red"))(256),sub="曜日別|メディア別”)

4

検索活動は集中するくらいしかわからない。今年の平均だけど、、

これでも、具体的なユーザー像にはならない。

そこで、ある特定のキャンペーンを行った場合の波及効果みたいなのをみたいが、出せるデータがないので、このブログの公開記事の閲覧数の減衰具合みたいなのを見てみる。

d.m <- getData(auth,21600568,metrics=c("entrances"),dimensions=c("hour","date","landingPagePath",”medium”),start.date="2010-08-01",max.results=10000)

rev(sort(tapply(d.m$entrances,d.m$landingPagePath,sum)))[1]
 /multi-cookie-tracking                                                                  338

と一番多い、multi-cookie-tracingを見てみる。メディアタイプを、オーガニックと参照リンクに絞って表示

d.m <- getData(auth,21600568,metrics=c("entrances",”newVisits”),dimensions=c("hour","date","medium"),start.date="2010-01-01",max.results=10000) 

d.m.a <- d.m[d.m$medium %in% c("organic","referral"),]
> levelplot(tapply(d.m.a$entrances,list(d.m.a$hour,d.m.a$date, d.m.a$medium),mean), col.regions=colorRampPalette(c("white",  "red"))(256),sub="特定ページメディア別”)

5

9月1日の深夜に出して、リンク中心にアクセスが上がって、その後は検索にかかるようになる。しかし、検索に乗るのも早いものだ。

次のものは、新規に絞ってみたもの。本当に新規でないのもあるだろうけど。検索による継続的な流入はある。

d.m <- getData(auth,21600568,metrics=c("entrances",”newVisits”),dimensions=c("hour","date","medium"),start.date="2010-01-01",max.results=10000) 

d.m.a <- d.m[d.m$medium %in% c("organic","referral"),]
> levelplot(tapply(d.m.a$newVisits,list(d.m.a$hour,d.m.a$date, d.m.a$medium),mean), col.regions=colorRampPalette(c("white",  "red"))(256),sub="特定ページメディア別”)

6

あとは、、、、

会員情報などとマッチングしてるサイト(外部ソースとの照合は規約違反かも)なら、ユーザー属性別のアクセス状況などは、比較表示しやすいと思います。

検索ワードで属性を分けたり、地域と時間情報と天候情報(外部から引っ張る)で属性を仮定したりと思ったのですが、余裕ができたらやってみたいと思います。

とりたてて何か発見ができたわけではないですが、Rを使うと、こんな感じで手短にグラフ出力ができます。ただ当然ながら、学習曲線はキツイ。ここまで来るのに相当な学習時間がかかりました。データ分析ではなく、データ表示だけなのに、、、

以下コードです。RCURLとXMLが必要です。

こちらに移動しました。

マルチトラッキング(複数cookie)について考える

*2010/09/10 追記を入れました。

*2010/09/14 _linkでアドレスバーからcookieにデータを取り込む際、日本語データがある(検索ワードなど)と、うまくデータの引継ぎができないと思います。(フォーラムに質問した)。使う方は気をつけて(?)ください。chrome, firefoxの場合。IEはOK。 エンコードしてればよかった。

僕自身はあまりマルチトラッキングについて馴染みがないのですが、時々、マルチトラッキング絡みの質問を、フォームから受けるようになってきたので、いろいろと頭の中を整理しました。読んでください。

また、マルチトラッキングがニーズとなるのは、ドメインやディレクトリで分けてデータを収集したいということなので、具体例も画像付きで書きました。下の方。

全体の仕組み

大まかな前提を。 google analyticsはビーコン型のアクセス解析ツールです。gifリクエストをサーバーに飛ばして、データを収集してレポートしてくれます。モバイル計測の場合を除き、javascriptで操作します。トラッカーオブジェクトを作り、データ置き場としてのcookieを操作しつつ、gifリクエストを発行します。

同じ情報を複数アカウントに

ですので、同一情報を複数のアカウントに送りたい場合は、トラッカーオブジェクトを複数発行して、このオブジェクトにアカウント情報をそれぞれいれてやって、送信すればいいだけです。

公式サイトには英語のものしかないですが、用例があります。http://code.google.com/intl/ja/apis/analytics/docs/tracking/asyncUsageGuide.html#MultipleCommands

ただ、ドメイン別・ディレクトリ別に情報を取って、専用のプロファイルに送りたいですよね。

3つのパターン。サブドメイン、クロスドメイン、サブディレクトリの場合を見ていきます。

ただ、もう少し、講釈を続けます。

複数cookieを実現する設定

*これは、僕自身の考えに基づいて書いています。計測がうまく行かないかもしれないので、うまく行かない場合は、ダメじゃないか!と怒るか、もしくは、ぜひ連絡ください

ケース: aaa.xxx.comというサイトと、bbb.xxx.comというサイトを管理していて、この二つの横断的な情報を収集しつつ、aaa, bbb個別の情報を得たい場合です。

通常の方法としては、

_gaq.push([“_setAccount”,”UA-xxxxxx-yy”]); 
_gaq.push([“_setDomainName”,”.xxx.com”]); 
_gaq.push([“_trackPageview”]) 


という形を、aaa, bbbの両方に同じようにおけば、これで計測できるわけで何も問題ないですし、フィルターで切り分ければ情報を分けることも可能です。aaa, bbb別にアクセス情報を見られます。ただ、cookieをaaa,bbbで共有するために、サブドメイン独自でのセッション情報の管理(ユニークユーザ、新規・既存・リファラーなど)ができません。

そこで、cookieを3つ、aaa専用 bbb専用 aaa-bbb共用という形で用意して、専用の3つのプロファイルという形を用意します。

aaa.xxx.com bbb.xxx.coom
_gaq.push([“ab._setAccount”,”UA-for-aaabbb”]);

_gaq.push([“ab._setDomainName”,”.xxx.com”]);

_gaq.push([“ab.trackPageview”]);

_gaq.push([“a._setAccount”,”UA-for-aaa”]);

_gaq.push([“a._trackPageview”]);

_gaq.push([“ab._setAccount”,”UA-for-aaabbb”]);

_gaq.push([“ab._setDomainName”,”.xxx.com”]);

_gaq.push([“ab.trackPageview”]);

_gaq.push([“b._setAccount”,”UA-for-aaa”]);

_gaq.push([“b._trackPageview”]);

これで、3つのcookie(utm(a,b,c,v,z))セットができます。

このコードの説明をこれからします。

_setDomainNameの二つの機能

このsetDomainNameは、内部的に二つの働きをします。

cookieの所属ドメインの決定と、cookieの値にドメイン情報を持たせることです。

cookieの基本的な仕様は、ドメイン、パス別に指定して作成することができますが、javascriptからはドメインとパスはみえません、読む場合は見えないのです。ですので、cookieの値にドメイン情報を持たせることは意味を持ちます。(ドメインハッシュ値は他にもセキュリティ用途もあるみたいですが、よくわかりません)

s1-test-analytics.com

google-analytics-cookie

s2.test-analytics.com

WS000005

画像の文字が細かいですが、.test-analytics.com(両方に存在)と、s1.test-analytics.com, s2.etst-analytics.comの3つがあります。

左側の赤四角が、ドメイン情報を現してます。.test-analytics.comなら 113074331。s1.test-analytics.com:154559162, s2.test-analtics.com: 155607801。

と、setDomainNameは、cookieのドメインと、cookieの値の最初の10桁数字(ドメインハッシュ値)を決めています。cookieの最初の値が、ドメイン固有(ハッシュ衝突がないとして)の値ですので、この値を見て、複数cookie時に、該当cookieを判断しています。ネームスペース的な機能とでも言えばいいでしょうか?

サブドメイン+メインドメインの個別管理の実際を見てみる。

では、cookieが3つできてることは確認できたので、今度はドメイン別に機能しているかをみてみましょう。

次のようなケースを想定します。

セッション1: s1に訪問後、s2を訪問。

セッション2: s1のみ訪問

セッション3: 再度、s1のみ訪問

セッション4: s2のみ訪問(外部リンク経由(phar.awe.jp)

セッション5: s1を訪問

この場合、全体をカバーする情報は、5セッション。s1では4セッション。s2では2セッションと記録される形になって欲しいです。参照情報は、全体では(phar.awe.jp) s1はDirect, s2は(phar.awe.jp)となって欲しいです。

実際に図を見ていきます。

セッション1 s1を訪問。

WS000010

同一セッション内で、s2を訪問。 s2の参照情報は、s1.test-analytics.comに。

WS000011

セッション2に。(セッションの更新は、utmcのcookieを削除で行う) 両方のutmaのカウンタ(Valueの最後)は2に。

WS000012

セッション3 同じようにカウンタがインクリメントされ、3に。

WS000013

セッション4 phar.awe.jpから s2に遷移。全体のもの、s2のcookieが更新される(カウンタ(utma)、参照情報(utmz))

WS000014 

セッション5 s1を訪問(セッション4で、s2を訪問した情報は、test-analytcs.comの方のみ反映されている。

WS000015

と、想定通りになりました。 .test-analytics.comで全体のセッション管理を。s1,s2は個別でセッション管理されてます。s1からs2の移動も外部参照元となりますし、訪問回数は、s1,s2は個別に管理されてます。

サブドメインは、これで問題ないですね。では、クロスドメインの例を見てみましょう。少し複雑で、問題含みです。

クロスドメイン計測での、全体計測と個別ドメイン管理の実現

どこまでニーズがあるのかわかりませんが、これもみていきましょう。livedoorでは、この形で運用してるみたいですね。 あと、公式サイトのクロスドメイン計測の形です。シングルトラッキングで、前提が多少入りますが、ここらの情報は検索すればあちこちにあるのでいいと思います。

それで先程、クロスドメインがサブドメインより、少し複雑と書いたのは、cookieは他のドメインの値は読めないので、特殊なことをしてるし、サブドメイン計測とは同等の機能とはならないからです。

とりあえず、設定を考えましょう。二つのドメイン計測で、全体計測と、個別計測を実現する。

test.analytics.com phar.awe.jp
_gaq.push(“a._setAccount”,”UA-for-any”]);

_gaq.push(“a._setDomainName”,”none”]);

_gaq.push(“a._setAllowLinker”,true]);

_gaq.push(“a._trackPageview”]);

_gaq.push(“b._setAccount”,”UA-test-analytics”]);

_gaq.push(“b._trackPageview”]);

_gaq.push(“a._setAccount”,”UA-for-any”]);

_gaq.push(“a._setDomainName”,”none”]);

_gaq.push(“a._setAllowLinker”,true]);

_gaq.push(“a._trackPageview”]);

_gaq.push(“b._setAccount”,”UA-phar-awe”]);

_gaq.push(“b._trackPageview”]);

これで、この両者のドメイン間に onlick=’_gaq.push([“a._link”,this.href]);return false;’という形。

*2010/09/10 どうも、setDomainが”none”のものと、通常のものの実行順番が、上記のものと反対になると”none”で設定した方が上手く動かないように見える。バグなのかそういう仕様なのかは謎だけど、”none”を先にして、setDomainName無しをあとにした方が良いよう。もともと、クロスドメインで値を受け渡しするのは、ポリシーに反する部分もあるだろうから、異なるドメインの計測はやらない方が良いんだろう。

サブドメインでの計測では、cookieがメインドメインの元で共有され、変更が反映されてました。でも、クロスドメインはそれができません。urlのパラメータを読み込む形での受け渡しです。ですので、この受け渡しがないと、値の変更を反映できません。

とにかく、実際の図をみていきましょう。セッションを全体で3回行います。test-analyticsに2回。phar.aweに2回。またぐセッションがそのうち一回です。

最初のセッション。 参照元(utmz)は、s2.tes-analyticsからリンクを張りました。

WS000016

_gaq.push([“a._link”,this.href])でクロスドメイン遷移。細かいですが、参照元は全体では s2。個別では test-analytics.comからと別れてます。

WS000017

セッション2。test-analytics.comを訪問。カウンタ(utma)が増えただけ。

WS000018

セッション3 phar.awe.jpを訪問。サブドメイン計測ではcookieが共有されていたので、カウンタが上がっていたのだが、クロスドメインはそれがないので、全体計測の方のカウンタ(umta)が3にならず。2のまま。

WS000019

と、全体で3セッションあったのだが、全体を計測する utma(ドメインハッシュ Valueが1の方) では、

2回目の訪問が二回あって、3回目の訪問がない結果となる。また参照情報の変更も、url上のパラメータ渡しがないと、cookie値を共有する機会がないので、不整合な結果を作りやすい。

ショッピングカートのように、必ず特定のドメインからの遷移であれば問題はないでしょうが、結論としては、

クロスドメインでの全体・個別の分別管理は問題が多そうと、僕は思います。

さて、最後にもう一つトピックを取り上げます。ディレクトリでの全体・個別をマルチトラッキングで管理するです。ディレクトリの分別管理はニーズが多そうですが、固有の問題があります。

サイト全体・特定ディレクトリでの全体計測・個別計測のマルチトラッキング

実は、僕が手伝ってるサイトでも、先日これをやろうとしたのですが、うまく行かなくて悩んだのです。

cookieの値がヘンだなあと、、

実は、ドメインの違いに関しては、google analyticsのcookieがドメイン情報を持っていたので、区別できたのですが、パスの情報は入れてくれてないのです。なので、複数cookieはできません。作る事はできても、カウンタのインクリメントは、どっちをするか不定です。参照情報のutmzは一個しかできません、最初に設定したパスで出るのみです。何も指定してなけば、”/” 。これは、最初にsetCookiePathで”/DDD/”としたのでこうなりました。

WS000020

utmaは、二つ作ってはいますが、判別手段がないため、次回の更新はどちらかの値を取得して、二つとも、同じ値に更新です。実質的に、サイト全体での管理しか、しないことと同じになります。utmzを”/”で指定すればです全体ですし、utmzが”/DDD/”のみになれば、全体のセッション管理が狂います。

で、手段がないのかというと、ドメインを分けてやれば、個別管理できます。

http://www.lunametrics.com/blog/2009/03/06/cookies-tracking-multiple-accounts-ga/

@t32k さんの昔のエントリーも発見

なので、ここで細かく書いてもしょうがないので、コードだけ書いておわりにします、、、、

と思ったのですがlunameticsのコードだと、ドメイン名が同じなのでcookieが独立して動かない(ga.js側が)と思います。ドメインを分けるには、サブドメイン表記を使うか、クロスドメインの”none”を使うかだと思います。ここでは、noneを使う形の載せます、、、、

と思ったのですが、setDomainName(“none”)を使うと、セッションの更新がうまく行かない気が、、上のクロスドメイン時では問題なかったので、setCookiePathといっしょに使うと、動きがヘンになる????

なので、setDomainName(“.test-analytics.com”)とsetCookiePath(“/DDD/”)を一緒に使う形にします。

通常の場所 特定ディレクトリ(今回は/DDD/)
_gaq.push([“a._setAccount”, “UA-all”]);

_gaq.push([“a._trackPageview”]);
_gaq.push([“a._setAccount”, “UA-all”];

_gaq.push([“a._trackPageview”]);

_gaq.push([“b.setAccount”, “UA-DDD”]);

_gaq.push([“b.setDomainName”,”.test-analytics.com”]);

_gaq.push([“b.setCookiePath”, “/DDD/”]);

_gaq.push([“b.trackPageview”]);

setDomainName(“none”)で作ったcookieは、FQDN所属(leading period ‘.’なし)のcookieになるので、ほかの場面でクロスドメイン用に、”none”を使う場合は使えません。サブドメンの設定を使うしかないと思う。

実際の例

セッション3回。/DDD/index.htmlを二回。/index.htmlを一回。

セッション1: /DDD/index.htmlを訪問。

WS000024

注意: 所属Domainは双方同じ .test-analytics.comになってますが、ドメインハッシュ値は113… と115…と違います。これはデフォルトsetDomainNameなしを使うと、内部としては “test-analytcs.com”と “.”なしでドメインハッシュを計算するため。 .を付けとけば違うハッシュ値をとれる。で、今回は所属ドメインンが同じだが、パスが違うためcookieは存在できる。

セッション2: index.htmlを訪問

WS000025

セッション3 /DDD/index.htmlを訪問

WS000026

全体で3回訪問した。全体を把握する方の,115001218は、カウンタ(utma)が3になってる。個別ディレクトリ管理の113074331は、2回と想定通り。めでたし、めでたし。

まとめ

ここまで、読んでくれる人がいるか疑問です(僕なら飛ばし読みだ)が、まとめです。感想の箇条書き。

  • 複数cookieを使えば、セッション管理を独立して行えるので、ドメイン別、ディレクトリ別に具体例をcookieの値を見ながら検証しました。レポート側では検証していません。なので、落とし穴がまだあるかもしれません。
  • サブドメインの全体・個別の独立管理は、たぶん実用に応すると思います。
  • クロスドメインでの全体・個別の独立管理は、セッション単位で分析するのには問題含みな気がします。
  • ディレクトリでの全体・個別の独立管理は、トリッキーながらも、そのトリッキが使える状況の下では、きちんと数字が取れそうだと思います。
  • google analyicsの先頭のドメインハッシュ値は、ネームスペース的役割を果たします。キー(名前)が一緒でも、こちらで同一名cookieの判別を可能にします。
  • ディレクトリ情報は、ドメインハッシュ値に含まれてないので、別ドメインのcookieを用意して、cookieの分別管理を可能にできます。
  • setDomainNameの役割、cookieの所属ドメイン、ドメインハッシュ値の作成の二つの機能を頭にいれておく。参考に、前にwikiに書いたものへのリンク

訪問回数別セッション数(vs 参照元)の残存率を見る

リファラー情報の扱いは、他のアクセス解析ツールと違う仕様

Google Analyticsの、他のサービスと違う有名な仕様として、外部リファラーが無い場合のリピーターのリファラー情報は、前回のリファラー情報とするというのがあります。

直接訪問は前回のリファラー情報でレポートとして上がるという事です。最初からノーリファラーなら、ノーリファラーですが。

僕は、他のアクセス解析サービスはよく知らないので、どちらが有用なデータ表示方法かは分からないのですが、GAの仕様を決定した人は、こっちが良いと思ってそうしたんだと思います。

この方法で良いなと思える点

本当は、ユーザー単位で、トラフィック情報の変遷を見ることが出来れば、万事解決なのですが、GAは大きな会社のサービスなので、いろんな事に配慮しなければならず、ユーザー単位のトラフィック情報を見ることはできません。ユーザーグループを作って、カスタム変数に記録すれば、グループ単位では見られるようになりますが、それは置いておきます。

それで良い点はというと、直接訪問を必ず、どこかの参照元の情報に帰属させてる点です。アクセス解析の目的は、コンバージョンの向上にあるわけで、その要因となる流入元情報の寄与を割り振ってるわけです。2,3回目は、bookmarkから来たんだろうけど、一回目は、、、というデータ処理を省くことができるわけです。

もちろん、リピーターは、複数の外部サイトからやってることも多いわけで、その場合は上書きされていくので、きちんとした?データにはならないわけですが。

参照元別の残存率 = コア化するユーザー率を見る

訪問回数と参照元情報をディメンジョンに、セッション数を指標にします。

  visits_against_visit_count

データは、仮想の数字です。サイトの数字を参考にして、乱数を降った擬似的なデータです。 縦軸(Y軸)は、10の対数です。4なら1万。2なら100。 2,3回目までくるのは、1%とかの世界ですね。1以下で10以下です。

あと、データ集計期間の長さによってデータが偏るので、そこも注意した方が良いです。その集計期間の訪問回数というのは、Google Analyticsでは出せないです。出る数字は、全ての測定期間で、何回目の訪問だったかです。

参照元別で残存率が違う場合、主要な参照元の5回目残存率なんかは、気にしても良いかもしれません。この場合だと、Eなんかは2.8(630くらい)から1.8(63くらい)くらいと、10%くらいは残ってくれてます。ほかは、Dなんかは、5回目で、3(1000以上)から1以下(10)になります。

最終的には、コンバージョン率と絡めて、数字を吟味する必要はあるのですが、参照元によって残存率が違う、訪問回数が進むにつれ、1/10, 1/100になっていくけど、参照元に依っては生き残る率が高いのがあるのを気にするのもいいかもしれません。

Google Analyticsのノーリファラーを前回のリファーラー情報に割り振る仕様も、こういう見方をする場合は、データ処理が楽だと思います。

もちろん、あるユーザーの二回目セッションは参照元がAで、三回目はBという事もあるので、訪問回数の残存= ユーザーの残存率 とはならないですが、ある程度は類似するはずです。また、このデータ集計期間に、一回目が入らずに二回目から登場のパターンもありえます。GAは、ある期間内で、何回目の訪問だったかは教えてくれません。

ということで、参照元別に訪問回数別のセッション数を見て、この参照元はコアのユーザーに成ってくれやすい。 裏を言えばリピートしない、というのを把握する話でした。

実はどこかのサイトのデータ整理をしてて、対数グラフにしたら、それなりに見えたので、blogを書きました。 底を求める方法が分からず、何回か検索した。中学生の僕が見たら、僕を殴りに来たかも、、、630 => 10^2.8 は、頭に出なかった、、、

ページ遷移レポートの自動配信を実現する

前回、スクロール計測のレポートを自動配信する話を書いたのですが、今回は、Google Analtyicsのページ遷移データをグラフ化してメール配信する話です。

同じく、google apps script + google chart api でのメールによるレポート配信です。

AuthSubでの作成も作りました。試してみてください。

Google Analyticsにおけるページ遷移のデータ

あるページにおける、遷移上の前後のページは、WEBのレポート画面で見ることができます。ナビゲーションサマリーですね。ナビゲーションサマリーの数字の見方は、以前Wikiの方に書きました。

WEB上のレポート画面では、重複ページの回数を抜いて、パーセンテージにして表示してます。(移動先のデータ(nextPage)のデータがよく分かってないのですが、、)

今回は、Data Export APIでデータを持ってくるので、重複ページを抜かないとと思っていたら、uniquePageviewの数字がそのままの数字なので、端折って、uniquePageviewの数字を使いました。uniquePageviewを使う妥当性について、Forumなどで質問があったみたいですが、数値を見る分には大丈夫そうなので、uniquePageviewを使います。単に重複を抜くためだけですが。(もう少し考えてみた。けっこう注意が必要かも)

とにかく、ディメンジョンに, “priviousPagepath”と”nextPagePath”。指標に uniquePageviewを使います。

Google Chart APIの GraphViz Chart

前回のデータを表示する時に、chart apiの文書を見てたら、おもしろいチャートの種類を見つけました。 Connectivity graphsとかいてあります。日本語だと 連結グラフ?

これも、パラメータを指定するだけで、グラフをimageにして返してくれます。またしても、パラメータの設定が難しかったのですが、PDFの説明書みたいなのを見ながら設定してみました。微妙に chart apiでの記述と、h本家の記述と違う部分もあると思います。subGraphも設定できるみたいで、それでクラスター表示みたいなのをしようと思ったけど、Google Chart Api側で、動くように設定する方法がわかりませんでした。(* google chart apiでの方法を知っていたら教えてください。)

前回も書きましたが、http://code.google.com/apis/chart/docs/chart_playground.htmlでできるチャート図を確認しながら、設定をいじれるので、便利です。

とりあえずの例

それで、実際にこのサイトのデータで生成してみました。メールレポートの場合は、google apps scriptでHTMLメールを使って、scriptの自動実行時間を指定すれば良いです。参考に、ちょっと違うけど、フォーム受付けを自動返信する話です。今回は、これを時間指定にするだけです。

できたimage画像です。 (画像クリックでできたURLそのものに遷移します)

閲覧開始数のベスト8ページのデータと、ページ遷移の組み合わせで数が多かったベスト10のデータを抜き出してます。頭に数字があるのは、そのページの期間内の閲覧開始数です。矢印線上にある数字がページ遷移の数です。 数字だけの奴(_108_)は、indexページです。閲覧開始数が108でした。

(自分自身に返ってる奴は、データの初期段階でパラメータが違うものをカットしたせいです。処理が粗いです。説明もゴニョゴニョですが、、)

サイトオーバーレイもいいですが、サイト全体のユーザーの動きはコチラのほうがイメージし易いと思います。

気を付ける点としては、上のリンク先の記事でも説明してるのですが、セッションベースのデータでないので、遷移の数は、ランディングからすぐに遷移した数ではないです。 secondPagePathもデータとしてはあるので、そちらでもグラフはかけそうではあるのですが、、、

あと、chart apiで生成できるピクセル数の大きさは、縦×横で、300000pxまでなのですが、このgraphVizでできるデータはそれを超えてます、、、、また、これはexperimentのマークがついてるので、仕様変更の可能性もありそうではあります。

それでも、自動化できたので、データを見せていただける方には、メールで日次配信します(コメントで遷移図希望と書いて下さい)。今回のは、Google Analtyisの初期設定で取れるデータなので、閲覧権限をもらえれば、それでOKです。 Auth認証でのデータ表示に対応するのは、詳しい人なら簡単にできそうなので、そういう人に任せます。

google apps scriptと chart apiを使ったレポート自動化

今回は、アクセス解析の話ではないのですが、データとして GAを使ったので、ここに書きます。

前回、スクロール率をgoogle analyticsで計測した話を書きました。 レポート部分は、エクセルでの表示だったんですが、今回、自動化のひとつの方法として、タイトルの方法をやったので、報告します。

Google Apps Script(GAS)は、かなりの便利ツール

データを外部から引っ張ってきて、加工して、メール配信というのが、割合簡単にできます。

今回は、google analyticsのデータを引っ張って、加工して、HTMLメールで配信という形の紹介です。

GASの記述は、javascriptです。 google analyticsの集計の設定も javascriptですので、 javascriptは習得しがいのある技術かもしれません。

手順としては、URLFetchで google analytics Data Export  Api からデータを取得して、それを google chart apiを使って、 HTMLメールで送る作業です。

Google Chart APIも、自動化ツールとして価値大。

URLを指定すれば、チャート画像を返してくれます。

ですので、変化する数字を自動的にグラフ化してレポーティングしたい場合に価値が高いです。

パラメータがたくさんあって、マニュアル(解説)が英語なのでとっつきにくいですが、データ、チャートタイプ、ラベル、軸、などの概念とapiでのパラメータが一致すれば、それなりに使えるのではと思ってます。

別サイトにメモみたいなのを書きましたが、、、あまり参考にならないかも。

GMailの問題?

いろいろいじって、なんとか自動化にこぎつけたのですが、GmailのHTML表示の時に、imageタグの部分が上手く表示されなくて、いろいろ探したのですが、結局あきらめました。 たぶん、文字数の問題のような気がしてるのですが、、、どうなんでしょう。 Yahoo Japanの Web mailなら問題なかったです。

出力画像と スクリプトを貼りつけます。

スクロール計測とそのレポート配信を試してみたい方は連絡下さい(コメントでスクロール計測希望と書いてくだい)。 設定して、週次 or 日次で、特定のディメンジョンで切ったスクロール率のよる閲覧割合をメールレポーティングします。無料です。 以下の画像のような形でのHTMLメールが送られます。

画像レポートの後に、参考に、GASのスクリプトを貼りつけておきます。 貼り付けた以外にも追加の定義(関数、代入式)などがあるので、全部ではないです。

2010-06-03から2010-06-15のセッション数上位3ページの精読率調査です。数字はセッション数です。

以下、レポート配信に使ったscriptの一部。

function CRReport(id,name,title,address){
    //id = "ga:21600568", name="shirai", title="wordpress", address="kimiyuki[at?]gmail.com";
    var startdate; var enddate; var dimensions = []; var metrics = []; var filters = ""; var segments = "";
    var entries; var sort;var data;
    var tmp;
    var siteurl;
    startdate = getMyDate(-15); enddate = getMyDate(-3);
    dimensions = ["ga:pagePath,ga:hostname"]; metrics=["ga:visits"]; sort=["-ga:visits"];
    entries =  getDataFromApi(id, startdate, enddate,dimensions, metrics, filters, segments, sort);
    pagePaths = [];
    entries.slice(0,3).forEach(function(entry){
        var el = entry.getElements("http://schemas.google.com/analytics/2009", "dimension");
        el.forEach(function(e){
            if(e.getAttribute("name").getValue() == "ga:pagePath") pagePaths.push(e.getAttribute("value").getValue());
            if(!siteurl && e.getAttribute("name").getValue() == "ga:hostname") siteurl = e.getAttribute("value").getValue();
        });
    });             
    
    data = {};
    var w1 = [null,null, null]; var w2 = [];
    pagePaths.forEach(function(path){
        Utilities.sleep(500);
        w1 = [null,null,null], w2=[];
        var dim_sg = "ga:medium";
        dimensions = ["ga:eventCategory", "ga:eventAction", "ga:pagePath",dim_sg]; metrics = ["ga:uniqueEvents"]; sort = null;
        filters="ga:eventCategory==CompRead0523B;ga:pagePath==" + path;
        segments=null;
        entries = getDataFromApi(id, startdate, enddate, dimensions, metrics, filters, segments, sort);
        entries.forEach(function(entry){
            var ds = entry.getElements("http://schemas.google.com/analytics/2009", "dimension");
            var es = entry.getElements("http://schemas.google.com/analytics/2009", "metric");
            var w = new Array();
            ds.forEach(function(e){
                if(e.getAttribute("name").getValue()=="ga:eventAction") w1[1] = parseInt(e.getAttribute("value").getValue().replace("z",""));
                if(e.getAttribute("name").getValue()== dim_sg){w1[0] = e.getAttribute("value").getValue();}
            });
            es.forEach(function(e){
                if(e.getAttribute("name").getValue() == "ga:uniqueEvents") w1[2] = parseInt(e.getAttribute("value").getValue());
            });
            w2.push([w1[0], w1[1],w1[2]]); //値にして設定するため
            w1 = [null,null, null];
        });
        w2 = w2.sort(function(a,b){return a[1] > b[1]});
        if(data[path] == null) data[path] = [];
        data[path] = w2.map(function(x){return x});
        //data[path] = w2.map(function(e){return [e[0], Math.floor((e[1]/total)*100)]});
    });
    // Logger.log(data);
    html = outputChart(data, startdate, enddate, siteurl);
    Logger.log(html);
    MailApp.sendEmail(address, "CompRead","html mail", {cc: "kimiyuki[aat]gmail.com", htmlBody: html});
}


function outputChart(data, startdate, enddate ,siteurl){
    var html = "
" + startdate + "から" + enddate + "のセッション数上位3ページの精読率調査です。数字はセッション数です。
"; for(e in data){ //Logger.log(e); //Logger.log(data[e] instanceof Array); //Logger.log(data[e].length); //Logger.log(data[e].toString()); //making dimentionable data var dimmed_data = data[e].reduce(function(r, x){ if(r[x[0]] == null){ r[x[0]] = x[2]; }else{ r[x[0]] += x[2]; } return r; }, {}); //Logger.log(dimmed_data.toSource()); var tmp = []; Logger.log("object="); Logger.log(dimmed_data.toSource() + "n"); for(c in dimmed_data){tmp.push(])}; dimmed_data = tmp.sort(function(a,b){ return a[1] < b[1]}); Logger.log("dimmed_data="); Logger.log(dimmed_data.toString()+"n"); var label = data[e].map(function(x){return x[1]}).unique(); var data1 = data[e].filter(function(x){return x[0] == dimmed_data[0][0]}).map(function(x){ return x[2]}); var data2 = data[e].filter(function(x){return x[0] == dimmed_data[1][0]}).map(function(x){ return x[2]}); var data3 = dimmed_data.length < 3 ? "" : data[e].filter(function(x){return x[0] == dimmed_data[2][0]}).map(function(x){return x[2]}); //Logger.log(label); //Logger.log(data1); //Logger.log(data2); //html += "" + e + "
" + data[e].map(function(x){return x[0] + '=>' + x[1]}).join(',') + ""; html += "
"; html += makeChart(label, data1, data2,data3, dimmed_data[0][0], dimmed_data[1][0], (dimmed_data.length > 2 ? dimmed_data[2][0] : "")); html += "
"; html += "" + e + "
"; html += "
  
" //全角空白を入れた。間隔を作るため } html += "
"; return html; } function makeChart(label, data1, data2, data3, dataLabel1, dataLabel2, dataLabel3){ var max = data1.concat(data2).reduce(function(r, e){return r > e ? r : e;}, 10); var chds = "chds=" + "0," + max; var chxr = "chxr=1,0," + max; var chco = "chco=4d89f9,c6d9fd" + (data3 != "" ? ",63C6DE" : ""); var chdl = "chdl=" + dataLabel1 + "|" + dataLabel2 + (dataLabel3 != "" ? "|"+dataLabel3 : ""); var chm = "chm=N,000000,0,,12,0,e|N,00FFFF,1,,12,0,e" + (data3 != "" ? "|N,0000FF,2,,12,0,e" : ""); var url = ""; //Logger.log(url); return url //.replace("&", "&"); }

ページのどこまで読まれたかを計測する

ウェブサイトのコンテンツをページングするのはユーザビリティを損なう事が多いと僕は思ってます。ユーザビリティの定義は知りませんが、読むこと以外に”意識”を取られると嫌な感じがします。 提供側の論理は知りません。ユーザビリティですから。

次のページへのリンクをクリックという行為は、

  1. そのアンカーテキストに目の焦点を併せる
  2. マウスを叩く
  3. リンク先のページがloadされる。

という順番で進むと思います。

速読の練習をした人はよく分かると思いますが、1の行為は、文字を探し・焦点を合わせるという、非常にコストのかかる行為です。読むという作業においては。。文脈を追う作業は超短期記憶のつなぎ合わせで、意識のallocation作業は天敵です。

一方で、アクセス数字を見たい人に取っては、ページ単位の計測が基本である以上、ページとコンテンツの粒度は一致してる方がいいと思ったりします。<h2> <h3>といった見出し単位での閲覧率を知りたいと思ったりすると思います。閲覧時間の方が知りたいかも、、、 とにかく、ページ閲覧量と滞在時間ではなくて、コンテンツ消費量とコンテンツ消化速度を知りたいとか思うと思います。

ヒートマップ使ったり、細かく計測タグを作れば、データは得られそうですが、面倒です。

で、とりあえずの一歩として、ページ全体でどの割合までページが表示されたかを、google analyticsで計測してみたので、その経過を書きます。

EventTrackで、表示領域割合をアクションとして送る。

当初、表示割合を計測するのに カスタム変数のページスコープ変数を使えばいいのかと思いました。上手く説明できないのですが、ページスコープは使いにくい機能(*)なので、前に使った手法(ページ別閲覧時間分布の作成)と同じような手法のtrackEventを利用する方法でやりました。

* ページスコープのカスタム変数を設定してtrackPageviewで送ったら、それは新規のページビューになってしまう。動的な行動記録をアトヅケで送れない。

それで、方針としは、

  1. 一秒毎に、画面の表示位置(割合)を取得。
  2. それが、そのページ閲覧中で最大値を超えていたら、trackEventする。
  3. 10%単位で区切る。google analyticsでは集計値しか取れないので、値は積み上げで送る。
    • 30%まで閲覧されたというデータを送る場合には、0, 10, 20, 30 と送る。
    • なんとなくだけど、データの連続送信制限があった気がしたので、少しsleepを入れておく。
    • このサイトのrs.jsという奴です。データを送る順番をコントロールするために、jsdeferred.jquery.js をいれました。このサイトの説明を参考にした

データを見る : totalEventsとpageviews

eventの数字を見るときは、totalEvents(イベント数)と uniqueEvents(ユニークイベント数)の二つを見ますが、uniqueEventは、セッション内の同一カテゴリ・アクション・ラベルを一つ(distinct)にします。

image

自作のDataViewerで見たところ。labelにページURL(path)を入れていたのですが、ディメンジョンとして pathPathも有効なので、labelは他の用途に振り向けてもいいかもしれません。

ちなみに、ABテスト別に見たい時は、カスタム変数を出してフィルタリングします。

ab_test_for_how_much_viewed_againt_content

ちなみにこの自作ツール、チョコチョコ改良してます。、カスタムレポートを組むより、操作時間は短いはずです。 日別のデータ作成には便利です。 GAのレポート画面だと、日別のデータをグラフにしてくれますが、数字で出すには、カスタムレポート組まないといけない。

レポート化

アクセス解析サミットで清水さんの講演を見て、スクロール計測のレポートの形式を真似ました。

image

画像にパーセントで線を入れるのにbookmarkletを実行、画像を撮って、エクセルでrept関数。

javascript:hg=document.height;wd=document.width;for(var i=1; i<10; i++){dv=document.createElement("div");dv.innerHTML= "<hr style=’color:#f00; background-color:#f00; height:5px;’/><strong>"+(i*10).toString()+"Percent==></strong>";dv.style.position="absolute";dv.style.top=parseInt((i/10)*hg).toString()+"px";dv.style.left="0";dv.style.width=wd+"px";dv.style.zIndex="1000";document.body.appendChild(dv.cloneNode(true));}

このbookmarkletは適当に作ったもの。 ページ全体画像撮りは、このchromeのextensionを使った

このレポートを自動化するには、

bookmarklet実行 + 画像収集 + データ抽出 + どこかで画像オブジェクトにする

という作業が必要。

Google Analtyicsで、trackEventを使って、ページのスクロールの割合を見て、レポートにするまで、でした。 アクションは知らない。

Windows版 の Data Feed Query Explorer

これは、昔作ったGAのデータ抽出ツールで、新しくつくりなおしたものは、
自作ツールの紹介になります。こちらをお使い下さい(あと、windows xpだと動かないかも、、、)

Data-Feeds-Query-Explorer-in-windows-application

Google Analyticsの Data Export APIからデータを引っ張るソフトを作った。

Visual Studio 2008 express editionのPublish機能を使って、パッケージ化した。.Net Framework 3.1 SP が必要。ただ、SetUp中にDownloadされるはず。

作った動機

1. なぜか、web上の Data Feed Query Explorer で、日本語が文字化けするようになった。 フォーラムに投稿したけど、英語力の問題もあって、上手くasset出来なかった

2. .NETの ライブラリーが更新されたのとのニュースがあった。

ので、今まで、ruby や pythonapps script で やってたけど、GUIで使えるソフトにも挑戦しようとして、やってみた。 ちなみに、windowsソフト( visual Studioを使って作る)のは、ほぼ初めてなので、UI、機能、エラー処理とかは、プリミティブです。検索や2chなどを見ながら、コピペなどをしながら作ったものです。

出来ないこと

Data Feeds の方のデータを引っ張ってこれるようにしただけです。 Account Feedsの方は、profileを引っ張れるだけです。本当は、Account Feedsの方で、ゴールの設定やら カスタム変数、アドバンスセグメントの設定などが、引っ張れるれのですが、やってません。

できる事は、profileIDを指定して、そのprofileのデータを取得するだけです。 用途としては、データをコピーして、エクセルに貼り付けるといいと思います。(unicodeテキストの貼付けを選ぶと文字化けしないはずです)

注意

Data Export APIの制限に注意して下さい。たくさん使うと制限に引っかかるようです。

あと、Dimensionは7つ、Metricsは10が一度に取れる上限項目数です。また、Dimension, Metircsの組み合わせで、データ取得不可のものがあります。これらの場合は、このソフトの上のテキストボックスにある、Error Messageに、そのようなメーセージが出るはずです。

僕の事を悪意を持ってない人だと信頼できて、ソフトの不出来を許容できる方に使ってもらうのが望ましいです。ただ、いろいろ感想を言ってもらえれば、改善へのモチベーションになるので、なにかあれば、@phar までおっしゃって下さい。

使い方

メールアドレスとパスワードを入れて、GetProfiles ボタンを押すと、自分の管理・閲覧できるprofilesがでます。

その後で、データが欲しいProfileのIDをクリックして、選択した状態にして、getDataを押すと、データ取得です。 下の GridDataViewという所にデータが出力されます。 後は、全選択してコピーして、エクセルで、形式を選択して貼付け- unicodeテキストでの貼付け を選ぶと、日本語の問題なくペーストできると思います。

あと、記録するにcheckを入れると、メールアドレスとパスワードを保存します。逆に、空欄にしてからcheckを入れれば、以前に記憶されたものが、空白で上書き(消去)されます。

実際に使っているキャプチャーは、wikiの方に上げるつもりです。