超初心者向けのRガイド

f. 分割表(クロス表)の作成

Author

SUGINO Isamu, Build with R4.4.1

Published

October 14, 2024

0 全体の構成

二変数の分割表(クロス表)

 調査結果の報告においては,高度な分析をするだけではなく,収集した情報の基本的な集計結果を示す事も重要になる。
しかしRでは,度数分布表(単純集計表などとも呼ばれる)や分割表(連関表,クロス表)について,必要最低限の結果を出力するコマンドが基本で,色々な情報を纏めて提示する為には自分で少し手を加える必要がある。
 以下では,学部学生の演習レヴェルであると便利だと思われる作表方法を紹介する。

模擬データの作成

 以下は,二つの変数(5件法と4件法,NA混じり)を発生させて,それを(敢えて)データ・フレイムにしている。
何故敢えてデータ・フレイムにしているかと言えば,通常社会調査データはcsvファイルでデータを作成し,それをデータ・フレイムとしてRに読み込んで分析するので,それに近い状態を再現する為である。

n <- 125

q01 <- sample(c(1, 2, 3, 4, 5, NA), size=n, replace=T, 
              prob=c(.25, .15, .20, .20, .15, .05))
q02 <- sample(c(1, 2, 3, 4, NA), size=n, replace=T, 
              prob=c(.30, .20, .20, .25, .05))

d01 <- data.frame(q01, q02)

 それぞれの変数にアクセスする為には,d01$q01,d01$q02とする事になる。

二つのカテゴリカル変数の分割表(クロス表)

 社会学でクロス表と呼ぶ事の多い分割表(連関表; contingency table)は二つのカテゴリカル変数の集計表であるが,これを作成するRの関数も table( ) である。table( ) に二つの変数を引数で与えると二変数の分割表になる。一変数の場合と同じく,useNA = オプションを指定しないとNAを除外した表になる。
 table( ) で作成した分割表は表の本体だけであるが,集計結果を示す場合には,行周辺度数・列周辺度数なども併せて表示する。
table( ) で作成された分割表が t01 と云うオブジェクトに格納されているとすると,周辺度数を付加した表は,addmargins( ) 関数にt01を引数として与えれば作成される。
 大抵の場合,度数ではなく相対度数の表も作成したい。関数は一変数の時と同じ prop.table( ) 関数である。
何もオプションを付けないと全体%の表になり,margin = 1 と云うオプションを付けると行%の表になる。margin = 2 では列%の表である。

オブジェクト名は適当であり,自由に付けてよい。

table(d01$q01, d01$q02)
   
     1  2  3  4
  1  3  7 12 10
  2  4  4  3  7
  3  6  3  5  4
  4 11  2  7  7
  5  5  1  3  7
table(d01$q01, d01$q02, useNA = "ifany")
      
        1  2  3  4 <NA>
  1     3  7 12 10    2
  2     4  4  3  7    0
  3     6  3  5  4    3
  4    11  2  7  7    1
  5     5  1  3  7    4
  <NA>  2  0  1  1    0
prop.table(table(d01$q01, d01$q02), margin = 1)
   
             1          2          3          4
  1 0.09375000 0.21875000 0.37500000 0.31250000
  2 0.22222222 0.22222222 0.16666667 0.38888889
  3 0.33333333 0.16666667 0.27777778 0.22222222
  4 0.40740741 0.07407407 0.25925926 0.25925926
  5 0.31250000 0.06250000 0.18750000 0.43750000
prop.table(table(d01$q01, d01$q02), margin = 2)
   
             1          2          3          4
  1 0.10344828 0.41176471 0.40000000 0.28571429
  2 0.13793103 0.23529412 0.10000000 0.20000000
  3 0.20689655 0.17647059 0.16666667 0.11428571
  4 0.37931034 0.11764706 0.23333333 0.20000000
  5 0.17241379 0.05882353 0.10000000 0.20000000
prop.table(table(d01$q01, d01$q02))
   
              1           2           3           4
  1 0.027027027 0.063063063 0.108108108 0.090090090
  2 0.036036036 0.036036036 0.027027027 0.063063063
  3 0.054054054 0.027027027 0.045045045 0.036036036
  4 0.099099099 0.018018018 0.063063063 0.063063063
  5 0.045045045 0.009009009 0.027027027 0.063063063
