2020年9月7日

R-Tableau勉強記5:Tableauで標本サイズが異なる場合のone-way ANOVAを実装する

前回の記事では標本サイズが同一の場合の対応なしone-way ANOVAの実装方法について書きました。

一方、実際にはデータに欠損値はつきもので標本サイズはグループごとに異なることは容易に発生し、かつTableau上にデータを読み込んだ段階では欠損値処理が難しかったりします。

Tableauに読み込ませる前に欠損値処理をしたデータを用意することも手ですが、BIツールの性質上、何らかの情報が集約されたデータを元に多種多様な分析や可視化をすることが多く、統計分析のために個別のデータソースを作成することはそこまで現実的でないかもしれません。

というわけで、今回はそのような欠損値を含むような集計データに対してのone-way ANOVAの実装を取り上げます。

参考:Rで分散分析 (p.48 ~ p.50)

今回使用したWorkbookは以下からダウンロードできます。

https://drive.google.com/file/d/1IP0chlkAFXY-pi8hzpnxYiVrZTdpcM4R/view?usp=sharing


欠損値つきのデータに対する勧化方

今回は以下のようなデータを用意しました。

良い感じに穴あきのデータであり、かく要因におけるデータ点数(標本数)がバラバラになっています。

ところで前回の復習ですが、各要素と全体平均値の差の総和は、以下のように「要因内の平均値の全体平均値に対するばらつき」と「各データの要因内の平均値に対するばらつき」に分解することができました。

標本数が同じの場合は、第1項は標本数nに平均値差の2乗和をかけたもので良かったのですが、今回の場合は標本数nはj番目要因によって変化するので、式が若干変わります。

この二つの項を使用してF値を計算するわけですので、それぞれをつらつら計算していく必要が出てきます。

ということで、まずはRコードを使用したTableau計算フィールドを以下に記載します。

p-value

SCRIPT_REAL(
 
"
 
#initial setup
 
library(installr)
 
key = .arg1
 
x = .arg2
 
g = .arg3
 

 
nc = length(unique(g))
 
unique_key = unique(key)
 
nr = length(unique_key)
 
label = factor(unique(g))
 

 
# align data with missing value label
 
x_matrix = matrix(NA, nrow=nr, ncol=nc)
 
for (i in 1:nr){
 
for (j in 1:nc){
 
if (!is.empty(x[key == unique_key[i] & g == label[j]])){
 
x_matrix[i,j] = x[key == unique_key[i] & g == label[j]]
 
}
 
}
 
}
 

 
m = ncol(x_matrix)
 
mx = nj = rep(0,m)
 

 
for (j in 1:m){
 
xj = x_matrix[,j]
 
nj[j] = length(xj[!is.na(xj)]) #sample size of each group
 
mx[j] = mean(xj[!is.na(xj)]) #mean of each group
 
}
 

 
# variations
 
gmx = sum(mx*nj) / sum(nj) #total mean
 
ss_b = sum((mx - gmx)^2 * nj) #mean diff between mean of groups and total mean
 
ss_t = sum((c(x_matrix)[!is.na(c(x_matrix))] - gmx)^2)
 
ss_e = ss_t - ss_b
 

 
# degree of freedom
 
df_b = m-1
 
df_e = sum(nj) - m
 

 
# mean squares
 
ms_b = ss_b/df_b
 
ms_e = ss_e/df_e
 

 
# F value
 
f = ms_b/ms_e
 
p = 1 - pf(f, df_b, df_e)
 
"
 
,MIN([Order Date]), SUM([Sales]), MIN([Segment])
 
)
 

ここからコードの解説をしていきます。

library(installr)

まず事前準備として、is.empty()関数が欲しかったのでinstallrパッケージをダウンロードします。

key = .arg1
 
x = .arg2
 
g = .arg3
 

 
nc = length(unique(g))
 
unique_key = unique(key)
 
nr = length(unique_key)
 
label = factor(unique(g))

TableauからRに渡す際にはデータがベクトルとして入るのですが、そのベクトルから最終的には以下の形を作成したいとします。

keyに指定するのは上記の行を指定するもの、xには各数値、gにはANOVAに要因として使用するディメンションを指定します。

ncは列数、nrは行数を取得しており、unique_key, labelは行と列のユニーク値を取得しています。

# align data with missing value label
 
x_matrix = matrix(NA, nrow=nr, ncol=nc)
 
for (i in 1:nr){
 
for (j in 1:nc){
 
if (!is.empty(x[key == unique_key[i] & g == label[j]])){
 
x_matrix[i,j] = x[key == unique_key[i] & g == label[j]]
 
}
 
}
 
}

ここではベクトル→行列の形に変換させるための処理を実施しています。

この処理により上図の表の形のデータがベクトルから作成されます。

あとはもう流れ作業で、F値の定義に従って必要な計算を行い、最後にpf()から算出されたF値のp値を求めています。

m = ncol(x_matrix)
 
mx = nj = rep(0,m)
 

 
for (j in 1:m){
 
xj = x_matrix[,j]
 
nj[j] = length(xj[!is.na(xj)]) #sample size of each group
 
mx[j] = mean(xj[!is.na(xj)]) #mean of each group
 
}
 

 
# variations
 
gmx = sum(mx*nj) / sum(nj) #total mean
 
ss_b = sum((mx - gmx)^2 * nj) #mean diff between mean of groups and total mean
 
ss_t = sum((c(x_matrix)[!is.na(c(x_matrix))] - gmx)^2)
 
ss_e = ss_t - ss_b
 

 
# degree of freedom
 
df_b = m-1
 
df_e = sum(nj) - m
 

 
# mean squares
 
ms_b = ss_b/df_b
 
ms_e = ss_e/df_e
 

 
# F value
 
f = ms_b/ms_e
 
p = 1 - pf(f, df_b, df_e)

ということで、以下に前回のようなプロット図を出してみました。

ANOVA Label

IF [p-value] < 0.05

THEN '★'

ELSE ''

END

表計算の設定は以下です。

ということで、標本数が異なる場合の対応なしone-way ANOVAもTableau上で実装することが出来ました。


最後に

今回は標本数が異なる場合の対応なしone-way ANOVAの実装方法について書きました。

Tableauへの実装は基本的にコードのコピー&ペーストで済んでしまうので、ぜひご自身の分析ダッシュボードに機会があれば使用してみてください。

ご質問等はTwitter、Linkedinへよろしくお願いします。それでは。