数量化 II 類 Last modified: Sep 24, 2009
目的
数量化 II 類を行う
使用法
qt2(dat, group)
print.qt2(obj, digits=5)
summary.qt2(obj, digits=5)
plot.qt2(obj, i=1, j=2, xlab=colnames(obj$category.score)[i], ylab=colnames(obj$category.score)[j],
pch=1:obj$ng, col=1:obj$ng, xpos="topright", ypos=NULL,
which=c("boxplot", "barplot", "category.score"), nclass=20, ...)
引数
dat データ行列(行がケース,列が変数)
データは,アイテム変数も factor であること
数値でも良いが,factor にすること
group 最終列が群を表す変数
obj qt2 関数が返すオブジェクト
digits 結果の表示桁数
ソース
インストールは,以下の 1 行をコピーし,R コンソールにペーストする
source("http://aoki2.si.gunma-u.ac.jp/R/src/qt2.R", encoding="euc-jp")
# 数量化 II 類
qt2 <- function(dat, # データ行列(アイテムデータ)
group) # 群変数
{
geneig <- function(a, b) # 一般化固有値問題を解く関数
{
a <- as.matrix(a)
b <- as.matrix(b)
if (nrow(a) == 1) {
res <- list(values=as.vector(a/b), vectors=as.matrix(1))
}
else {
res <- eigen(b)
g <- diag(1/sqrt(res$values))
v <- res$vectors
res <- eigen(g %*% t(v) %*% a %*% v %*% g)
res$vectors <-v %*% g %*% res$vectors
}
return(res)
}
ok <- complete.cases(dat, group)
dat <- subset(dat, ok) # 欠損値を持つケースを除く
group <- group[ok]
stopifnot(all(sapply(dat, is.factor), is.factor(group)))# データは全て factor であること
nc <- nrow(dat) # ケース数
item <- ncol(dat) # アイテム変数の数
n <- as.vector(table(group)) # 各群のケース数
ng <- length(n) # 群の数
vname <- colnames(dat) # 変数名
cname <- unlist(sapply(dat, levels)) # カテゴリー名
gname <- levels(group) # 群の名前
dat <- data.frame(dat, group)
dat[,1:(item+1)] <- lapply(dat, as.integer)
cat <- sapply(dat, max) # 各アイテム変数の最大値
junjo <- c(0, cumsum(cat))[1:(item+1)] # ダミー変数に変換するときに使う,アイテム変数の位置情報
nobe2 <- sum(cat) # 群変数も含めた延べカテゴリー数
nobe <- nobe2-ng # アイテム変数だけの延べカテゴリー数
dat2 <- t(apply(dat, 1, # 群変数も含めて,ダミー変数に変換する
function(obs)
{
zeros <- numeric(nobe2)
zeros[junjo+obs] <- 1
zeros
}
))
a2 <- array(apply(dat2, 1, function(i) outer(i, i)), # クロス集計表を作る準備
dim=c(nobe2, nobe2, nc))
x <- apply(a2, 1:2, sum) # 3 次元配列に対して合計をとる
pcros <- x[1:nobe, 1:nobe] # アイテム変数同士のクロス集計
gcros <- x[(nobe+1):nobe2, 1:nobe] # 群変数とアイテム変数間のクロス集計
w <- outer(n, n)/nc
diag(w) <- 0
grgr <- diag(n-n^2/nc)-w
w <- diag(pcros)
grpat <- gcros-outer(n, w)/nc
pat <- pcros-outer(w, w)/nc
select <- (junjo+1)[1:item] # 冗長な行の添え字
pat <- pat[-select, -select] # 冗長性を排除した行列
grpat <- grpat[-1, -select, drop=FALSE] # 冗長性を排除した行列
r <- grgr[-1, -1, drop=FALSE] # 冗長性を排除した行列
ndim <- ng-1 # 得られる解の数
m <- ncol(pat) # 行列の大きさ
pat <- solve(pat) # 逆行列を求める
c <- grpat%*%pat%*% matrix(t(grpat), nrow=m, ncol=ndim)
w <- geneig(c, r) # 一般化固有値問題を解く
val <- w$values # 固有値
vec <- w$vectors # 固有ベクトル
w <- t(t(pat%*%t(grpat)%*%vec)/sqrt(val))
a <- matrix(0, nrow=nobe, ncol=ndim) # カテゴリースコア
ie <- 0
for (j in 1:item) {
is <- ie+1
ie <- is+cat[j]-2
offset <- junjo[j]+2
a[offset:(offset+ie-is),] <- w[is:ie,]
}
w <- diag(pcros)*a
for (j in 1:item) {
is <- junjo[j]+1
ie <- is+cat[j]-1
s <- colSums(w[is:ie,, drop=FALSE])/nc
a[is:ie,] <- t(t(a[is:ie,])-s)
}
a <- a/sqrt(diag(t(a) %*% pcros %*% a)/nc)
sample.score <- dat2[,1:nobe] %*% a # サンプルスコア
centroid <- n*rbind(0, vec) # 各群の重心
centroid <- t(t(rbind(0, vec))-colSums(centroid)/nc)
centroid <- t(t(centroid)/sqrt(colSums(centroid^2*n)/nc/val))
item1 <- item + 1 # 外的基準との偏相関係数
partial.cor <- matrix(0, item, ndim)
for (l in 1:ndim) {
pat <- matrix(0, item1, item1)
pat[1, 1] <- sum(n*centroid[, l]^2)
temp <- rowSums(a[, l]*t(gcros*centroid[, l]))
pat[1, 2:(item+1)] <- mapply(function(is, ie) sum(temp[is:ie]), junjo[-item1]+1, junjo[-item1]+cat[-item1])
temp <- outer(a[, l], a[, l])*pcros
for (i in 1:item) {
is <- junjo[i]+1
ie <- is+cat[i]-1
for (j in 1:i) {
pat[j+1, i+1] <- sum(temp[is:ie, (junjo[j]+1):(junjo[j]+cat[j])])
}
}
d <- diag(pat)
pat <- pat/sqrt(outer(d, d))
pat <- pat+t(pat)
diag(pat) <- 1
pat <- solve(pat)
partial.cor[, l] <- -pat[2:item1, 1]/sqrt(pat[1, 1]*diag(pat)[-1])
}
dim(val) <- c(1, ndim)
rownames(a) <- paste(rep(vname, cat[1:item]), cname, sep=".")
rownames(partial.cor) <- vname
rownames(centroid) <- gname
rownames(sample.score) <- paste("#", 1:nc, sep="")
rownames(val) <- "Eta"
colnames(val) <- colnames(a) <- colnames(centroid) <- colnames(sample.score) <- colnames(partial.cor) <- paste("解", 1:ndim, sep="")
return(structure(list(ndim=ndim, group=group, ng=ng, category.score=a, partial.cor=partial.cor,
centroid=centroid, eta=val, sample.score=sample.score), class="qt2"))
}
# print メソッド
print.qt2 <- function( obj, # qt2 が返すオブジェクト
digits=5) # 結果の表示桁数
{
cat("\nカテゴリー・スコア\n\n")
print(round(obj$category.score, digits=digits))
}
# summary メソッド
summary.qt2 <- function(obj, # qt2 が返すオブジェクト
digits=5) # 結果の表示桁数
{
print.default(obj, digits=digits)
}
# plot メソッド
plot.qt2 <- function(obj, # qt2 が返すオブジェクト
i=1, # カテゴリースコアを描画するときの対象次元,三群以上の判別図のときの横軸に対する次元
j=2, # 三群以上の判別図のときの縦軸に対する次元
xlab=colnames(obj$category.score)[i], # 三群以上の判別図の横軸のラベル
ylab=colnames(obj$category.score)[j], # 三群以上の判別図の縦軸のラベル
pch=1:obj$ng, # 三群以上の scatterplot を描く記号
col=1:obj$ng, # 三群以上の scatterplot の記号の色
xpos="topright", ypos=NULL, # 三群以上の scatterplot の凡例の位置
which=c("boxplot", "barplot", "category.score"), # 描画するグラフの種類の指定(三群以上の判別のときはこの指示によらない)
nclass=20, # barplot の階級数
...) # plot, boxplot, barplot に引き渡す引数
{
which <- match.arg(which)
if (which == "category.score") {
cscore <- obj$category.score
cname <- rev(rownames(cscore))
cscore <- rev(cscore[, i])
names(cscore) <- NULL
barplot(cscore, horiz=TRUE, xlab=xlab, ...)
text(0, 1.2*(1:length(cname)-0.5), cname, pos=ifelse(cscore > 0, 2, 4))
}
else {
group <- obj$group
if (obj$ndim > 1) {
group.levels <- levels(group)
sample.score <- obj$sample.score
plot(sample.score[, i], sample.score[, j], xlab=xlab, ylab=ylab, col=col[as.integer(group)], pch=pch[as.integer(group)], ...)
legend(x=xpos, y=ypos, legend=group.levels, col=col, pch=pch)
}
else {
if (which == "boxplot") { # boxplot
plot(obj$sample.score[, i] ~ group, xlab="群", ylab="サンプル・スコア", ...)
}
else if (which == "barplot") { # barplot
tbl <- table(group, cut(obj$sample.score,
breaks=pretty(obj$sample.score, n=nclass)))
barplot(tbl, beside=TRUE, legend=TRUE, xlab="サンプル・スコア", ...)
}
}
}
}
使用例
> x1 <- factor(c("hi", "hi", "hi", "med", "med", "hi", "med", "lo"), levels=c("lo", "med", "hi"))
> x2 <- factor(c("female", "male", "female", "male", "male", "male", "male", "female"), levels=c("male", "female"))
> group <- factor(c("Treatment2", "Treatment1", "Treatment1", "Treatment2", "Treatment1", "Control", "Control", "Control"), levels=c("Treatment2", "Treatment1", "Control"))
> dat <- data.frame(x1=x1, x2=x2)
> a <- qt2(dat, group)
> print(a, digits=3) # 実際には print.qt2 関数が使われる
カテゴリー・スコア
解1 解2
x1.lo -3.141 -0.268
x1.med 0.918 -1.195
x1.hi 0.097 0.963
x2.male -0.713 0.656
x2.female 1.188 -1.093
> summary(a) # summary メソッドでは,qt2 が返すすべての結果を返す
$ndim
[1] 2
$group
[1] Treatment2 Treatment1 Treatment1 Treatment2 Treatment1 Control Control Control
Levels: Treatment2 Treatment1 Control
$ng
[1] 3
$category.score
解1 解2
x1.lo -3.14099318 -0.2676973
x1.med 0.91769402 -1.1952703
x1.hi 0.09697778 0.9633770
x2.male -0.71251496 0.6556084
x2.female 1.18752493 -1.0926807
$partial.cor
解1 解2
x1 0.6302492 0.2398440
x2 0.5138933 0.2038242
$centroid
解1 解2
Treatment2 0.7448409 -0.3344828
Treatment1 0.2913815 0.3166733
Control -0.7879421 -0.0936848
$eta
解1 解2
Eta 0.4033555 0.06886674
$sample.score
解1 解2
#1 1.2845027 -0.1293037
#2 -0.6155372 1.6189855
#3 1.2845027 -0.1293037
#4 0.2051791 -0.5396618
#5 0.2051791 -0.5396618
#6 -0.6155372 1.6189855
#7 0.2051791 -0.5396618
#8 -1.9534682 -1.3603781
attr(,"class")
[1] "qt2"
> str(a) # どのような結果が返されるか見てみる
List of 8
$ ndim : num 2
$ group : Factor w/ 3 levels "Treatment2","Treatment1",..: 1 2 2 1 2 3 3 3
$ ng : int 3
$ category.score: num [1:5, 1:2] -3.141 0.918 0.097 -0.713 1.188 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : chr [1:5] "x1:lo" "x1:med" "x1:hi" "x2:male" ...
.. ..$ : chr [1:2] "解1" "解2"
$ partial.cor : num [1:2, 1:2] -0.118 -0.245 0.143 -0.162
..- attr(*, "dimnames")=List of 2
.. ..$ : chr [1:2] "x1" "x2"
.. ..$ : chr [1:2] "解1" "解2"
$ centroid : num [1:3, 1:2] 0.745 0.291 -0.788 -0.334 0.317 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : chr [1:3] "Treatment2" "Treatment1" "Control"
.. ..$ : chr [1:2] "解1" "解2"
$ eta : num [1, 1:2] 0.4034 0.0689
..- attr(*, "dimnames")=List of 2
.. ..$ : chr "Eta"
.. ..$ : chr [1:2] "解1" "解2"
$ sample.score : num [1:8, 1:2] 1.285 -0.616 1.285 0.205 0.205 ...
..- attr(*, "dimnames")=List of 2
.. ..$ : chr [1:8] "#1" "#2" "#3" "#4" ...
.. ..$ : chr [1:2] "解1" "解2"
- attr(*, "class")= chr "qt2"
> print(a$sample.score) # 個々の要素を書き出すこともできる
解1 解2
#1 1.2845027 -0.1293037
#2 -0.6155372 1.6189855
#3 1.2845027 -0.1293037
#4 0.2051791 -0.5396618
#5 0.2051791 -0.5396618
#6 -0.6155372 1.6189855
#7 0.2051791 -0.5396618
#8 -1.9534682 -1.3603781
グラフの表示
> dat <- iris[1:4]
> dat[1:4] <- lapply(iris[1:4], function(x) {qtile <- quantile(x); qtile[1] <- -Inf; qtile[5] <- Inf; cut(x, breaks=qtile, ordered_result=TRUE, labels=paste("C", 1:4, sep=""))})
> group <- iris[,5]
> ans <- qt2(dat, group)
> plot(ans) # 三群以上のときの判別図(ただし,二次元表示のみ)
> plot(ans, which="category.score", i=2) # カテゴリースコアのグラフ化
> dat <- iris[51:150, 1:4]
> dat[1:4] <- lapply(iris[51:150, 1:4], function(x) {qtile <- quantile(x); qtile[1] <- -Inf; qtile[5] <- Inf; cut(x, breaks=qtile, ordered_result=TRUE, labels=paste("C", 1:4, sep=""))})
> group <- factor(iris[51:150,5], levels=c("versicolor", "virginica"))
> x <- qt2(dat, group)
> plot(x)
> plot(x, which="barplot", nclass=10) # 二群判別のときの判別図
解説ページ
直前のページへ戻る
E-mail to Shigenobu AOKI