判別分析(線形判別関数) Last modified: Aug 27, 2009
目的
線形判別分析を行う。
変数選択を行う場合には「sdis 関数」を使うこと。
(R の MASS パッケージに lda, predict.lda がある)
使用法
disc(data, group, func.name=c("solve", "ginv"))
print.disc(obj, digits=5)
summary.disc(obj, digits=5)
plot.disc(obj, which=c("boxplot", "barplot"), nclass=20, ...)
引数
data データ行列(行がケース,列が変数)
group 各ケースがどの群であるかを表す変数
func.name 逆行列を計算する関数名(solve か ginv)。
普通に逆行列が求まる場合にはどちらを使っても結果は同じ
省略時は solve
ムーア・ペンローズ型一般化逆行列を使うときは ginv
obj disc 関数が返すオブジェクト
digits 結果の表示桁数
which 2 群判別の場合に,描画するグラフの種類
nclass barplot のときのおよその階級数
pch scatterplot を描く記号
col scatterplot の記号の色
xpos, ypos scatterplot の凡例の位置
... boxplot, barplot, scatterplot に引き渡す引数
ソース
インストールは,以下の 1 行をコピーし,R コンソールにペーストする
source("http://aoki2.si.gunma-u.ac.jp/R/src/disc.R", encoding="euc-jp")
# 線形判別関数
disc <- function( data, # データ行列
group, # 群変数
func.name=c("solve", "ginv")) # 逆行列を計算する関数名
{
inverse <- if (match.arg(func.name) == "solve") solve else { library(MASS); ginv}
data <- as.data.frame(data)
if (is.null(colnames(data))) {
colnames(data) <- paste("Var", 1:p, sep="")
}
vname <- colnames(data)
group <- as.factor(as.matrix(group)) # factor にする
gname <- levels(group)
OK <- complete.cases(data, group) # 欠損値を持つケースを除く
data <- as.matrix(data[OK,])
group <- group[OK]
p <- ncol(data) # 説明変数の数
ncase <- nrow(data) # サンプルサイズ
num <- table(group) # 各群のサンプルサイズ
ng <- length(num) # 群の数
g.name <- names(num) # 群の名前
means <- t(matrix(unlist(by(data, group, colMeans)), p))
g.mean <- colMeans(data)
t <- var(data)*(ncase-1) # 分散共分散行列
vars <- by(data, group, function(x) var(x)*(nrow(x)-1)) # 各群の変動・共変動行列
w <- matrix(rowSums(matrix(mapply("+", vars), ncol=ng)), p) # 群内変動・共変動行列
g.sd <- apply(data, 2, sd) # 各変数の標準偏差
det.w <- det(w) # 行列式
det.t <- det(t) # 行列式
wl <- det.w/det.t
inv.w <- inverse(w) # 逆行列
a <- -2*(ncase-ng)*inv.w%*%t(means)
a0 <- rowSums(means%*%inv.w*means)*(ncase-ng)
c.function <- rbind(a, a0)
temp <- matrix(0, nr=ng, nc=ng)
temp1 <- row(temp)
temp1 <- temp1[upper.tri(temp1)]
temp2 <- col(temp)
temp2 <- temp2[upper.tri(temp2)]
d.function <- sapply(1:length(temp1), function(i) (c.function[,temp2[i]]-c.function[,temp1[i]])/2)
F <- diag(inverse(t)/inv.w)
idf1 <- ng-1 # 第一自由度
idf2 <- ncase-idf1-p # 第二自由度
F <- idf2/idf1*(1-F)/F # F 値
P <- pf(F, idf1, idf2, lower.tail=FALSE) # P 値
c1 <- ifelse(p^2+idf1^2 != 5, sqrt((p^2*idf1^2-4)/(p^2+idf1^2-5)), 1)
c2 <- wl^(1/c1)
df1 <- p*idf1
df2 <- (ncase-1-(p+ng)/2)*c1+1-0.5*p*idf1
F.wl <- df2*(1-c2)/(df1*c2)
P.wl <- pf(F.wl, df1, df2, lower.tail=FALSE)
t.data <- t(data)
D2 <- (ncase-ng)*matrix(sapply(1:ng, function(i) {temp <- t.data-means[i,]; sapply(1:ncase, function(j) temp[,j]%*%inv.w%*%temp[,j])}), nr=ncase)
P2 <- pchisq(D2, p, lower.tail=FALSE)
prediction <- as.factor(g.name[apply(P2, 1, order)[ng,]])
correct <- ifelse(prediction == group, TRUE, FALSE)
correct.table <- table(group, prediction)
correct.rate <- sum(diag(correct.table))/ncase*100
factor1 <- levels(group)
factor2 <- levels(prediction)
if (ng ==2) { # 2 群の場合には,判別値を計算
discriminant.value <- data%*%d.function[1:p]+d.function[p+1]
}
else {
discriminant.value <- NULL
}
colnames(c.function) <- paste("g", 1:ng, sep="")
colnames(D2) <- paste("D to", gname)
colnames(P2) <- paste("P to", gname)
colnames(d.function) <- paste(gname[temp1], gname[temp2], sep=":")
rownames(c.function) <- rownames(d.function) <- c(vname, "constant")
colnames(c.function) <- gname
return(structure(list(d.function=d.function, c.function=c.function, partial.F=F, partial.F.P=P, df1=idf1, df2=idf2, wilks.lambda=wl, wilks.lambda.F=F.wl, wilks.lambda.P=P.wl, wilks.lambda.df1=df1, wilks.lambda.df2=df2, distance=D2, P.value=P2, prediction=prediction, correct=correct, correct.table=correct.table, correct.rate=correct.rate, discriminant.value=discriminant.value, group=group, factor1=factor1, factor2=factor2), class="disc"))
}
# print メソッド
print.disc <- function( obj, # disc 関数が返すオブジェクト
digits=5) # 結果の表示桁数
{
cat("\n判別関数\n\n")
result <- cbind(obj$d.function, "Partial F"=c(obj$partial.F, NA), "p-value"=c(obj$partial.F.P, NA))
print.default(round(result, digits=digits), na.print="")
cat("\n分類関数\n\n")
print(round(obj$c.function, digits=digits))
cat("\n判別結果\n\n")
print(obj$correct.table)
cat(sprintf("\n正判別率 = %.1f %%\n", obj$correct.rate))
}
# summary メソッド # すべての結果を表示する
summary.disc <- function( obj, # disc が返すオブジェクト
digits=5) # 結果の表示桁数
{
print.default(obj, digits=digits)
}
# plot メソッド
plot.disc <- function( obj, # disc 関数が返すオブジェクトの
which=c("boxplot", "barplot", "scatterplot"), # 箱髭図か棒グラフか散布図かの選択
nclass=20, # 棒グラフの場合のおよその階級数
pch=1:ncol(obj$distance), # scatterplot を描く記号
col=1:ncol(obj$distance), # scatterplot の記号の色
xpos="topright", ypos=NULL, # scatterplot の凡例の位置
...) # boxplot, barplot, scatterplt に引き渡す引数
{
if (!is.null(obj$discriminant.value)) {
which <- match.arg(which)
if (which == "boxplot") { # boxplot
plot(obj$discriminant.value ~ obj$group, xlab="群", ylab="判別値", ...)
}
else if (which == "barplot") { # barplot
tbl <- table(obj$group, cut(obj$discriminant.value,
breaks=pretty(obj$discriminant.value, n=nclass)))
barplot(tbl, beside=TRUE, legend=TRUE, xlab="判別値", ...)
}
else { # scatterplot 各群の重心までの二乗距離
group <- obj$group
group.levels <- levels(group)
distance1 <- obj$distance[,1]
distance2 <- obj$distance[,2]
max1 <- max(distance1)
max2 <- max(distance2)
max0 <- max(max1, max2)
plot(distance1, distance2, col=col[as.integer(group)], pch=pch[as.integer(group)],
xlim=c(0, max0), xlab=paste(group.levels[1], "の重心への二乗距離"),
ylim=c(0, max0), ylab=paste(group.levels[2], "の重心への二乗距離"), asp=1, ...)
abline(0, 1, lty=2)
text(max1, max2/2, paste(group.levels[2], "に判別される領域"), pos=2)
text(0, max2+strheight("H")*1.5, paste(group.levels[1], "に判別される領域"), pos=4)
legend(x=xpos, y=ypos, legend=group.levels, col=col, pch=pch)
}
}
else {
warning("3群以上の場合にはグラフ表示は用意されていません")
}
}
使用例
> data(iris) # Fisher のアヤメのデータ
print メソッドによる出力
> ( result <- disc(iris[1:4], iris[5]) )
判別関数
setosa:versicolor setosa:virginica versicolor:virginica Partial F p-value
Sepal.Length 7.84596 11.09832 3.25236 4.72115 0.01033
Sepal.Width 16.51536 19.90259 3.38723 21.93593 0.00000
Petal.Length -21.64209 -29.19718 -7.55509 35.59017 0.00000
Petal.Width -23.83264 -38.47752 -14.64488 24.90433 0.00000
constant -13.45586 18.05985 31.51571
分類関数
setosa versicolor virginica
Sepal.Length -47.08833 -31.39642 -24.89170
Sepal.Width -47.17574 -14.14502 -7.37056
Petal.Length 32.86128 -10.42290 -25.53309
Petal.Width 34.79682 -12.86846 -42.15823
constant 170.41972 143.50799 206.53942
判別結果
prediction
group setosa versicolor virginica
setosa 50 0 0
versicolor 0 48 2
virginica 0 1 49
正判別率 = 98.0 %
summary メソッドによる出力
> summary(result)
$d.function # 判別関数
setosa:versicolor setosa:virginica versicolor:virginica
Sepal.Length 7.846 11.098 3.2524
Sepal.Width 16.515 19.903 3.3872
Petal.Length -21.642 -29.197 -7.5551
Petal.Width -23.833 -38.478 -14.6449
constant -13.456 18.060 31.5157
$c.function # 分類関数
setosa versicolor virginica
Sepal.Length -47.088 -31.396 -24.8917
Sepal.Width -47.176 -14.145 -7.3706
Petal.Length 32.861 -10.423 -25.5331
Petal.Width 34.797 -12.868 -42.1582
constant 170.420 143.508 206.5394
$partial.F # 偏 F 値
Sepal.Length Sepal.Width Petal.Length Petal.Width
4.7212 21.9359 35.5902 24.9043
$partial.F.P # 偏 F 値に対する P 値
Sepal.Length Sepal.Width Petal.Length Petal.Width
1.0329e-02 4.8312e-09 2.7562e-13 5.1432e-10
$df1 # 偏 F 値の自由度
[1] 2
$df2 # 偏 F 値の自由度
[1] 144
$wilks.lambda # ウィルクスのΛ
[1] 0.023439
$wilks.lambda.F # ウィルクスのΛと等価な F 値
[1] 199.15
$wilks.lambda.P # ウィルクスのΛと等価な F 値に対する P 値
[1] 1.365e-112
$wilks.lambda.df1 # ウィルクスのΛと等価な F 値の自由度
[1] 8
$wilks.lambda.df2 # ウィルクスのΛと等価な F 値の自由度
[1] 288
$distance # 各ケースから各重心へのマハラノビスの距離の二乗
D to setosa D to versicolor D to virginica
[1,] 0.29109 98.88475 191.78864
[2,] 2.03135 80.97126 169.18698
[3,] 0.55328 87.28938 177.07006
[4,] 2.08670 75.29369 160.72442
[5,] 0.59563 100.92317 193.85404
[6,] 1.94475 95.93997 183.11405
[7,] 1.33369 84.01179 170.05690
[8,] 0.11741 89.51039 179.57534
[9,] 3.85012 71.64100 155.92692
[10,] 1.44194 84.12304 174.43416
中略
[148,] 158.98165 12.75125 1.23422
[149,] 188.87498 28.19287 5.62524
[150,] 153.76185 11.97777 3.92688
$P.value # 各ケースが各群に属する確率
P to setosa P to versicolor P to virginica
[1,] 9.9038e-01 1.6992e-20 2.1874e-40
[2,] 7.2999e-01 1.0845e-16 1.5630e-35
[3,] 9.6811e-01 4.9559e-18 3.1748e-37
[4,] 7.1982e-01 1.7270e-15 1.0223e-33
[5,] 9.6355e-01 6.2560e-21 7.8711e-41
[6,] 7.4592e-01 7.1917e-20 1.5984e-38
[7,] 8.5563e-01 2.4581e-17 1.0168e-35
[8,] 9.9834e-01 1.6730e-18 9.1989e-38
[9,] 4.2667e-01 1.0220e-14 1.0923e-32
[10,] 8.3687e-01 2.3281e-17 1.1686e-36
中略
[148,] 2.4172e-33 1.2557e-02 8.7243e-01
[149,] 9.2478e-40 1.1399e-05 2.2894e-01
[150,] 3.1803e-32 1.7517e-02 4.1599e-01
$prediction # 各ケースがどの群に属するかの判定
[1] setosa setosa setosa setosa setosa setosa setosa setosa
[9] setosa setosa setosa setosa setosa setosa setosa setosa
[17] setosa setosa setosa setosa setosa setosa setosa setosa
[25] setosa setosa setosa setosa setosa setosa setosa setosa
[33] setosa setosa setosa setosa setosa setosa setosa setosa
[41] setosa setosa setosa setosa setosa setosa setosa setosa
[49] setosa setosa versicolor versicolor versicolor versicolor versicolor versicolor
[57] versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor
[65] versicolor versicolor versicolor versicolor versicolor versicolor virginica versicolor
[73] versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor
[81] versicolor versicolor versicolor virginica versicolor versicolor versicolor versicolor
[89] versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor
[97] versicolor versicolor versicolor versicolor virginica virginica virginica virginica
[105] virginica virginica virginica virginica virginica virginica virginica virginica
[113] virginica virginica virginica virginica virginica virginica virginica virginica
[121] virginica virginica virginica virginica virginica virginica virginica virginica
[129] virginica virginica virginica virginica virginica versicolor virginica virginica
[137] virginica virginica virginica virginica virginica virginica virginica virginica
[145] virginica virginica virginica virginica virginica virginica
Levels: setosa versicolor virginica
$correct # 判定が正しいかどうか
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[16] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[31] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[46] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[61] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE
[76] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE
[91] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[106] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[121] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE
[136] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
$correct.table # 判別結果の総括表
prediction
group setosa versicolor virginica
setosa 50 0 0
versicolor 0 48 2
virginica 0 1 49
$correct.ratio # 正判別率
[1] 98
$discriminant.value # 判別値(2 群の判別のときのみ)
NULL
$group # 実際の群
[1] setosa setosa setosa setosa setosa setosa setosa setosa
[9] setosa setosa setosa setosa setosa setosa setosa setosa
[17] setosa setosa setosa setosa setosa setosa setosa setosa
[25] setosa setosa setosa setosa setosa setosa setosa setosa
[33] setosa setosa setosa setosa setosa setosa setosa setosa
[41] setosa setosa setosa setosa setosa setosa setosa setosa
[49] setosa setosa versicolor versicolor versicolor versicolor versicolor versicolor
[57] versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor
[65] versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor
[73] versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor
[81] versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor
[89] versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor
[97] versicolor versicolor versicolor versicolor virginica virginica virginica virginica
[105] virginica virginica virginica virginica virginica virginica virginica virginica
[113] virginica virginica virginica virginica virginica virginica virginica virginica
[121] virginica virginica virginica virginica virginica virginica virginica virginica
[129] virginica virginica virginica virginica virginica virginica virginica virginica
[137] virginica virginica virginica virginica virginica virginica virginica virginica
[145] virginica virginica virginica virginica virginica virginica
Levels: setosa versicolor virginica
$factor1 # group に与えられたデータ
[1] "setosa" "versicolor" "virginica"
$factor2
[1] "setosa" "versicolor" "virginica"
二群の判別の場合のグラフ表示
> (ans <- disc(iris[51:150, 1:4], iris[51:150, 5]))
判別関数
versicolor:virginica Partial F p-value
Sepal.Length 3.5563 7.3679 7.8862e-03
Sepal.Width 5.5786 10.5875 1.5776e-03
Petal.Length -6.9701 24.1566 3.7035e-06
Petal.Width -12.3860 37.0916 2.3836e-08
constant 16.6631
分類関数
versicolor virginica
Sepal.Length -30.8020 -23.689
Sepal.Width -31.9428 -20.786
Petal.Length 5.1633 -8.777
Petal.Width 1.1729 -23.599
constant 123.8859 157.212
判別結果
prediction
group versicolor virginica
versicolor 48 2
virginica 1 49
正判別率 = 97.0 %
> plot(ans)
> plot(ans, which="barplot", nclass=40, args.legend=list(x="top"))
> plot(ans, which="scatter", xpos="topleft")
解説ページ
直前のページへ戻る
E-mail to Shigenobu AOKI