LoginSignup
1
2

GoogleAnalyticsのデータでアソシエーション分析

Last updated at Posted at 2021-01-28

この記事はGoogle Analytics 4ではなく、Universal Analyticsを対象としています。

Rでアソシエーション分析したい

多変量解析の手法のひとつであるアソシエーション分析を実データで学習しておりまして、アクセスログからデータ抽出・前処理するまでの流れをメモ程度に残しておきます。
この記事はGoogle Analytics 360(BigQuery Export)の利用を前提としています。

アソシエーション分析とは

バスケット内のアイテム間の意味のある関係を調べる分析手法です。「XXが購入されるとYYも購入される傾向にある」といったようなアイテムごとの組み合わせの規則を抽出することができます。

データ抽出

分析に用いるデータのトランザクション(共起するデータポイント)の単位について、以下2つの粒度で抽出してみます。

  • セッション内でのイーコマーストランザクション(SKU)
  • セッション内で表示されたページ(第二階層)

今回の場合はBigQueryからデータ抽出・CSVファイル出力し、R側で最終的にトランザクション型のデータを用意することになります。

1. SKU単位の場合

セッション(visitId)ごとの購入(SKU)を1つのトランザクションとします。
※抽出元のサービスが1度に1つの商品しか購入できないため、「1セッションを1つのトランザクション」として捉えています。一度に複数購入可能であればこの限りではありません。

SELECT
  visitId,
  product.productSKU AS sku 
FROM
  `project_name.dataset_name.ga_sessions_YYYYMMDD`,
  UNNEST(hits) AS hits,
  UNNEST(hits.product) AS product

以下のようなテーブルが抽出できるイメージです。

visitId sku
1 1585704179 ABC00000149
2 1585674923 DEF00001609
3 1585701501 GHI00004228

2. ページ単位の場合

セッションごとの閲覧ディレクトリ(第2階層/pagePathLevel2)を1つのトランザクションとします。/の文字列は列名としては扱えないので、あらかじめ除去しておきます。

WITH
  raw_data AS (
  SELECT
    visitId,
    hits.page.pagePathLevel2 AS path
  FROM
    `project_name.dataset_name.ga_sessions_YYYYMMDD`,
    UNNEST(hits) AS hits
  WHERE
    hits.type = "PAGE"),
  fixed_data AS(
  SELECT
    visitId,
  IF
    (path = "/",
      "top_page",
      path) AS path
  FROM
    raw_data)
SELECT
  visitId,
  REGEXP_REPLACE(path, "/", "") AS path,
FROM
  fixed_data
GROUP BY
  visitId,
  path

以下のようなテーブルが抽出できるイメージです。

visitId path
1 1585704179 top_page
2 1585674923 faq
3 1585701501 products

Rで前処理

今回必要なライブラリを読み込みます。

library(tidyverse) # データハンドリング
library(arules) # アソシエーションルールの検出
library(arulesViz) # アソシエーションルールの可視化
library(dummies) # one-hotエンコード

ローカル環境の処理能力の限界もありますので、前処理は可能な限りBigQueryやDataprepなどクラウド側の計算資源を活かした方が良さそうです。

CSVファイルをデータフレームとして読み込み、one-hotエンコーディングし、transaction型へキャストします。

raw_data <- read_csv("src/xxx_by_visitid.csv") %>% 
  distinct(visitId,sku) %>% 
  as.data.frame() #dummiesがtibbleを扱えないためdataframeにキャスト
df.one_hot <- dummy.data.frame(raw_data,sep = "_") 

colnames(df.one_hot) = str_replace(colnames(df.one_hot), 'column_name_', '')

df.one_hot <- df.one_hot %>% 
  group_by(visitId) %>% 
  summarise_each(funs(sum)) %>% 
  select(-visitId)

d.transaction <- as(as.matrix(df.one_hot), "transactions") 

aprioriの実行

apriori()を実行してアソシエーションルールを検出します。parameterでの支持度、確信度の閾値は 検出されるルールの数やマシンの計算資源に合わせて適宜調整します。

d.ap <- apriori(d.transaction, parameter = list(supp = 0.001, conf = 0.1))

d.apにルール集合を代入しているのででinspect()を用いてアソシエーションルールの確認ができます。ここではリフト値の高い順に10件抽出してみます。

inspect(head(sort(d.ap, by = "lift"),10))
##      lhs                         rhs        support   confidence coverage 
## [1]  {category,game,top10}    => {market}   0.8035937 0.9778611  0.8217872
## [2]  {enquete,top10}          => {market}   0.8010750 0.9761986  0.8206065
## [3]  {category,game,product}  => {market}   0.8049768 0.9743712  0.8261500
## [4]  {category,game}          => {market}   0.8096207 0.9738291  0.8313787
## [5]  {game,product,top10}     => {market}   0.8071919 0.9730396  0.8295571
## [6]  {game,top10}             => {market}   0.8123531 0.9723680  0.8354379
## [7]  {category,product,top10} => {market}   0.8955393 0.9723114  0.9210417
## [8]  {category,top10}         => {market}   0.9021848 0.9716029  0.9285530
## [9]  {game,market,top10}      => {category} 0.8035937 0.9892172  0.8123531
## [10] {game,market,product}    => {category} 0.8049768 0.9884297  0.8143996
##      lift     count
## [1]  1.057983 71466
## [2]  1.056185 71242
## [3]  1.054208 71589
## [4]  1.053621 72002
## [5]  1.052767 71786
## [6]  1.052040 72245
## [7]  1.051979 79643
## [8]  1.051213 80234
## [9]  1.050876 71466
## [10] 1.050039 71589

lhs(left-hand-side)が条件部、rhs(right-hand-side)が結論部となり、「lhsが含まれるトランザクションにはrhsが含まれやすい」と判断できます。

ここでの結果はどれもリフト値が1に近いため、ルールの重要度が高いと判断するのは難しそうです。

ルール分布をplotで描画

plot()では支持度と信頼度の散布図を描画することができます。

plot(d.ap)

Rplot05.png

medhodgroupedを指定するとルールをグルーピングすることができます。

plot(d.ap, method = "grouped", control = list(k=10))

Rplot03.png

methodgraphを指定するとigraphによるグラフ描画が可能です。

plot(d.ap, method = "graph", control = list(type = "items"))

Rplot07.png

円の大きさがルールの支持度、濃淡がリフト値を表しています。アイテムからルールに向かう矢印は「そのアイテムが左側」であり、ルールからアイテムに向かう矢印は「そのアイテムが右側」であることを意味しています。

interactiveTRUEを指定するとXQuartsを利用してインタラクティブな描画が可能になります。

plot(d.ap,method = "graph", control = list(type="items"), interactive = TRUE)

スクリーンショット 2021-01-28 0.19.55.png

このグラフからアソシエーションルールの向きの意味を解釈するのは難しそうですが、クラスタのパターン発見という意味では有意義な結果が得られそうです。例えば事前の知識がない状態でアクセスログを確認する場合に、ざっくりとした行動パターンのクラスタは把握できるかもしれません。また「導線設置」の施策があったとして、その施策の前後のグラフを比較することでクラスタに変化があったかどうかを可視化できそうです。

おわりに

実際にアソシエーションルールを分析したところSKUについてはある程度納得の行く結果が得られたものの、同時購入ではなくセッション内での購入ベースとなるため、共起の重要性が低そうな印象もありました。
またページパスについてはサイトにおいてある程度ユーザーの行動が決まっていることもあり、有意味なルールを見つけることはできませんでした。ただ、グラフ描画によるクラスタ理解は活用できそうに思えました。

参考文献

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2