addmargins(table(d01$q01, d01$q02))
     
        1   2   3   4 Sum
  1     3   7  12  10  32
  2     4   4   3   7  18
  3     6   3   5   4  18
  4    11   2   7   7  27
  5     5   1   3   7  16
  Sum  29  17  30  35 111

with( )round( ) を使い,適宜オブジェクト保存してもう少し見易くしよう。

t01  <- with(d01, table(q01, q02)); t01
   q02
q01  1  2  3  4
  1  3  7 12 10
  2  4  4  3  7
  3  6  3  5  4
  4 11  2  7  7
  5  5  1  3  7
t01T <- with(d01, table(q01, q02, useNA = "ifany")); t01T
      q02
q01     1  2  3  4 <NA>
  1     3  7 12 10    2
  2     4  4  3  7    0
  3     6  3  5  4    3
  4    11  2  7  7    1
  5     5  1  3  7    4
  <NA>  2  0  1  1    0
pr01 <- prop.table(t01, margin = 1) # 行比率
round(pr01*100, 1)
   q02
q01    1    2    3    4
  1  9.4 21.9 37.5 31.2
  2 22.2 22.2 16.7 38.9
  3 33.3 16.7 27.8 22.2
  4 40.7  7.4 25.9 25.9
  5 31.2  6.2 18.8 43.8
pc01 <- prop.table(t01, margin = 2) # 列比率
round(pc01*100, 1)
   q02
q01    1    2    3    4
  1 10.3 41.2 40.0 28.6
  2 13.8 23.5 10.0 20.0
  3 20.7 17.6 16.7 11.4
  4 37.9 11.8 23.3 20.0
  5 17.2  5.9 10.0 20.0
ps01 <- prop.table(t01) # 全体比率
round(ps01*100, 1)
   q02
q01    1    2    3    4
  1  2.7  6.3 10.8  9.0
  2  3.6  3.6  2.7  6.3
  3  5.4  2.7  4.5  3.6
  4  9.9  1.8  6.3  6.3
  5  4.5  0.9  2.7  6.3
addmargins( )による周辺度数
t01m <- addmargins(t01)
t01m
     q02
q01     1   2   3   4 Sum
  1     3   7  12  10  32
  2     4   4   3   7  18
  3     6   3   5   4  18
  4    11   2   7   7  27
  5     5   1   3   7  16
  Sum  29  17  30  35 111

集計表の項目ラベル

 SPSSでは変数に変数ラベル,値に値ラベルを定義する事が出来,出力を見易くする事が出来るが,Rはこの点については不親切である。
もっとも特に値ラベルについては,実体としての数値が何であるかが分からなくなって却って初心者が間違える場合もあるので,うまく付けないと(或いは適切に表示オプションを設定しないと)便利ではなくなる。
 いずれにせよRでも出力を分かり易くする方法は知っておいた方が良いので,ここでは分割表にラベルを付ける単純な方法を紹介する。
 まずは模擬データを生成する。

性別と教育年数の架空データでデータ・フレイムを作成

n <- 800
sex    <- sample(c(1, 2, 3), size = n, replace = T, prob = c(.45, .50, .05))
school <- sample(c(9, 12, 14, 16, 18), size = n, replace = T, 
                 prob = c(.10, .30, .15, .40, .05))

演習上,男女で分布が異なる方が例示の役に立つので,男性データに改変を加える。
(ここはやや混み入った操作を行っているので初学者は分からなくても良い,)

.N <- length(school[sex == 1 & school == 14])
school[sex == 1 & school == 14] <-  school[sex == 1 & school == 14] + 
  sample(c(-2, 0, +2), size = .N, replace = T, prob = c(.5, .1, .4))
d02 <- data.frame(ID = 1:n, sex, school)
head(d02)

このデータで,性別の度数分布表や,性別と教育年数の分割表を作成する。

with(d02, addmargins(table(sex)))
sex
  1   2   3 Sum 
363 403  34 800 
with(d02, addmargins(table(sex, school)))
     school
sex     9  12  14  16  18 Sum
  1    49 119   7 170  18 363
  2    33 132  65 155  18 403
  3     4   9   6  14   1  34
  Sum  86 260  78 339  37 800

SPSSの様な変数ラベルや値ラベルがついていないのでこれでは分りにくい。
性別の度数分布表をオブジェクトに格納して,変数値や変数にラベルを付けてみよう。

t10 <- with(d02, table(sex))
rownames(t10) <- c("1 男性", "2 女性", "3 その他")

