主成分分析     Last modified: Aug 02, 2009

目的

主成分分析を行う。
R には,princomp および prcomp という,二種類の関数が用意されている。
しかし,これらが返す「loadings」は固有ベクトルそのものであって,いわゆる負荷量ではない。
そこで,princomp2prcomp2 という関数を書いたので,そちらも参照してみるとよい。

使用法

pca(dat)
print.pca(obj, npca=NULL, digits=3)
summary.pca(obj, digits=5)
plot.pca(obj, which=c("loadings", "scores"), pc.no=c(1,2), ax=TRUE, label.cex=0.6, ...)

引数

dat  データフレームまたはデータ行列(行がケース,列が変数)

obj        pca が返すオブジェクト
npca       表示する主成分数
digits     結果の表示桁数

which      主成分負荷量か主成分得点か
pc.no      描画する主成分番号
ax         座標軸を描き込むかどうか
label.cex  主成分負荷量のプロットのラベルのフォントサイズ
...        plot に引き渡す引数

ソース

インストールは,以下の 1 行をコピーし,R コンソールにペーストする
source("http://aoki2.si.gunma-u.ac.jp/R/src/pca.R", encoding="euc-jp")

# 主成分分析
pca <- function(dat)                                 # データ行列
{
        if (is.null(rownames(dat))) rownames(dat) <- paste("#", 1:nrow(dat), sep="")
        dat <- subset(dat, complete.cases(dat))              # 欠損値を持つケースを除く
        nr <- nrow(dat)                                      # サンプルサイズ
        nc <- ncol(dat)                                      # 変数の個数
        if (is.null(colnames(dat))) {
                colnames(dat) <- paste("X", 1:nc, sep="")
        }
        vname <- colnames(dat)
        heikin <- colMeans(dat)                              # 各変数の平均値
        bunsan <- apply(dat, 2, var)                 # 各変数の不偏分散
        sd <- sqrt(bunsan)                           # 各変数の標準偏差
        r <-cor(dat)                                 # 相関係数行列
        result <- eigen(r)                           # 固有値・固有ベクトルを求める
        eval <- result$values                                # 固有値
        evec <- result$vectors                               # 固有ベクトル
        contr <- eval/nc*100                         # 寄与率(%)
        cum.contr <- cumsum(contr)                   # 累積寄与率(%)
        fl <- t(sqrt(eval)*t(evec))                  # 主成分負荷量
        fs <- scale(dat)%*%evec*sqrt(nr/(nr-1))              # 主成分得点
        names(heikin) <- names(bunsan) <- names(sd) <-
                rownames(r) <- colnames(r) <- rownames(fl) <- colnames(dat)
        names(eval) <- names(contr) <- names(cum.contr) <-
                colnames(fl) <- colnames(fs) <- paste("PC", 1:nc, sep="")
        return(structure(list(mean=heikin, variance=bunsan,
                        standard.deviation=sd, r=r,
                        factor.loadings=fl, eval=eval,
                        contribution=contr,
                        cum.contribution=cum.contr, fs=fs), class="pca"))
}
# print メソッド
print.pca <- function(       obj,                            # pca が返すオブジェクト
                        npca=NULL,                      # 表示する主成分数
                        digits=3)                       # 結果の表示桁数
{
        eval <- obj$eval
        nv <- length(eval)
        if (is.null(npca)) {
                npca <- sum(eval >= 1)
        }
        eval <- eval[1:npca]
        cont <- eval/nv
        cumc <- cumsum(cont)
        fl <- obj$factor.loadings[, 1:npca, drop=FALSE]
        rcum <- rowSums(fl^2)
        vname <- rownames(fl)
        max.char <- max(nchar(vname), 12)
        fmt1 <- sprintf("%%%is", max.char)
        fmt2 <- sprintf("%%%is", digits+5)
        fmt3 <- sprintf("%%%i.%if", digits+5, digits)
        cat("\n主成分分析の結果\n\n")
        cat(sprintf(fmt1, ""),
            sprintf(fmt2, c(sprintf("PC%i", 1:npca), "  Contribution")), "\n", sep="", collapse="")
        for (i in 1:nv) {
                cat(sprintf(fmt1, vname[i]),
                    sprintf(fmt3, c(fl[i, 1:npca], rcum[i])),
                    "\n", sep="", collapse="")
        }
        cat(sprintf(fmt1, "Eigenvalue"),   sprintf(fmt3, eval[1:npca]), "\n", sep="", collapse="")
        cat(sprintf(fmt1, "Contribution"), sprintf(fmt3, cont[1:npca]), "\n", sep="", collapse="")
        cat(sprintf(fmt1, "Cum.contrib."), sprintf(fmt3, cumc[1:npca]), "\n", sep="", collapse="")
        
}
# summary メソッド
summary.pca <- function(obj,                         # pca が返すオブジェクト
                        digits=5)                       # 結果の表示桁数
{
        print.default(obj, digits=digits)
}
# plot メソッド
plot.pca <- function(        obj,                            # pca が返すオブジェクト
                        which=c("loadings", "scores"),  # 主成分負荷量か主成分得点か
                        pc.no=c(1,2),                   # 描画する主成分番号
                        ax=TRUE,                        # 座標軸を描き込むかどうか
                        label.cex=0.6,                  # 主成分負荷量のプロットのラベルのフォントサイズ
                        ...)                            # plot に引き渡す引数
{
        which <- match.arg(which)
        if (which == "loadings") {
                d <- obj$factor.loadings
        }
        else {
                d <- obj$fs
        }
        label <- sprintf("第%i主成分", pc.no)
        plot(d[, pc.no[1]], d[, pc.no[2]], xlab=label[1], ylab=label[2], ...)
        if (which == "loadings") {
                text(d[, pc.no[1]], d[, pc.no[2]], rownames(obj$factor.loadings), pos=1, cex=label.cex)
        }
        abline(h=0, v=0)
}


