数量化 I 類     Last modified: Sep 02, 2009

目的

数量化 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)

fig

> plot(a, which="fitness", pch=19)

fig


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 ・ 解説ページ


・ 直前のページへ戻る  ・ E-mail to Shigenobu AOKI

Made with Macintosh