t10
sex
  1 男性   2 女性 3 その他 
     363      403       34 
names(dimnames(t10)) <- "性別 sex"
t10
性別 sex
  1 男性   2 女性 3 その他 
     363      403       34 

 上と同様にして,分割表の行と列にラベルを付けよう。

分割表の行と列にラベルを付ける
t11 <- with(d02, table(sex, school))
rownames(t11) <- c("1 男性", "2 女性", "3 その他")
colnames(t11) <- c("1 中学", "2 高校", "3 短大", "4 四大", "5 院")
names(dimnames(t11)) <- c("性別 sex", "最終学歴 school")

t11
          最終学歴 school
性別 sex 1 中学 2 高校 3 短大 4 四大 5 院
  1 男性       49    119      7    170   18
  2 女性       33    132     65    155   18
  3 その他      4      9      6     14    1

 変数そのものにラベルを貼り付けるのとは違って集計表の行や列に名前を付けているだけなので,正直このやり方ではいちいち非常に面倒であり,SPSS的な変数ラベル,値ラベルを使いたいと思う事も多いだろう。
しかしそこは逆に,常に値とラベルの対応に注意させられる事で,ラベルに惑わされて実態としての値(数字)を取り違え,処理や解釈を誤ると云うリスクがなくなると前向きに考えておこう(実際初心者がSPSSを使う場合にこのリスクは小さくない)。
Rで変数ラベル,値ラベルを使用可能にする工夫も幾つか開発されているようが,ここでは極力追加アプリケイションや追加パッケイジをインストールしなくて済む方法を紹介しているので,割愛する。

因子型変数を用いてラベルを付ける

 分割表を作成するごとにそれの行や列にラベルを付ける上記のやり方は,同じ変数で沢山の分割表を作成する場合には効率的とは言えない。
 ここでは,数値型変数から,実質的にそれと同じ因子型変数を作り,それで分割表や(下記の)モザイクプロットを表示する方法を推奨する。

数値型変数は小文字の変数名を持っているので,大文字の変数名で対応する因子型変数を作成する方針とする。

d02$SEX <- factor(d02$sex, levels = 1:3, 
                  labels = c("male", "female", "others"))

新変数を作成したら必ず新旧変数の分割表で齟齬が無いかどうかを確認する。

with(d02, table(sex, SEX, useNA = "ifany"))
   SEX
sex male female others
  1  363      0      0
  2    0    403      0
  3    0      0     34
d02$SCHOOL <- factor(d02$school, levels =c(9, 12, 14, 16, 18), 
                     labels = c("JH", "High", "College", "UNIV", "Graduate"))

with(d02, table(school, SCHOOL, useNA = "ifany"))
      SCHOOL
school  JH High College UNIV Graduate
    9   86    0       0    0        0
    12   0  260       0    0        0
    14   0    0      78    0        0
    16   0    0       0  339        0
    18   0    0       0    0       37

因子型変数で分割表を作成する。改めて値ラベルは付けない。

with(d02, table(SEX, SCHOOL, useNA = "ifany"))
        SCHOOL
SEX       JH High College UNIV Graduate
  male    49  119       7  170       18
  female  33  132      65  155       18
  others   4    9       6   14        1

変数のラベルはつかないが,分割表の行と列にラベルを付けなくても,因子型変数のラベルが用いられるので数値だけで表示されるより分かり易い。
同じ質問項目に数値型変数と因子型変数の二つを用意しておくと,場合に応じて使い分けられて便利かも知れない。

分割表をそのまま図示する

分割表をグラフ表示するには,伝統的な帯グラフよりはモザイク・プロットの方が良い。
そうでなければ横に並べた棒グラフだろう。

mosaicplot(t11, col = terrain.colors(dim(t11)[2]))

barplot(t(t11), beside = T, col=terrain.colors(dim(t11)[2]), legend=T)

mosaicplot(t11, shade = T)

複雑なモザイクプロット

因子型変数を用い,オプションを色々と設定した。
最初は複数のオプションを一度に設定するのではなく,一つ一つ追加してそれがどの様な設定を行うのかを確認して理解してから使うこと。

with(d02, 
  mosaicplot(SEX ~ SCHOOL, col = terrain.colors(5),
             las = 1, off = 3, border = "#00000060",
             cex = 1.0,  
             main = "性別と学歴のモザイクプロット",
             sub = "(模擬データによる)",
             xlab = "性別", ylab = "学歴")
)