廿TT

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

[searchConsoleR]文脈に基づく検索キーワードのクラスタリング

検索クエリではなく、検索クエリに含まれるキーワードをグルーピングしたい。

Search Console のデータを使います。

キーワードの類似度

どこからどこまでを一つのキーワードとみなすかは難しいですが、ここでは単純に検索クエリ内のスペースで区切られた文字列を「キーワード」とみなします。

形態素解析とかはしません。

かけあわせキーワードが同じになるクエリの個数を、キーワードどうしの類似度と呼ぶことにします。

もうちょっとていねいに述べると以下のような感じです。

ユニークなキーワードを u[m] (m=1,...,M) と書くことにします。

語順などは無視します。

キーワード u[m] を含むクエリを q[n|u[m]] (n=1,...,N[m]) と書くことにします。

q[n|u[m]] はキーワードの集合です。

クエリ q[n|u[m]] からキーワード u[m] だけを除いた集合(差集合)を q[n|u[m]] - u[m] と書くことにします。

キーワード u[i] と u[j] の類似度を、

空集合でない {q[n|u[i]] - u[i]} と、空集合でない {q[n|u[j]] - u[j]} の積集合の要素の個数」

と定義します。

提案手法は、この類似度で M 行 M 列の行列を作って、それを k-means でクラスタリングするだけです。

ふつう k-means でクラスタリングするときは、変数を標準化することが多いのですが、なんどもいろんなクエリにあらわれるメイン的なキーワードと、少数のクエリにあらわれるサブ的なキーワードを区別したいので、今回はあえて標準化しないことにします。

R による実践

searchConsoleR でデータを読み込みます。

library(searchConsoleR)
library(ggplot2)
library(tidyr)
library(dplyr)

scr_auth()
sc_websites <- list_websites()

scdata <- search_analytics(sc_websites[1,1], 
                           dimensions = c("query"),
                           dimensionFilterExp = "page~~/entry/2014/12/19/221230")

とってきたデータクリック数(clicks)順の頭 6 行はこんな感じです。

> head(scdata)
          query clicks impressions        ctr position
1      近似曲線    214        5915 0.03617921 7.000000
2      指数近似    184         678 0.27138643 2.022124
3      対数近似    166         726 0.22865014 2.022039
4 近似曲線 種類    102         358 0.28491620 2.527933
5 指数関数 近似     60         289 0.20761246 2.802768
6  近似曲線とは     57        1864 0.03057940 7.173283

類似度を計算する関数を定義します。

make_similarity_matrix <- function(query){
query_list <-sapply(query,function(x)strsplit(x," "))
tab1 <-table(unlist(query_list))
kw <-names(tab1[tab1>1])
BoW <-t(sapply(query_list,function(x){kw %in% x}))
BoW <- BoW[apply(BoW,1,any),]
colnames(BoW) <- kw
M <- length(kw)
simmat <- matrix(NA,M,M)
for(j in 1:M){
  for(i in 1:M){
    list1 <- apply(BoW[BoW[,i],-i],1,which)
    list2 <- apply(BoW[BoW[,j],-j],1,which)
    simmat[i,j] <-length(intersect(list1,list2))
  }
}
colnames(simmat)<-kw
rownames(simmat)<-kw
list(kw=kw,similarity_matrix=simmat,query_list=query_list)
}

こんな感じで k-means 法でクラスタリングします。

out1 <-make_similarity_matrix(scdata$query)
set.seed(1234)
cl1<-kmeans(out1$similarity_matrix,3,iter.max = 100)

クラスタの要素の個数はこんな感じです。

> table(cl1$cluster)

 1  2  3 
 2  5 32 

キーワードを見ていくと以下のようにわかれました。

> out1$kw[cl1$cluster==1]
[1] "excel"    "エクセル"
> out1$kw[cl1$cluster==2]
[1] "近似"     "近似曲線" "指数近似" "対数近似" "累乗近似"
> out1$kw[cl1$cluster==3]
 [1] "e"              "log"            "グラフ"         "できない"      
 [5] "とは"           "フィッティング" "意味"           "違い"          
 [9] "回帰曲線"       "関数"           "求め方"         "曲線"          
[13] "近似曲線とは"   "近似式"         "近似線"         "近似値"        
[17] "減衰曲線"       "使い分け"       "指数"           "指数関数"      
[21] "自然対数"       "式"             "種類"           "数式"          
[25] "線形近似"       "対数"           "対数グラフ"     "対数関数"      
[29] "反比例"         "微分"           "変曲点"         "累乗"          

今回対象としたランディングページは、
指数近似、対数近似曲線の導出と近似曲線の選び方 - 廿TT
であり、クラスタ 2 がページタイトルそのものに近いメイン系キーワード、クラスタ 1 がエクセル関連ワード、クラスタ 3 がその他のかけあわせキーワードというふうに解釈できます。

ぼくとしては、まあリーズナブルなわかれ方だと思います。

せっかくなので、クラスタごとの傾向の違いをみることにします。

エクセル関連ワードを含むクエリと含まないクエリで層別してみます。

scdata_excel <-scdata %>% 
  mutate(excel=sapply(out1$query_list, function(x)any(x %in% out1$kw[cl1$cluster==1]))) %>% 
  gather(metrics,value,-excel,-query)

ggplot(scdata_excel,aes(x=excel,y=log(value,2)))+
  geom_boxplot()+
  facet_wrap(~metrics,scales = "free_y")

f:id:abrahamcow:20170713003147p:plain

TRUE がエクセル関連ワードを含むほう、FALSE が含まないほうです。

エクセル関連ワードは競争率が高いのか、掲載順位(position)が低めでクリック数(clicks)、インプレッション数(impressions)も少なめです。

次にメイン系キーワードのみからなるクエリとそれ以外で層別してみます。

scdata_main <-scdata %>% 
  mutate(main=sapply(out1$query_list, function(x)all(x %in% out1$kw[cl1$cluster==2]))) %>% 
  gather(metrics,value,-main,-query)

ggplot(scdata_main,aes(x=main,y=log(value,2)))+
  geom_boxplot()+
  facet_wrap(~metrics,scales = "free_y")

f:id:abrahamcow:20170713003530p:plain

メイン系キーワードのみからなるクエリの方がインプレッション、クリックともに多く、クリック率(ctr)も高めに保たれていることがわかります。

ちょっと考えると、シンプルなメイン系キーワードのみからなるクエリより、その他のかけあわせキーワードをいっぱい含んだクエリの方が検索者のニーズが具体的で、クリック率が高くなりそうな気がするのですが、逆の結果になりました。

こういうことはままあります。

「これからは広告ではなく狭告だ」「顧客一人ひとりのニーズに合わせたイグザクトなセグメンテーションが重要だ」というようなことはよく言われるのですが、ニーズが具体的すぎる検索者は、こちらの推薦や提案を受け入れる余地があまりなく、獲得効率が悪かったりします。

その辺のバランスのとり方がマーケターの腕の見せどころなのかもしれません。

検索連動型広告を成功に導くSEM戦略 増補改訂版

検索連動型広告を成功に導くSEM戦略 増補改訂版