↓Menu

Splitting the page for mobile: page #1 | #.Next

January 11, 2011

plyrで集計 ggplot2でグラフ化

shirai ^2:47 am

Table of Contents

  • 複数の指標を時系列で並べる
  • 期間効果(曜日)を考慮する
  • 分布を見る。滞在時間分布(セグメントデータとして)を見る
  • キーワード + ランディングページ別のセッション滞在時間
  • Rを使ったアクセスデータの集計(1)

    plyrとggplotを使ってます。
    (*)Rを勉強し始めたら、早めにplyrとggplot2を覚えるのが吉。
    見通しがよくなると思います。アクセス数値の集計というより、Rの勉強エントリ。

    複数の指標を時系列で並べる

    アクセスの基本的な数値を集計して、同じ時間軸で並べます。
    以下のものを図示します。まず下準備。認証まで

    コード(認証)

    #RGoogleAnalyticsをファイル内にダウンロードしておいて使う。
    source("/home/shirai/ga/r/RGoogleAnalytics/R/RGoogleAnalytics.R")
    source("/home/shirai/ga/r/RGoogleAnalytics/R/QueryBuilder.R")
    
    #今回の目的のggplot2、同時に plyrとreshapeもloadされる。
    library(ggplot2)
    
    #オブジェクト的な使い方? dataframeの要素に関数がある
    ga <- RGoogleAnalytics()
    #mail, pwを自分の設定ファイルから取得する
    ac <- read.csv("/home/shirai/.gacc.csv",header=T,stringsAsFactors = F)[1,]
    #認証を通す
    ga$SetCredential(ac$mail,ac$pw)

    コード(クエリー、集計、グラフ化)

    クエリーを組み立てて、データ集計、グラフ化まで

    #queryオブジェクトを作ってリクエストを作る。ビルドパターンって奴?
    query <- QueryBuilder()
    id <- "ga:21600568"
    start.date = "2010-01-01"; end.date = "2010-12-30"
    query$Init(start.date=start.date, end.date = end.date, table.id = id,
              dimensions = c("ga:date"),
              metrics = c("ga:visits,ga:pageviews,ga:timeOnSite"))
    
    #データ取得 $dataにデータが、それ以外にはレコード数とかもある
    output <- ga$GetReportData(query)
    data.b <- output$data
    
    #使い易いように、カラム名を加工、日付データは日付型に
    names(data.b) <- sub("ga:","",names(data.b))
    data.b$date <- as.Date(data.b$date, "%Y%m%d")
    
    #滞在時間は平均滞在時間に、pageviewは平均PVへ、いるものだけ残す
    data.b <- transform(data.b, avStay = (timeOnSite/visits))
    data.b <- transform(data.b, avPV = (pageviews/visits))
    data.b <- data.b[, c("date","visits","avStay","avPV")]
    
    #ずるして、avPVは3000(5分)以上はNAに。 異常値なので
    data.b$avStay <- ifelse(data.b$avStay > 1800, NA, data.b$avStay)
    
    #パッケージのreshape機能。いわゆる?行持ちのデータ(日付 x データ種類 x 数値)に
    data.b.molten <- melt(data.b, id="date")
    head(data.b.molten) #ちょっと出力
    #|       date | variable | value |
    #| 2010-01-01 | visits   |     9 |
    #| 2010-01-02 | visits   |     7 |
    #| 2010-01-03 | visits   |     9 |
    #| 2010-01-04 | visits   |    20 |
    #| 2010-01-05 | visits   |    32 |
    #| 2010-01-06 | visits   |    18 |
    #
    #ggplotで出力(x軸にdate,y軸にvalue:数値,
    p <- qplot(date, value, data=data.b.molten, geom="line", main = "基本数値")
    
    #ここで、グループ別に図示する機能 facet_gridを使う, 縦軸スケールは個別で
    p <- p + facet_grid(variable ~ ., scale="free_y")
    
    #見た目を調整して、ファイルに出力
    p <- p + opts(axis.text.x = theme_text(size=5))
    p <- p + opts(strip.text.x = theme_text(size=5))
    p <- p + scale_x_date(major="1 month", format="%m月")
    ggsave("basic.png", height=6, width=6, dpi=96)

    結果

    ぎざぎざ。データの把握がしにくいですね。

    http://abc-analytics.com/wp-content/uploads/2011/01/wpid-basic.png

    対策としては、週別のデータにすればいいけど、それだと一日の変動の様子が消えてしまう。下で移動平均を考えることによって、曜日変動の除去を考えるけど、ページ別のセッション数も見ておく。

    ページ別セッション数の累計表示

    • 全ソースでのページ別
      query$Init(start.date=start.date, end.date = end.date, table.id = id,
                 dimensions = c("ga:date,ga:pagePath"),
                 metrics = c("ga:uniquePageviews"),
                 max.results = 10000,
                 start.index = 1
                 )
      ret <- ga$GetReportData(query,max.rows=50000)
      pv.data <- ret$data
      names(pv.data) <- sub("ga:","",names(pv.data))
      pv.data$date <- as.Date(pv.data$date, "%Y%m%d")
      ret <- ddply(pv.data, .(pagePath), summarise, pagesum = sum(uniquePageviews))
      top5.urls <- ret[rev(order(ret[,"pagesum"]))[1:5],1]
      pv.data.top5 <- subset(pv.data, pagePath %in% top5.urls)


      上位5ページを表示

      p <- qplot(date, uniquePageviews, data=pv.data.top5, geom="line", log="y")
      p <- p + facet_grid(pagePath~., labeller = function(l,x)substr(x,0,30),scales='free_y')
      p + opts(strip.text.y = theme_text(angle=0)) + scale_x_date(major="1 month", format="%m")
      ggsave("visits.png", height=5, width=6,dpi=96)

      http://abc-analytics.com/wp-content/uploads/2011/01/wpid-visits.png

      累計で表示してみる

      pv.data.top5.cumsum <- ddply(pv.data.top5, .(pagePath), transform, cumsum = cumsum(uniquePageviews))
      p2 <- ggplot(data=pv.data.top5.cumsum, aes(date,cumsum,color=pagePath)) + geomline()
      p2 + opts(legend.position="bottom") + scalexdate(major="1 month", format="%m")
      p2 + opts(legend.position="bottom", legend.box="vertical")
      ggsave("cumsumvisits.png", height=5, width=6, dpi=96)
      

      http://abc-analytics.com/wp-content/uploads/2011/01/wpid-cumsum_visits.png

      積み上げのが比較しやすいのかも
      10月過ぎから勢いがついたページがある。

    • ソース別(yahoo,google)で見てみる。yahooとgoogleのセッション数を見てみる
      query$start.index(1)
      query$dimensions("ga:data,ga:pagePath,ga:source")
      ret <- ga$GetReportData(query,max.rows=50000)
      pv.data <- ret$data
      names(pv.data) <- sub("ga:","",names(pv.data))
      pv.data$date <- as.Date(pv.data$date, "%Y%m%d")
      pv.data.top5 <- subset(pv.data, pagePath %in% top5.urls)
      pv.data.top5.yg <- subset(pv.data.top5, source %in% c("yahoo","google"))
      pv.data.top5.yg.cumsum <- ddply(pv.data.top5.yg, .(pagePath), transform, cumsum = cumsum(uniquePageviews))
      p2 <- ggplot(data=pv.data.top5.cumsum, aes(date,cumsum,color=source)) + geom_line()
      p2 + facet_grid(pagePath~.,scale="free_y",labeller=function(l,x)substr(x,1,20)) + opts(strip.text.y = theme_text(angle=0))
      ggsave("upv_yg.png", width=5,height=5,dpi=96)

      http://abc-analytics.com/wp-content/uploads/2011/01/wpid-upv_yg.png

      あんまり関係なさそう。あとyahooから来るのは一ヶ月遅い(かった)。

    期間効果(曜日)を考慮する

    考え方

    曜日効果を考慮することによって、日別の変動を捉えつつ、ギザギザ問題の解消を目指します。Rのdocompose関数を使って、曜日効果とトレンドを分離します。

    基本のアイデアは、観測値を (季節分+トレンド+誤差) と考えて、7日間の移動平均をとれば、曜日効果はキャンセルアウトされる。
    んで、誤差もキャンセルアウトとまずは考える。なので、移動平均はトレンドの値と考えられる。曜日効果分は、曜日ごとの平均を出して、全体の平均から引いて出す。
    で、実測値から、トレンドと曜日分を引いたのが誤差分。

    こんな考えらしい。細かくは曜日分や誤差分にトレンドを入れたりするみたいだけど、decompose関数は普通にそのまんまみたい。で、decompose関数でいきます。

    まずはセッション数。

    • コード
      #前のデータをそのままで visitsのdecomposeする。tsオブジェクトにする
      #曜日効果なので、7日間を指定,日付に関しては無視
      visits.c <- ts(data.b$visits, freq=7)
      #decompose関数はそのまんま、入れるだけ
      visits.d <- decompose(visits.c)
      #ggplotで出力するので、data.frameに戻す
      visits.d1 <- as.data.frame(visits.d[c(2,1,3)])
      #NAが初めと終わりに3日づつでるので、除去
      visits.d2 <- visits.d1[c(-1,-2,-3,-362,-363,-364),]
      #日付を再代入
      visits.d2$date <- seq(as.Date("2010-01-04"),as.Date("2010-12-27"),by=1)
      #元データと合体して、列順を入れ替え
      visits.d2$observe <- data.b$visits[c(-1,-2,-3,-362,-363,-364)]
      visits.d2 <- visits.d2[, c(5,1,2,3,4)]
      #meltさせて行持ちにして、グラフ
      p <- qplot(date,value, data = melt.data.frame(visits.d2, id.vars="date"), geom="line")
      p + facet_grid(variable~., scales='free_y')
      ggsave("decompose.png", width=6, height=6, dpi=96)
    • 結果上から 実測値、トレンド、曜日効果分、誤差分http://abc-analytics.com/wp-content/uploads/2011/01/wpid-decompose.pngセッション数の曜日別差異(合計は 0 )
      9.7 14.3 16.7 15.4 11.9 -32.8 -35.2 0.

      とりあえず、トレンドは見える感じです。
      週刊平均値をプロットするよりは、ダイナミック。日別よりは見やすい。

    平均滞在時間も曜日効果を見る

    エンゲージメントの測定として、滞在時間を対象にします

    • 注意GAはeventTrackの値も滞在時間のログとしてみてます。
      なので、eventTrackを細かく発行してると、通常よりは細かく滞在時間がでます。
      ただ、それでもこのサイトのeventTrackeの発行タイミングも等時間隔で出てるわけではないし、
      非常に怪しいデータではあります。
    • コード
      library(stringr)
      query$Init(start.date=start.date, end.date = end.date, table.id = id,
      dimensions = c("ga:date"),
      metrics = c("ga:visits,ga:pageviews,ga:timeOnSite"))
      d1 <- ga$GetReportData(query)
      d2 <- d1$data
      names(d2) <- str_replace(names(d2), "ga:", "")
      d2$date <- as.Date(d2$date,"%Y%m%d")
      d2 <- transform(d2, avTime = timeOnSite/visits)
      #4月以降のデータにする(1−3月は計測方法が違うので)
      d3 <- subset(d2, date >= as.Date("2010-04-01"))
      dc.avtime <- decompose(ts(d3$avTime, f=7))
      dc.visits <- decompose(ts(d3$visits, f=7))
      #曜日別の滞在時間(結果画面で)
      print(dc.visits$figure)
      print(dc.avtime$figure)
      #trendDataだけ持ってくる
      d.bind <- data.frame(
      visits = dc.visits$trend,
      avTime = dc.avtime$trend,
      date = seq(as.Date("2010-04-01"),as.Date("2010-12-30"),by=1))
      #平均化によるデータのない部分を除去
      d.bind2 <- d.bind[c(-1,-2,-3, -272,-273,-274),]
      #グラフ化
      p <- qplot(date,value, data=melt(d.bind2, id.var="date"),geom="line")
      p <- p + facet_grid(variable~.,scale="free_y")
      p <- p + scale_x_date(major="1 month", format="%m")
      p +  opts(ylab="上:セッション数 下:平均滞在時間(秒)
      ggsave("trend_visits_timeonsite.png",height=6,width=6,dpi=96)
    • 結果曜日別差異を見る
      セッション数(上にだしたと同じもの)
      9.7 14.3 16.7 15.4 11.9 -32.8 -35.2

      滞在時間(単位は秒数)

      月曜 火曜 水曜 木曜 金曜 土曜 日曜
      45.8 4.9 53.9 20.3 20.3 (-)46.0 (-)99.2

      トレンドデータ(曜日効果除去後のもの)

      http://abc-analytics.com/wp-content/uploads/2011/01/wpid-trend_visits_timeonsite.pngなんかこれだけでは、よくわからんかも。 曜日別というより、他のセグメントを当たる必要がある。

    分布を見る。滞在時間分布(セグメントデータとして)を見る

    考え方

    日別の集計値としての、平均滞在時間ではなんとも言いがたい。
    実は、GAはセッション滞在時間もセグメント情報として持ってる。
    なので、他のセグメント情報と掛け合わせで、滞在時間によるセッションの分布がだせる。
    指標側では平均しか見えないけど、こちらは分布まで見える。
    ここでは、月別とメディア別とランディングページ別を見てみる
    ただ、上でも書きましたが、滞在時間データそのものの信頼性には疑問はあります。
    僕自身のRの演習が主目的になっちゃってます。

    月間別

    月別のセグメントも入れて、データを取得。滞在時間は ga:visitLength

    • 単純にバー表示
      #クエリーを組み立てる。その前は、前のコードから続いてるものがある
      query$dimensions("ga:visitLength,ga:month")
      query$metrics("ga:visits")
      
      #前と同じくmax.rowsは10000に増やす
      output <- ga$GetReportData(query,max.rows=10000)
      output$total.result #=>5708
      d1 <- output$data
      names(d1) <- sub("ga:","",names(d1))
      
      #バープロットは、通常はcountデータをとるけど、weight指定で合計もいける
      p <- qplot(visitLength, data=d1, geom="bar", weight=visits, log="y")
      p + facet_grid(month~.)

      なんかみずらい、、、右側に月の表示。左側にセッション数、x軸は滞在時間だけど、、謎グラフになった。
      あと滞在時間が、飛び飛びになってるが怪しいし、0秒がどこだか不明だし、、
      全然だめ、、

      http://abc-analytics.com/wp-content/uploads/2011/01/wpid-bar_month_visits.png

      横軸を詰める。facet_wrapで表示。

      p <- qplot(visitLength, data=d1, geom="bar", weight=visits, log="xy")
      p + facet_wrap(~month)

      こちらのがみやすい。

      http://abc-analytics.com/wp-content/uploads/2011/01/wpid-month_stay_dst.png

    • density表示にするR(ggplot2)は、近似曲線も計算して引いてくれる。
      月別の分布を密度で近似線表示
      #http://tolstoy.newcastle.edu.au/R/e2/help/06/10/2836.html
      d2 <- data.frame(lapply(d1, rep, d1$visits)[1:2])
      d2$visitLength <- as.numeric(d2$visitLength)
      qplot(x=d2$visitLength, data=d2, geom="density",binwidth=10) + facet_grid(month ~ .)
      ggsave(dpi=96,width=6,height=6,file="hist_month_visits.png")

      http://abc-analytics.com/wp-content/uploads/2011/01/wpid-hist_month_visits.png

      なんか形は違ってきましたね、、、くらいか。

    • 平均値と中央値の表示
      これでも意味不明なので、平均値と中央値と引く
      近似線と実数(密度だけど)のバーを合わせて表示もする。
      #中央値と平均値を求める
      stt <- ddply(d2, .(month), function(x) data.frame(median=median(x$visitLength),
                                                         mean=mean(x$visitLength)))
      #以下、グラフ出力今回は、barplotとdensityを合わせる
      p <- ggplot(d2, aes(visitLength)) + geom_histogram(aes(y=..density..)) + geom_density()
      p <- p + facet_grid(month ~ ., labeller=function(l,x)paste(x,"月",sep=""))
      p <- p + opts(strip.text.y = theme_text(hjust=1, angle=0))
      p <- p + geom_vline(data=stt, aes(xintercept=stt$median), color=I("red"))
      p <- p + geom_vline(data=stt, aes(xintercept=stt$mean), color=I("green"))
      ggsave("hist_month_visits2.png",width=6,height=10,dpi=96)

      レジェンドが引けなかった、、、緑が平均値。赤が中央値。

      複数のgeomがある場合のlegendの対象指定はどうなのだろう?

      http://abc-analytics.com/wp-content/uploads/2011/01/wpid-hist_month_visits2.png

    メディア別

    時間変化とは別にメディア別もやってみる。

    • バープロット
      query$dimensions("ga:visitLength,ga:medium")
      query$metrics("ga:visits")
      output.m <- ga$GetReportData(query,max.rows=10000)
      d.m <- output.m$data
      colnames(d.m) <- sub("ga:","", colnames(d.m))
      #organic, referral, (none) に絞る
      d.m1 <- subset(d.m, medium %in% c("organic","referral","(none)"))
      #visits単位のレコードに
      d.m2 <- data.frame(lapply(d.m1[1:2], rep, d.m1$visits))
      d.m2$visitLength <- as.numeric(d.m2$visitLength)
      p <- ggplot(d.m2, aes(x=medium, y=visitLength)) + stat_boxplot()
      p <- p + coord_flip() + ylab("滞在時間(秒)")
      ggsave("boxplot_medium_visits.png",width=6,height=6,dpi=96)

      http://abc-analytics.com/wp-content/uploads/2011/01/wpid-boxplot_medium_visits.png

      分類が大まかすぎる。下でキーワード別をやる

    • 四分表示
      数値を出しておく
      今度は分表示にしておく。

    Splitting the page for mobile: page #1 | #.Next

    Images: Show | As Link

    New Posts | Recent Comments | Archives | Categories | Tags | Log in
    ファーストクリック分析 | 無料レポーティング | 遷移図分析 | RSS | Profile
    Converted by Ktai Style plugin.