目的 数量化 I 類による分析を行う。 カテゴリー変数をダミー変数に変換すれば,R に元から備わっている lm 関数で分析することにより本質的に同じ解を得ることができる。 しかも,lm を使えば,実際には自分でダミー変数に変換する必要すらない。 使用法 qt1(dat, group, func.name=c("solve", "ginv")) print.qt1(obj, digits=5) summary.qt1(obj, digits=5) plot.qt1(obj, which=c("category.score", "fitness"), ...) 引数 dat データ行列またはデータ・フレーム 行がケース,列が変数。すべて factor であること y 従属変数 func.name 逆行列を計算する関数名(solve か ginv) 正規方程式が特異行列になる場合以外はどちらを使っても結果は同じ 省略時は solve ムーア・ペンローズ型一般化逆行列を使うときは ginv obj qt1 が返すオブジェクト digits 結果の表示桁数 which カテゴリースコアを描画するなら category.score,観察値と予測値を描画するなら fitness ソース インストールは,以下の 1 行をコピーし,R コンソールにペーストする source("http://aoki2.si.gunma-u.ac.jp/R/src/qt1.R", encoding="euc-jp") # 数量化 I 類 qt1 <- function(dat, # データ行列 y, # 従属変数 func.name=c("solve", "ginv")) # 逆行列を取る関数名の選択 { vname <- colnames(dat) # 変数名 vname.y <- deparse(substitute(y)) cname <- unlist(sapply(dat, levels)) # カテゴリー名 dat <- data.frame(dat, y) dat <- subset(dat, complete.cases(dat)) # 欠損値を持つケースを除く p <- ncol(dat) # 最右端が従属変数,残りはカテゴリー変数 ncat <- p-1 # 最右端が従属変数,残りはカテゴリー変数 stopifnot(all(sapply(dat[, 1:ncat], is.factor))) # 独立変数はすべて factor であること dat[, 1:ncat] <- lapply(dat[ ,1:ncat, drop=FALSE], as.integer) nc <- nrow(dat) # 列数 mx <- sapply(dat[, 1:ncat, drop=FALSE], max) # 各カテゴリー変数の取る値の最大値 start <- c(0, cumsum(mx)[-ncat]) # 延べの順序番号 nobe <- sum(mx) # 延べカテゴリー数 # ダミー変数を使ったデータ行列に変換 x <- t(apply(dat, 1, function(obs) { zeros <- numeric(nobe) zeros[start+obs[1:ncat]] <- 1 c(zeros[-start-1], obs[ncat+1]) } )) # 重回帰分析として解く a <- cov(x) ndim <- nobe-ncat if (match.arg(func.name) == "solve") { inverse <- solve B <- inverse(a[1:ndim, 1:ndim], a[ndim+1, 1:ndim]) } else { library(MASS) inverse <- ginv B <- inverse(a[1:ndim, 1:ndim]) %*% a[ndim+1, 1:ndim] } m <- colMeans(x) const <- m[ndim+1]-sum(B*m[1:ndim]) prediction <- x[,1:ndim]%*%as.matrix(B)+const observed <- x[,ndim+1] prediction <- cbind(observed, prediction, observed-prediction) # 数量化 I 類としての解に変換 ncase <- nrow(dat) s <- colSums(x) name <- coef <- NULL en <- 0 for (i in 1:ncat) { st <- en+1 en <- st+mx[i]-2 target <- st:en temp.mean <- sum(s[target]*B[target])/ncase const <- const+temp.mean coef <- c(coef, -temp.mean, B[target]-temp.mean) } coef <- c(coef, const) names(coef) <- c(paste(rep(vname, mx), cname, sep="."), "定数項") # アイテム変数と従属変数間の偏相関係数 par <- matrix(0, nrow=nc, ncol=ncat) for (j in 1:nc) { en <- 0 for (i in 1:ncat) { st <- en+1 en <- st+mx[i]-2 target <- st:en par[j, i] <- crossprod(x[j, target], B[target]) } } par <- cbind(par, observed) r <- cor(par) print(vname) i <- inverse(r) d <- diag(i) partial.cor <- (-i/sqrt(outer(d, d)))[ncat+1, 1:ncat] partial.t <- abs(partial.cor)*sqrt((nc-ncat-1)/(1-partial.cor^2)) partial.p <- pt(partial.t, nc-ncat-1, lower.tail=FALSE)*2 partial <- cbind(partial.cor, partial.t, partial.p) coef <- as.matrix(coef) colnames(coef) <- "カテゴリースコア" colnames(prediction) <- c("観察値", "予測値", "残差") colnames(partial) <- c("偏相関係数", "t 値", "P 値") rownames(prediction) <- paste("#", 1:nc, sep="") rownames(partial) <- vname rownames(r) <- colnames(r) <- c(vname, vname.y) return(structure(list(coefficients=as.matrix(coef), r=r, partial=partial, prediction=prediction), class="qt1")) } # print メソッド print.qt1 <- function( obj, # qt1 が返すオブジェクト digits=5) # 結果の表示桁数 { print(round(obj$coefficients, digits=digits)) } # summary メソッド summary.qt1 <- function(obj, # qt1 が返すオブジェクト digits=5) # 結果の表示桁数 { print.default(obj, digits=digits) } # plot メソッド plot.qt1 <- function( obj, # qt1 が返すオブジェクト which=c("category.score", "fitness"), # カテゴリースコアを表示するか観察値と予測値を表示するかの選択 ...) # barplot, plot に引き渡す引数 { if (match.arg(which) == "category.score") { coefficients <- obj$coefficients[-length(obj$coefficients),] coefficients <- rev(coefficients) cname <- names(coefficients) names(coefficients) <- NULL barplot(coefficients, horiz=TRUE, xlab="カテゴリースコア", ...) text(0, 1.2*(1:length(cname)-0.5), cname, pos=ifelse(coefficients > 0, 2, 4)) } else { result <- obj$prediction plot(result[, 2], result[, 1], xlab="予測値", ylab="観察値", asp=1, ...) abline(c(0,1)) } } 使用例 > dat <- data.frame(x1=c(1,3,1,1,2,1,2,1,3,1), x2=c(2,2,2,1,3,3,2,1,2,1), x3=c(2,2,2,1,2,3,2,1,2,2)) > dat[, 1:3] <- lapply(dat, factor) > y <- c(6837,7397,7195,6710,6670,6279,6601,4929,5471,6164) > (a <- qt1(dat, y)) カテゴリースコア x1.1 199.4 x1.2 -215.6 x1.3 -382.6 x2.1 -610.2 x2.2 241.8 x2.3 310.8 x3.1 -195.0 x3.2 149.5 x3.3 -656.5 定数項 6425.3 > summary(a) $coefficients カテゴリースコア x1.1 199.4 x1.2 -215.6 x1.3 -382.6 x2.1 -610.2 x2.2 241.8 x2.3 310.8 x3.1 -195.0 x3.2 149.5 x3.3 -656.5 定数項 6425.3 $r # 相関係数 x1 x2 x3 y x1 1.00000 -0.51066 -0.46318 -0.10328 x2 -0.51066 1.00000 0.16479 0.44059 x3 -0.46318 0.16479 1.00000 0.29052 y -0.10328 0.44059 0.29052 1.00000 $partial 偏相関係数 t 値 P 値 x1 0.30875 0.79512 0.45684 x2 0.50094 1.41777 0.20604 x3 0.35840 0.94035 0.38333 $prediction 観察値 予測値 残差 #1 6837 7016.0 -179.0 #2 7397 6434.0 963.0 #3 7195 7016.0 179.0 #4 6710 5819.5 890.5 #5 6670 6670.0 0.0 #6 6279 6279.0 0.0 #7 6601 6601.0 0.0 #8 4929 5819.5 -890.5 #9 5471 6434.0 -963.0 #10 6164 6164.0 0.0 attr(,"class") [1] "qt1" > plot(a) > plot(a, which="fitness", pch=19)
lm を使って分析する手順 > dat2 <- data.frame(dat, y) > result <- lm(y ~ x1+x2+x3, data=dat2) > summary(result) Call: lm(formula = y ~ x1 + x2 + x3, data = dat2) Residuals: 1 2 3 4 5 6 7 8 9 -1.790e+02 9.630e+02 1.790e+02 8.905e+02 -7.105e-14 -8.527e-14 1.563e-13 -8.905e+02 -9.630e+02 10 -8.527e-14 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 5819.5 764.3 7.614 0.0047 ** x12 -415.0 1323.8 -0.313 0.7744 x13 -582.0 1080.9 -0.538 0.6276 x22 852.0 1323.8 0.644 0.5656 x23 921.0 2022.1 0.455 0.6797 x32 344.5 1323.8 0.260 0.8115 x33 -461.5 2416.9 -0.191 0.8608 --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 1081 on 3 degrees of freedom Multiple R-squared: 0.3151, Adjusted R-squared: -1.055 F-statistic: 0.23 on 6 and 3 DF, p-value: 0.9402 予測値は以下のようになっている(qt1 による予測値と同じ) 1 2 3 4 5 6 7 8 9 10 7016.0 6434.0 7016.0 5819.5 6670.0 6279.0 6601.0 5819.5 6434.0 6164.0 数量化 I 類の表現に導くには,以下のようにする。 元のデータの第 1 列の反応例数は > xtabs(~dat$x1) dat$x1 1 2 3 6 2 2 x1=2, x=3 の例数とそれに対応する係数の積和を求め全例数(6+2+2)で割ると平均スコアになる。 > sum(xtabs(~dat$x1)[2:3]*result$coefficients[2:3])/length(dat$x1) [1] -199.4 これは,x1=1 のときを 0 としたときの平均スコアなので,平均スコアが 0 になるようにするには, -199.4 だけスコアを小さくしてやればよい(今の場合は,199.4 大きくするということ)。 すなわち,x1=1,x1=2,x1=3 に対応するカテゴリースコアは (0, -415, -582) のそれぞれから -199.4 を引けばよい。 最初の数値が,fd11 に対応するカテゴリースコア。 > c(0, result$coefficients[2:3])-(-199.4) x12 x13 199.4 -215.6 -382.6 これを全てのアイテム変数について行い,最後に定数項の調整をする。 x1,x2,x3 について,カテゴリースコアを計算するために調整した数値の和は, 199.4-610.2-195.0 = -605.8 これを定数項で調整するため, 5819.5-(-605.8) = 6425.3
名義尺度変数を単純に 0/1 変数に変換しただけでは,冗長性があるので, 普通は問題が生じるが,R では一応ちゃんと答えを出すことができる。 以下の make.dummy 関数などにより,0/1 データに直す インストールは,以下の 1 行をコピーし,R コンソールにペーストする source("http://aoki2.si.gunma-u.ac.jp/R/src/make.dummy.R", encoding="euc-jp") # アイテムデータをカテゴリーデータに変換する make.dummy <- function(dat) { ncat <- ncol(dat) dat[, 1:ncat] <- lapply(dat, function(x) { if (is.factor(x)) { return(as.integer(x)) } else { return(x) } }) mx <- sapply(dat, max) start <- c(0, cumsum(mx)[1:(ncat-1)]) nobe <- sum(mx) t(apply(dat, 1, function(obs) 1:nobe %in% (start+obs))) + 0 } > d <- make.dummy(dat[,1:3]) > d Cat-1-1 Cat-1-2 Cat-1-3 Cat-2-1 Cat-2-2 Cat-2-3 Cat-3-1 Cat-3-2 Cat-3-3 [1,] 1 0 0 0 1 0 0 1 0 [2,] 0 0 1 0 1 0 0 1 0 [3,] 1 0 0 0 1 0 0 1 0 [4,] 1 0 0 1 0 0 1 0 0 [5,] 0 1 0 0 0 1 0 1 0 [6,] 1 0 0 0 0 1 0 0 1 [7,] 0 1 0 0 1 0 0 1 0 [8,] 1 0 0 1 0 0 1 0 0 [9,] 0 0 1 0 1 0 0 1 0 [10,] 1 0 0 1 0 0 0 1 0 > summary(lm(y ~ d)) Call: lm(formula = y ~ d) Residuals: 1 2 3 4 5 6 7 8 9 10 -1.790e+02 9.630e+02 1.790e+02 8.905e+02 2.668e-13 -4.296e-13 -3.017e-13 -8.905e+02 -9.630e+02 -3.443e-13 Coefficients: (3 not defined because of singularities) Estimate Std. Error t value Pr(>|t|) (Intercept) 5697.0 1528.6 3.727 0.0336 * dCat-1-1 582.0 1080.9 0.538 0.6276 dCat-1-2 167.0 1323.8 0.126 0.9076 dCat-1-3 NA NA NA NA dCat-2-1 -921.0 2022.1 -0.455 0.6797 dCat-2-2 -69.0 1528.6 -0.045 0.9668 dCat-2-3 NA NA NA NA dCat-3-1 461.5 2416.9 0.191 0.8608 dCat-3-2 806.0 2022.1 0.399 0.7169 dCat-3-3 NA NA NA NA --- Signif. codes: 0 `***' 0.001 `**' 0.01 `*' 0.05 `.' 0.1 ` ' 1 Residual standard error: 1081 on 3 degrees of freedom Multiple R-Squared: 0.3151, Adjusted R-squared: -1.055 F-statistic: 0.23 on 6 and 3 DF, p-value: 0.9402 解説ページ