使用例

> set.seed(123)
> x <- matrix(rnorm(1000), 100)
> colnames(x) <- paste("X", 1:10, sep="")
> a <- pca(x)
> print(a) # print メソッドによる出力

主成分分析の結果

                 PC1     PC2     PC3     PC4     PC5  Contribution
          X1   0.517   0.477  -0.052   0.047  -0.187   0.535
          X2  -0.068  -0.010  -0.443  -0.643   0.328   0.722
          X3  -0.306  -0.251  -0.289   0.069   0.467   0.462
          X4   0.513  -0.579   0.179  -0.186   0.168   0.694
          X5  -0.502  -0.309   0.474  -0.063  -0.432   0.763
          X6  -0.337   0.125   0.410  -0.669   0.004   0.744
          X7  -0.037  -0.158  -0.525  -0.125  -0.529   0.598
          X8   0.557   0.214   0.200  -0.424  -0.107   0.587
          X9  -0.181   0.520   0.330   0.150   0.382   0.580
         X10   0.371  -0.461   0.327   0.136   0.186   0.510
  Eigenvalue   1.477   1.290   1.239   1.143   1.047
Contribution   0.148   0.129   0.124   0.114   0.105
Cum.contrib.   0.148   0.277   0.401   0.515   0.620

> plot(a) # plot メソッドにより,以下のような図を描くことができる

graph

> summary(a) # summary メソッドは,すべての結果を表示する

$mean # 平均値
       X1        X2        X3        X4        X5        X6        X7        X8        X9       X10 
 0.090406 -0.107547  0.120465 -0.036223  0.105851 -0.042300 -0.149644  0.105874  0.093590 -0.019193 

$variance # 分散
     X1      X2      X3      X4      X5      X6      X7      X8      X9     X10 
0.83323 0.93506 0.90227 1.07907 0.97881 0.88121 1.05727 1.02012 1.10630 1.04108 

$standard.deviation # 標準偏差
     X1      X2      X3      X4      X5      X6      X7      X8      X9     X10 
0.91282 0.96699 0.94988 1.03878 0.98935 0.93873 1.02824 1.01001 1.05181 1.02033 

$r # 相関係数行列
           X1        X2         X3        X4         X5        X6          X7          X8        X9
X1   1.000000 -0.049532 -0.1291760 -0.044079 -0.1927111 -0.056484 -0.03436677  0.18157297 -0.022603
X2  -0.049532  1.000000  0.0305790  0.043833 -0.1306222  0.114488  0.07811288 -0.03312350 -0.045328
X3  -0.129176  0.030579  1.0000000 -0.044866 -0.0248484  0.018210  0.00868518 -0.11502946 -0.053282
X4  -0.044079  0.043833 -0.0448657  1.000000 -0.0192599 -0.089913 -0.06378733  0.16789328 -0.165068
X5  -0.192711 -0.130622 -0.0248484 -0.019260  1.0000000  0.206618 -0.00650252 -0.14065351 -0.039583
X6  -0.056484  0.114488  0.0182101 -0.089913  0.2066177  1.000000 -0.06469260  0.09415014  0.074363
X7  -0.034367  0.078113  0.0086852 -0.063787 -0.0065025 -0.064693  1.00000000  0.00026531 -0.128910
X8   0.181573 -0.033123 -0.1150295  0.167893 -0.1406535  0.094150  0.00026531  1.00000000 -0.000812
X9  -0.022603 -0.045328 -0.0532819 -0.165068 -0.0395835  0.074363 -0.12891005 -0.00081201  1.000000
X10  0.011005 -0.091490 -0.0144420  0.245212 -0.0160433 -0.025055 -0.02046957  0.02425240 -0.022721
          X10
