前の記事(プログラム書法)で,似たようなことを行う 2 つの関数を 1 つにまとめたが,今回はさらに,もう 2 つの関数を抱き合わせにする。
関数名を覚えるのが面倒ということは些細な理由である。関数のメンテナンスが「間違いなく」,「容易に」できるというメリットがある。また,短い関数は見通しがよいので,バグが入りにくい(か?)。
前回のプログラムで,wilcox.test, t.test の呼び出し時に paired=FALSE,t.test のときに var.equal=FALSE をわざわざ指定していたが,デフォルトなのでそれらを取り除くと,4 つの検定関数の呼び出し時の引数指定が全く同じなので,なにかうまい方法があるんじゃないかと思う人もいよう。そのうまい方法とは,以下のように,変数(func)に関数オブジェクト(wilcox.test など)を代入することである。
# 全ての変数に wilcox.test / t.test / kruskal.test / oneway.test を行う関数
Rep = function(data, group, method = c("wilcox", "t", "kruskal", "oneway"), sort = TRUE) {
name = method = match.arg(method)
if (method == "wilcox") {
func = wilcox.test
} else if (method == "t") {
func = t.test
} else if (method == "kruskal") {
func = kruskal.test; name = "chi-squared"
} else { # if (method == "oneway")
func = oneway.test; name = "F"
}
old = options(warn = -1)
ans = sapply(data, function(d) func(d ~ group)$statistic)
options(old)
ans = cbind(ans)
rownames(ans) = colnames(data)
if (sort) ans = cbind(ans[order(ans[,1], decreasing = TRUE), ])
colnames(ans) = name
ans
}
# 関数の実行
# library(kernlab)
# data(spam)
# Rep(spam[c(1:10, 16, 19)], spam$type)
# Rep(spam[c(1:10, 16, 19)], spam$type, sort=FALSE)
# Rep(spam[c(1:10, 16, 19)], spam$type, method = "t")
# Rep(spam[c(1:10, 16, 19)], spam$type, method = "t", sort=FALSE)
Rep(iris[1:4], iris$Species, method="k") # method は省略形でも指定できる
Rep(iris[1:4], iris$Species, method="k", sort=FALSE)
Rep(iris[1:4], iris[,5], method="o") # group はベクトルでなければならない
Rep(iris[1:4], iris[,5], method="o", sort=FALSE)