廿TT

譬如水怙牛過窓櫺 頭角四蹄都過了 因甚麼尾巴過不得

共起関係とCTRに基づく検索キーワードのクラスタリング

今日の川柳

去年の大晦日に公開された論文で提案されたモデルについて書きます。
A latent allocation model for the analysis of microbial composition and disease | BMC Bioinformatics | Full Text

もともとは各個人が持っている腸内細菌の組み合わせによって病気になる確率が変わるのではないか? という仮説をもとに、病気になりやすい人が持っている細菌と病気になりにくい人が持っている細菌を比較するためのモデルです。

今回はこの手法を使って検索キーワードのクラスタリングをやってみます。

  • ある人の腸内細菌の組み合わせ→あるクエリの検索キーワードの組み合わせ
  • ある人が病気を持っている確率→あるクエリのCTR(クリック率)

に対応します。

もと論文ではEMアルゴリズムを使っているのですが今回はギブスサンプリングを使ってみたいと思います。

Rcpp で実装したのでちょっと長くなってしまった。

コードは次のリンク先においておきます。

binom_mult.cpp · GitHub

ギブスサンプリングを使うことでWBICを参考にクラスタ数を決めることができます。
(参考:WBICで混合多項分布のクラスタ数を決めてみる(ギブスサンプリング) - 廿TT

f:id:abrahamcow:20190117003205p:plain

L はクラスタ数です。L=5にして分析をすすめたいと思います。

申し遅れましたが分析対象は
Excel でワイブルプロット - 廿TT
といページです。

推定されたパラメータは次の図にまとめることができます。

f:id:abrahamcow:20190117003306p:plain

rho(塗りつぶしの色に対応)はクラスタごとに異なるCTRです。

p(棒グラフの高さに対応)はクラスタごとのキーワードの出現確率です。

目を引くのは右上の「エクセル」左上の「excel」といったエクセル関連ワードです。

CTRが高くなるに連れて、出現確率が上がっていることがわかります。

分析対象はまんま『Excel でワイブルプロット』というページなので予想通りの結果になったというところでしょうか。

ぼくがおもしろいと思ったのは「waiburu」とか「weibul」のグラフがガタガタしているのに、「weibull」のグラフがきれいな右肩上がりになっているところです。ワイブルのつづりをちゃんと覚えている人のほうがクリックしているようです。

残念なのは「とは」とか「書き方」「使い方」「解説」「わかりやすい」といった悩み・疑問系キーワードが軒並み右肩下がりになっているところです。

当該ページではワイブルプロットの解説はウィキペディアに丸投げしているので、妥当な結果だと言えるでしょう。

ワイブルプロットについてわかりやすい解説を書けばクリック率が上がりそうですね。
(まあでも今どきワイブルプロット使う必要ある?)

以上のように施策の振り返りや新しい施策への示唆を得ることができました。

R のコードを貼ります。

library(searchConsoleR)
library(tidyverse)
library(Rcpp)
library(parallel)
sourceCpp("~/Documents/binom_mult.cpp")
scr_auth()
sc_websites <- list_websites()
scdata <- search_analytics(sc_websites[1,1],
                           startDate = "2018-12-01",
                           endDate = "2018-12-31",
                           dimensions = c("query"),
                           dimensionFilterExp = "page~~/entry/2017/05/05/150436")
query_list <-sapply(scdata$query,function(x)strsplit(x," "))
q_len <- sapply(query_list, length)
n_q <- nrow(scdata)
vocab <- unique(unlist(query_list))
n_vocab <- length(vocab)
W <- t(sapply(query_list, function(X)as.integer(vocab %in% X)))
set.seed(1)
fitlist <- mclapply(2:9,function(l)binom_mult_Gibbs(scdata$clicks,scdata$impressions,W,l,
                                                phiini=rep(1/l,l),pini = gtools::rdirichlet(l,rep(1,n_vocab)),rhoini = runif(l),
                                                alpha = 1,gamma=1,beta=1/log(nrow(scdata)),iter = 2000))
lml <- sapply(fitlist,function(x)-mean(x$loglik[-c(1:999)]))
plot(2:9,lml,xlab="L",ylab = "WBIC",type="b")
abline(h=min(lml),lty=2)
print((2:9)[which.min(lml)])

set.seed(2)
fit <- binom_mult_Gibbs(scdata$clicks,scdata$impressions,W,5,
                        phiini=rep(1/5,5),pini = gtools::rdirichlet(5,rep(1,n_vocab)),rhoini = runif(5),
                        alpha = 1,gamma=1,beta=1,iter = 2000)
plot(fit$loglik,type="l")

phat <- apply(fit$p,1:2,mean)
colnames(phat) <- vocab

p_df <- as_data_frame(phat) %>% 
  mutate(l=row_number(),rho=colMeans(fit$rho)) %>% 
  gather(word,p,-l,-rho)

ggplot(p_df,aes(x=l,y=p,fill=rho))+
  geom_col()+
  facet_wrap(~word,scales = "free_y")+
  theme_bw(base_family = "Osaka")+
  theme(axis.text.x = element_text(angle = 90))  

ggsave("~/Desktop/res.png",height = 10,width = 18)

論文中ではベイズの定理を使って、キーワード(=腸内細菌)の組み合わせからCTR(=疾病を持つ確率)を計算する式も載っています。
結果はただの重み付き平均になります。

おしまい。