X1   0.011005
X2  -0.091490
X3  -0.014442
X4   0.245212
X5  -0.016043
X6  -0.025055
X7  -0.020470
X8   0.024252
X9  -0.022721
X10  1.000000

$factor.loadings # 主成分負荷量
          PC1       PC2       PC3       PC4        PC5       PC6       PC7       PC8       PC9
X1   0.517278  0.476861 -0.052369  0.046502 -0.1869609  0.285421 -0.077013  0.489319  0.368549
X2  -0.068118 -0.010183 -0.443158 -0.642999  0.3283064 -0.345063 -0.136811  0.220083  0.141827
X3  -0.305558 -0.251422 -0.288849  0.068673  0.4666195  0.664353  0.214749 -0.061908  0.209696
X4   0.513138 -0.579260  0.178953 -0.186259  0.1683695 -0.116629 -0.173785 -0.209851  0.331968
X5  -0.502346 -0.308797  0.473858 -0.063168 -0.4317162  0.033310 -0.114150  0.041986  0.371840
X6  -0.336515  0.124599  0.409766 -0.668959  0.0036195  0.206013  0.166547  0.221193 -0.161331
X7  -0.036841 -0.158350 -0.525102 -0.125233 -0.5292793 -0.137064  0.581665 -0.073112  0.141855
X8   0.557055  0.213936  0.200370 -0.423696 -0.1074629  0.266109  0.181577 -0.454372 -0.060737
X9  -0.181014  0.519696  0.330143  0.149726  0.3820022 -0.351764  0.390861 -0.180442  0.330547
X10  0.371304 -0.460744  0.327348  0.135656  0.1861430 -0.105584  0.471437  0.441483 -0.150436
         PC10
X1  -0.050095
X2   0.267016
X3   0.047445
X4  -0.328692
X5   0.288470
X6  -0.332676
X7  -0.139382
X8   0.314292
X9  -0.038484
X10  0.196728

$eval # 固有値
    PC1     PC2     PC3     PC4     PC5     PC6     PC7     PC8     PC9    PC10 
1.47679 1.29035 1.23907 1.14254 1.04747 0.92354 0.88806 0.82569 0.63012 0.53637 

$contribution # 主成分距率
    PC1     PC2     PC3     PC4     PC5     PC6     PC7     PC8     PC9    PC10 
14.7679 12.9035 12.3907 11.4254 10.4747  9.2354  8.8806  8.2569  6.3012  5.3637 

$cum.contribution # 累積寄与率
    PC1     PC2     PC3     PC4     PC5     PC6     PC7     PC8     PC9    PC10 
 14.768  27.671  40.062  51.487  61.962  71.198  80.078  88.335  94.636 100.000 

$fs # 主成分得点
           PC1       PC2        PC3         PC4        PC5       PC6        PC7         PC8
#1   -1.612555 -0.273815 -1.6185782  1.08688059  0.2832542  1.092703  0.8801606 -0.89722227
#2   -0.843994 -0.182274 -2.2869553  1.11084435  0.8932829  0.327667 -0.5543246  0.25070182
#3    0.043907  1.585518  0.1595640  0.05497306  0.0034773  0.038015  0.6262311  1.70524691
#4   -0.306952  0.515026  1.4935579  0.32611764  1.3911034  0.333032  0.9030307  1.01841905
#5   -0.148867 -0.744177 -0.2274698  2.14464144 -0.9172497 -1.052776  0.6208851  0.73431644
中略
#99  -0.6323143 -0.332812
#100 -0.9801591 -0.419919

attr(,"class")
[1] "pca"


> b <- pca(iris[1:4])
> plot(b, which="scores", col=c("black", "red", "blue")[as.integer(iris[,5])],
+ pch=c(19, 1, 2)[as.integer(iris[,5])]) # 主成分得点の描画

graph正準判別分析の結果と比較してみよ)

・ 解説ページ


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

Made with Macintosh