正準判別分析 Last modified: Jul 06, 2015
目的
正準判別分析を行う。
MASS パッケージにある lda は,3群以上の判別の場合には,正準判別分析を行っている。
そして,このプログラムも lda も,全く同じ答えを出す。
使用法
candis(data, group)
print.candis(obj)
summary.candis(obj)
plot.candis(obj, pch=as.integer(obj$group), col=as.integer(obj$group))
引数
data データ行列(行がケース,列が変数)
group 各ケースがどの群であるかを表す変数
obj candis が返すオブジェクト
3 群以上の判別図
pch プロット記号(判別する群の数と同じ長さの整数ベクトル)
col プロット色(判別する群の数と同じ長さの整数ベクトル)
xpos, ypos legend 関数の x, y 引数(座標値の他,xpos="topright" など)
... plot への引数
2 群の判別図
which 図の種類 boxplot か barplot
nclass barplot のときのおよその階級数
... boxplot, barplot への引数
ソース
以下のほかに,一般化固有値問題を解く関数が必要。
インストールは,以下の 1 行をコピーし,R コンソールにペーストする
source("http://aoki2.si.gunma-u.ac.jp/R/src/candis.R", encoding="euc-jp")
# 正準判別分析
candis <- function( data, # 説明変数データ行列
group) # 群変数
{
vnames <- colnames(data)
group <- as.factor(as.matrix(group)) # 群を factor に変換
OK <- complete.cases(data, group) # 欠損値を持つケースを除く
data <- as.matrix(data[OK,])
colnames(data) <- vnames
group <- group[OK]
p <- ncol(data) # 変数の個数
n <- nrow(data) # ケース数
n.i <- table(group) # 各群のケース数
k <- length(n.i) # 群の個数
group.means <- matrix(unlist(by(data, group, colMeans)), p) # 各変数の群ごとの平均値
grand.means <- colMeans(data) # 各変数の全体の平均値
means <- cbind(grand.means, group.means) # 結果表示のためにまとめる
F.value <- apply(data, 2, function(x) oneway.test(x ~ group, var.equal=TRUE)$statistic)
df1 <- k-1
df2 <- n-k
p.value <- format.pval(pf(F.value, df1, df2, lower.tail=FALSE))
wilksFromF <- df2/(F.value*df1+df2)
univariate <- data.frame(wilksFromF, F.value, rep(df1, p), rep(df2, p), p.value)
ss <- split(data.frame(data), group)
w <- Reduce("+", lapply(ss, function(x) var(x)*(nrow(x)-1))) # 群内変動・共変動行列
b <- (var(data)*(n-1))-w # 群間変動・共変動行列
within.cov <- w/(n-k) # プールされた分散・共分散行列
sd <- sqrt(diag(within.cov))
within.r <- within.cov/outer(sd, sd)
result <- geneig(b, w) # 一般化固有値問題を解く
eigen.values <- result$values # 固有値
nax <- sum(eigen.values > 1e-10) # 解の個数
eigen.values <- eigen.values[1:nax] # 必要な個数の固有値を取り出す
eigen.vectors <- result$vectors[, 1:nax,drop=FALSE] # 固有ベクトルも取り出す
LAMBDA <- rev(cumprod(1/(1+rev(eigen.values)))) # Wilks のΛ
chi.sq <- ((p+k)/2-n+1)*log(LAMBDA) # カイ二乗値
l.L <- 1:nax-1
df <- (p-l.L)*(k-l.L-1) # 自由度
p.wilks <- pchisq(chi.sq, df, lower.tail=FALSE) # P 値
canonical.corr.coef <- sqrt(eigen.values/(1+eigen.values)) # 正準相関係数
temp <- diag(t(eigen.vectors) %*% w %*% eigen.vectors)
temp <- 1/sqrt(temp/(n-k))
coeff <- eigen.vectors*temp # 正準判別係数
const <- as.vector(-grand.means %*% coeff) # 定数項
coefficient <- rbind(coeff,const) # 両方併せる
std.coefficient <- coeff * sqrt(diag(within.cov)) # 標準化正準判別係数
centroids <- t(t(coeff) %*% group.means+const) # 重心
can.score <- t(t(data %*% coeff)+const) # 正準得点
structure <- matrix(0, p, nax) # 構造行列
for (i in 1:nax) {
ss <- split(data.frame(cs=can.score[,i], data), group)
ss <- Reduce("+", lapply(ss, function(x) var(x)*(nrow(x)-1)))
structure[,i] <- (ss[,1] / sqrt(ss[1,1] * diag(ss)))[-1]
}
d <- sapply(1:k, function(i) colSums((t(can.score)-centroids[i,])^2)) # 二乗距離
p <- pchisq(d, p, lower.tail=FALSE) # ケースがそれぞれの群に属するとしたとき,その判別値を取る確率
p.Bayes <- t(t(exp(-d/2))*as.numeric(n.i)) # 各ケースが各群に所属するベイズ確率
p.Bayes <- p.Bayes/rowSums(p.Bayes) # P 値
gname <- levels(group)
classification <- factor(gname[max.col(p.Bayes)], levels=gname)
colnames(means) <- c("grand mean", gname)
colnames(univariate) <- c("Wilks のラムダ", "F 値", "df1", "df2", "P 値")
rownames(std.coefficient) <- rownames(structure) <- rownames(univariate) <- rownames(means)
colnames(std.coefficient) <- colnames(structure) <- colnames(coefficient) <-
colnames(centroids) <- colnames(can.score) <- paste("axis", 1:nax)
rownames(coefficient) <- c(rownames(means), "constant")
rownames(centroids) <- colnames(p.Bayes) <- colnames(p) <- gname
rownames(can.score) <- rownames(p.Bayes) <- rownames(p) <- paste("case", 1:n)
return(structure(list(means=means, univariate=univariate, betwee.ss=b, within.ss=w, within.cov=within.cov,
within.r=within.r, eigen.values=eigen.values, LAMBDA=LAMBDA,
chi.sq=chi.sq, df=df, p.wilks=p.wilks,
canonical.corr.coef=canonical.corr.coef, std.coefficient=std.coefficient,
structure=structure, coeff=coefficient, centroids=centroids, can.score=can.score,
p.Bayes=p.Bayes, p=p, classification=classification, group=group, ngroup=k, nax=nax),
class="candis"))
}
# print メソッド
print.candis <- function( obj, # candis が返すオブジェクト
digits=5) # 結果の表示桁数
{
cat("\nWilks のラムダ\n\n")
d <- data.frame(1:obj$nax, obj$LAMBDA, obj$chi.sq, obj$df, format.pval(obj$p.wilks))
colnames(d) <- c("関数", "Wilks のラムダ", "カイ二乗値", "自由度", "P 値")
print(d, digits=digits, row.names=FALSE)
cat("\n判別係数\n\n")
print(round(obj$coeff, digits=digits))
cat("\n標準化判別係数\n\n")
print(round(obj$std.coefficient, digits=digits))
cat("\n構造行列\n\n")
print(round(obj$structure, digits=digits))
cat("\n判別結果\n\n")
print(xtabs(~obj$group+obj$classification))
}
# summary メソッド
summary.candis <- function( obj, # candis が返すオブジェクト
digits=5) # 結果の表示桁数
{
print.default(obj, digits=digits)
}
# plot メソッド
plot.candis <- function(obj, # candis が返すオブジェクト
pch=1:obj$ngroup, # 3 群以上の判別時の記号
col=1:obj$ngroup, # 3 群以上の判別時の色
xpos="topright", ypos=NULL, # 3 群以上の判別時の legend 関数の x, y 引数
which=c("boxplot", "barplot"), # 2 群判別のときのグラフの種類
nclass=20, # barplot のおよその階級数
...) # plot, boxplot, barplot への引数
{
score <- obj$can.score
group <- obj$group
if (ncol(score) >= 2) {
int.group <- as.integer(group)
plot(score, pch=pch[int.group], col=col[int.group], ...)
legend(x=xpos, y=ypos, legend=levels(group), pch=pch, col=col)
}
else {
which <- match.arg(which)
if (which == "boxplot") { # boxplot
plot(score ~ group, xlab="群", ylab="判別値", ...)
}
else { # barplot
tbl <- table(group, cut(score, breaks=pretty(score, n=nclass)))
barplot(tbl, beside=TRUE, legend=TRUE, ...)
}
}
}
使用例
> data(iris)
> (result <- candis(iris[1:4], iris[5]))
print メソッドでは以下の結果だけを表示する
Wilks のラムダ
関数 Wilks のラムダ カイ二乗値 自由度 P 値
1 0.023439 546.12 8 < 2.22e-16
2 0.777973 36.53 3 5.7861e-08
判別係数
axis 1 axis 2
Sepal.Length 0.82938 0.02410
Sepal.Width 1.53447 2.16452
Petal.Length -2.20121 -0.93192
Petal.Width -2.81046 2.83919
constant 2.10511 -6.66147
標準化判別係数
axis 1 axis 2
Sepal.Length 0.42695 0.01241
Sepal.Width 0.52124 0.73526
Petal.Length -0.94726 -0.40104
Petal.Width -0.57516 0.58104
構造行列
axis 1 axis 2
Sepal.Length -0.22260 0.31081
Sepal.Width 0.11901 0.86368
Petal.Length -0.70607 0.16770
Petal.Width -0.63318 0.73724
判別結果
obj$classification
obj$group setosa versicolor virginica
setosa 50 0 0
versicolor 0 48 2
virginica 0 1 49
> summary(result)
sumamry メソッドでは,すべての要素を表示することができる。
$means # 全体および各群の平均値
grand mean setosa versicolor virginica
Sepal.Length 5.8433 5.006 5.936 6.588
Sepal.Width 3.0573 3.428 2.770 2.974
Petal.Length 3.7580 1.462 4.260 5.552
Petal.Width 1.1993 0.246 1.326 2.026
$univariate # 平均値の差の検定(一変量;一元配置分散分析)
Wilks のラムダ F 値 df1 df2 P 値
Sepal.Length 0.38129427 119.26450 2 147 < 2.22e-16
Sepal.Width 0.59921715 49.16004 2 147 < 2.22e-16
Petal.Length 0.05862828 1180.16118 2 147 < 2.22e-16
Petal.Width 0.07111707 960.00715 2 147 < 2.22e-16
$between.ss # 群間平方和・積和行列
Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length 63.212 -19.953 165.25 71.279
Sepal.Width -19.953 11.345 -57.24 -22.933
Petal.Length 165.248 -57.240 437.10 186.774
Petal.Width 71.279 -22.933 186.77 80.413
$within.ss # 群内平方和・積和行列
Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length 38.956 13.6300 24.6246 5.6450
Sepal.Width 13.630 16.9620 8.1208 4.8084
Petal.Length 24.625 8.1208 27.2226 6.2718
Petal.Width 5.645 4.8084 6.2718 6.1566
$within.cov # プールした分散・共分散行列
Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length 0.265008 0.092721 0.167514 0.038401
Sepal.Width 0.092721 0.115388 0.055244 0.032710
Petal.Length 0.167514 0.055244 0.185188 0.042665
Petal.Width 0.038401 0.032710 0.042665 0.041882
$within.r # プールした相関係数行列
Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length 1.00000 0.53024 0.75616 0.36451
Sepal.Width 0.53024 1.00000 0.37792 0.47053
Petal.Length 0.75616 0.37792 1.00000 0.48446
Petal.Width 0.36451 0.47053 0.48446 1.00000
$eigen.values # 固有値
[1] 32.19193 0.28539
$LAMBDA # Wilks のラムダ
[1] 0.023439 0.777973
$chi.sq # カイ二乗値(近似値)
[1] 546.12 36.53
$df # 自由度
[1] 8 3
$p.wilks # P 値
[1] 8.8708e-113 5.7861e-08
$canonical.corr.coef # 正準相関係数
[1] 0.98482 0.47120
$std.coefficient # 標準化判別係数
axis 1 axis 2
Sepal.Length 0.42695 0.012408
Sepal.Width 0.52124 0.735261
Petal.Length -0.94726 -0.401038
Petal.Width -0.57516 0.581040
$structure # 構造行列
axis 1 axis 2
Sepal.Length -0.22260 0.31081
Sepal.Width 0.11901 0.86368
Petal.Length -0.70607 0.16770
Petal.Width -0.63318 0.73724
$coeff # 判別係数(生データに対応するもの)
axis 1 axis 2
Sepal.Length 0.82938 0.024102
Sepal.Width 1.53447 2.164521
Petal.Length -2.20121 -0.931921
Petal.Width -2.81046 2.839188
constant 2.10511 -6.661473
$centroids # 各群の重心
axis 1 axis 2
setosa 7.6076 0.21513
versicolor -1.8250 -0.72790
virginica -5.7826 0.51277
$can.score # 各ケースの判別スコア
axis 1 axis 2
case 1 8.06180 0.3004206
case 2 7.12869 -0.7866604
case 3 7.48983 -0.2653845
case 4 6.81320 -0.6706311
case 5 8.13231 0.5144625
【中略】
case 147 -5.17956 -0.3634750
case 148 -4.96774 0.8211405
case 149 -5.88615 2.3450905
case 150 -4.68315 0.3320338
$p.Bayes # 各ケースが各群に所属するベイズ確率
setosa versicolor virginica
case 1 1.0000e+00 3.8964e-22 2.6112e-42
case 2 1.0000e+00 7.2180e-18 5.0421e-37
case 3 1.0000e+00 1.4638e-19 4.6759e-39
case 4 1.0000e+00 1.2685e-16 3.5666e-35
case 5 1.0000e+00 1.6374e-22 1.0826e-42
【中略】
case 147 4.6166e-36 5.8988e-03 9.9410e-01
case 148 5.5490e-35 3.1459e-03 9.9685e-01
case 149 1.6137e-40 1.2575e-05 9.9999e-01
case 150 2.8580e-33 1.7542e-02 9.8246e-01
$p # ケースがそれぞれの群に属するとしたとき,その判別値をとる確率
setosa versicolor virginica
case 1 9.9469e-01 1.7650e-20 2.2729e-40
case 2 8.7264e-01 1.6010e-16 2.3190e-35
case 3 9.9309e-01 5.7625e-18 3.6980e-37
case 4 8.4147e-01 2.3946e-15 1.4239e-33
case 5 9.8525e-01 7.0052e-21 8.8231e-41
【中略】
case 147 2.1872e-34 2.2556e-02 8.8926e-01
case 148 3.0565e-33 1.5412e-02 9.4386e-01
case 149 2.8248e-39 3.2602e-05 4.9821e-01
case 150 1.1969e-31 5.4196e-02 8.7125e-01
$classification # 分類された群
[1] setosa setosa setosa setosa setosa setosa setosa setosa setosa
[10] setosa setosa setosa setosa setosa setosa setosa setosa setosa
[19] setosa setosa setosa setosa setosa setosa setosa setosa setosa
【中略】
[136] virginica virginica virginica virginica virginica virginica virginica virginica virginica
[145] virginica virginica virginica virginica virginica virginica
Levels: setosa versicolor virginica
$group # 実際の群
[1] setosa setosa setosa setosa setosa setosa setosa setosa setosa
[10] setosa setosa setosa setosa setosa setosa setosa setosa setosa
[19] setosa setosa setosa setosa setosa setosa setosa setosa setosa
【中略】
[136] virginica virginica virginica virginica virginica virginica virginica virginica virginica
[145] virginica virginica virginica virginica virginica virginica
Levels: setosa versicolor virginica
$ngroup # 群の数
[1] 3
$nax # 解の数
[1] 2
> plot(result, xpos="top")
plot メソッドにより,判別図を描くことができる
(主成分分析の結果と比較してみよ)
二群判別の場合
> ( result2 <- candis(iris[51:150, 1:4], iris[51:150, 5]) )
判別係数
axis 1
Sepal.Length 0.94312
Sepal.Width 1.47943
Petal.Length -1.84845
Petal.Width -3.28473
constant 4.41899
判別結果
classification
group versicolor virginica
versicolor 48 2
virginica 1 49
> plot(result2)
> plot(result2, which="barplot", nclass=40, args.legend=list(x="top"))
解説ページ
直前のページへ戻る
E-mail to Shigenobu AOKI