前回の記事では標本サイズが同一の場合の対応なしone-way ANOVAの実装方法について書きました。
一方、実際にはデータに欠損値はつきもので標本サイズはグループごとに異なることは容易に発生し、かつTableau上にデータを読み込んだ段階では欠損値処理が難しかったりします。
Tableauに読み込ませる前に欠損値処理をしたデータを用意することも手ですが、BIツールの性質上、何らかの情報が集約されたデータを元に多種多様な分析や可視化をすることが多く、統計分析のために個別のデータソースを作成することはそこまで現実的でないかもしれません。
というわけで、今回はそのような欠損値を含むような集計データに対してのone-way ANOVAの実装を取り上げます。
参考:Rで分散分析 (p.48 ~ p.50)
今回使用したWorkbookは以下からダウンロードできます。
欠損値つきのデータに対する勧化方
今回は以下のようなデータを用意しました。
良い感じに穴あきのデータであり、かく要因におけるデータ点数(標本数)がバラバラになっています。
ところで前回の復習ですが、各要素と全体平均値の差の総和は、以下のように「要因内の平均値の全体平均値に対するばらつき」と「各データの要因内の平均値に対するばらつき」に分解することができました。
標本数が同じの場合は、第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へよろしくお願いします。それでは。