こんにちは、usagi-san です。
今回は集計表及び、ピボットテーブルの作成方法をみていきます。
クロス集計表は、factor型のデータの各levelの度数、和、平均を取り扱う際に便利です。
エクセルではピボットテーブルという機能を用いれば、直感的に簡単に集計表を作成することが可能です。
エクセルで作成した集計表を用いても解析が可能ですが、R言語でもパッケージを用いればピボットテーブルの作成ができます。
今回はピボットテーブルの作成の例として、2元及び3元のテーブルを作成していきます(2元及び3元分割表を作成していきます)。
以下のダウンロードリンクから、今回用いるプログラミンコードをダウンロードできます。
R言語 クロス集計表・ピボットテーブル Rスクリプト
是非是非ダウンロードしてください
また、データフレームの操作をすべてまとめた記事も書きました。データフレームの詳細については次の記事を参照。
【R言語】データフレーム操作 作成・値の代入・行と列の追加と削除など
R言語を使う際に避けては通れない道であるデータフレームの操作について解説します。 データフレーム(data.frame)はデータセットを格納するための行列であり、データ解析をするうえで必要不可欠です。 ...
続きを見る
クロス集計表の作り方
データセットの準備
まずは、クロス集計表(2元の分割表)を作る方法を解説していきます。
R言語にデフォルトで入っているmtcarsという自動車のテストデータセットを例に集計方法を解説していきます。
まず次のコードを実行し、dfにmtcartを代入しましょう。
1 | df <- mtcars #自動車のテストのデータセット |
試しに、dfの列名および、データの構造を確認してみましょう。関数headを用いるとデータフレームの一部を参照することができます。
1 2 3 4 5 6 7 8 | > head(df) mpg cyl disp hp drat wt qsec vs am gear carb Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 |
上の実行結果のように、dfはmpgなどのnumeric型の列とcyl、vs、am、gear、carbといったfactor型の列から成ることが分かります。
factor型のデータを例にいろいろな集計方法をみていきます。
クロス集計表の作成
では、vsとamに関するクロス集計を行います。
df$vsとdf$amのように各2つの列名(タグ)を指定し、次のようにas.factorやlevelsを用いることで、0と1のlevelをもつfactro型のデータであることが分かります(注意: vsとamなどの列のデータはデフォルトだとcharacter型です)。
1 2 3 4 5 6 7 | > as.factor(df$vs) [1] 0 0 1 1 0 1 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 0 1 0 0 0 1 Levels: 0 1 > > as.factor(df$am) [1] 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 Levels: 0 1 |
これら2つの列のクロス集計表を作成する際に、次の表のように4通りの組み合わせを考える必要があります。
vs\am | 0 | 1 |
0 | vs=0かつam=0 | vs=0かつam=1 |
1 | vs=1かつam=0 | vs=1かつam=1 |
度数についてのクロス集計
まず、上の表にある条件式を用いて各セルの度数を計算してみます。
次のようにして、上の表の4通りのパターンを計算することができます。
1 2 3 4 5 | #1. vsとamに関する度数 table_11 <- nrow(df[df$vs == 0 & df$am == 0, ]) #vs=0かつam=0 table_12 <- nrow(df[df$vs == 0 & df$am == 1, ]) #vs=0かつam=1 table_21 <- nrow(df[df$vs == 1 & df$am == 0, ]) #vs=1かつam=0 table_22 <- nrow(df[df$vs == 1 & df$am == 1, ]) #vs=1かつam=1 |
table_11には、vs=0かつam=0の度数が代入されているように、tableの添え字には、線形代数のブロック行列に対応するものとなっています(11の場合、左上の成分。12の場合、右上の成分, . . . )。
次のコードを実行することで、table_11, . . . table_22の各成分を用いてクロス集計表を作成することができます。
1 2 3 | table <- data.frame(c(table_11, table_21), c(table_12, table_22)) rownames(table) <- c(0, 1) colnames(table) <- c(0, 1) |
また、rownames(table)とcolnames(table)をそれぞれc(0, 1)にし、集計表の行名と列名を指定しています。
クロス集計表tableをコンソール上で確認すると、次のようにvsとamの集計表を作成できたことが分かります。
1 2 3 4 | > table #2×2分割表 0 1 0 12 6 1 7 7 |
和についてのクロス集計
次に、列名mpgの各セルの和についてのクロス主計表を作成していきます。
R言語 データフレーム練習【初心者向け】で説明したように、関数sumを用いることで、numeric型のデータの和を計算することができます。
度数の場合と同様に、各4パターンのdf$mpgを考え、関数sumを用いて、それぞれのnumeric型のベクトルの和を求めています。
1 2 3 4 5 | #2. vsとamに関するmpgの和 sumTable_11 <- sum(df$mpg[df$vs == 0 & df$am == 0]) #vs=0かつam=0 sumTable_12 <- sum(df$mpg[df$vs == 0 & df$am == 1]) #vs=0かつam=1 sumTable_21 <- sum(df$mpg[df$vs == 1 & df$am == 0]) #vs=1かつam=0 sumTable_22 <- sum(df$mpg[df$vs == 1 & df$am == 1]) #vs=1かつam=1 |
例として、vs=0かつam=0のとき、関数sumの引数df$mpg[df$vs == 0 & df$am == 0]は次のようになっています。
1 2 3 4 | > df$mpg[df$vs == 0 & df$am == 0] [1] 18.7 14.3 16.4 17.3 15.2 10.4 10.4 14.7 15.5 15.2 13.3 19.2 > length(df$mpg[df$vs == 0 & df$am == 0]) [1] 12 |
2行目では、vs=0かつam=0である行のdf$mpgが 出力されていることが確認できます。
またlengthが12であることは、先ほど計算したvs=0かつam=0の度数と一致しているのもわかります。
度数の場合と同様に、次を実行することで、sumTable_11、sumTable_12、sumTable_21、sumTable_22をクロス集計表にまとめます。
1 2 3 | sumTable <- data.frame(c(sumTable_11, sumTable_21), c(sumTable_12, sumTable_22)) rownames(sumTable) <- c(0, 1) colnames(sumTable) <- c(0, 1) |
コンソール上で、sumTableを確認すると、和に関するクロス集計表ができていることが確認できます。
1 2 3 4 | > sumTable #和の2×2分割表 0 1 0 180.6 118.5 1 145.2 198.6 |
平均についてのクロス集計
最後に、列名mpgの各セルの平均についてのクロス主計表を作成していきます。
各セルの平均は、度数の集計表と和の集計表から計算することができます。
ベクトルや行列、データフレームは各要素についての四則演算が可能であるように、次の割り算/で平均についてのクロス集計表を求めることができます。
1 2 | #3. csとamに関するmpgの平均 meanTable <- sumTable / table #和の各要素を度数の各要素で割る |
コンソール上で、meanTableを参照すると、次の平均についてのクロス集計表ができていることが分かります。
1 2 3 4 | > meanTable #平均の2×2分割表 0 1 0 15.05000 19.75000 1 20.74286 28.37143 |
2元の場合のクロス集計の方法を説明しましたが、実行するとわかるように、factor型のlevelの数が多くなればなるほど、作成が困難になります。
そのため次では、集計用の関数xtabsを用いた集計表の作成の一連の流れを説明します。
xtabsを用いた作成
クロス集計用の関数として、xtabsを紹介します。
先ほどのクロス集計表の作成の例では、各levelsのパターンを考えて1から作成しましたが、xtabsを用いることで、この計算の手間を省くことができます。
xtabsを用いた度数のクロス集計
xtabsを用いて度数についてのクロス集計表を作成するには、xtabsの引数を次のように与えます。
1 2 | #1. vsとamに関する度数 table <- xtabs(~ vs + am, data = df) |
1つ目の引数には式を代入します。今、vsとamの集計表を得たいので"~ vs + am"としています。
2つ目に、集計するデータフレームを代入しています。
tableを参照すると、tableには次のようなint型のリストが格納されているのが分かります。
1 2 3 4 5 | > table am vs 0 1 0 12 6 1 7 7 |
xtabsを用いた和のクロス集計
xtabsを用いて和の集計を行うには、xtabsの最初の引数である式の"~"の前に和を求める列名を指定します。
次のようにxtabsの引数を指定することで、df$mpgの和についての集計表を作成することができます。
1 2 | #2. vsとamに関するmpgの和 sumTable <- xtabs(mpg ~ vs + am, data = df) |
度数の場合と同様に、sumtableには次のようなint型のリストが格納されているのが分かります。
1 2 3 4 5 | > sumTable am vs 0 1 0 180.6 118.5 1 145.2 198.6 |
xtabsを用いた平均のクロス集計
xtabsで出力される度数と和の集計表を用いて、平均のクロス集計表を作成することができます。
次のように、割り算/により平均についてのクロス集計表を作成できます。
1 2 | #3. csとamに関するmpgの平均 meanTable <- sumTable / table |
meanTableには、平均に関するint型のリストが格納されていることがわかります。
1 2 3 4 5 | > meanTable am vs 0 1 0 15.05000 19.75000 1 20.74286 28.37143 |
csvファイルへの出力
xtabsで作成した集計表は、参照するとわかるようにlint型のリストとなっており、集計表の形でのcsvファイルへの出力は難しいです。
行名や列名を結合しなおすことで、集計表の形を維持したままcsvファイルに出力することができます。
まず扱いやすくするために、int型のリストをmatrixに変換します。
1 2 3 | matrixTable <- as.matrix(table) #扱いやすよう行列にする matrixSumTable <- as.matrix(sumTable) matrixMeanTable <- as.matrix(meanTable) |
次のrbindとcbindで、クロス集計表の行名と列名およびvsとamを結合させています。
1 2 3 4 5 6 | table <- cbind(c("", "", "vs", ""), c("", "", rownames(matrixTable)), rbind(c("am", ""), colnames(matrixTable), matrixTable)) sumTable <- cbind(c("", "", "vs", ""), c("", "", rownames(matrixSumTable)), rbind(c("am", ""), colnames(matrixSumTable), matrixSumTable)) meanTable <- cbind(c("", "", "vs", ""), c("", "", rownames(matrixMeanTable)), rbind(c("am", ""), colnames(matrixMeanTable), matrixMeanTable)) |
例として、tableを参照すると、集計表の形をしたデータフレームが作成されていることが確認できます。
1 2 3 4 5 6 | > table 0 1 "" "" "am" "" "" "" "0" "1" 0 "vs" "0" "12" "6" 1 "" "1" "7" "7" |
最後に、csvファイルへの出力には、write.csvではなく、write.tableを用います。
これは、write.csvでは引数col.names = TRUEなどの変更が許されないためです。今、上の実行結果から、tableにはすでに列名が挿入されているのが分かるのでcol.names = Fとしてcsvファイルに出力していきます。
次のようにwrite.tableの引数にrow.names = F や col.names = Fを指定することで、上の出力結果の集計表をcsvファイルを出力することができます。
1 2 3 | write.table(table, "分割表(度数).csv", quote = F, sep = ",", row.names = F, col.names = F) write.table(sumTable, "分割表(和).csv", quote = F, sep = ",", row.names = F, col.names = F) write.table(meanTable, "分割表(平均).csv", quote = F, sep = ",", row.names = F, col.names = F) |
次の画像のように、分割表(度数).csvをみてみると、xtabsで出力した集計表が保存されていることが分かります。
3元以上のクロス集計表
3元以上のクロス集計表の作成
3元以上のクロス集計表を解説していきます。
dfのvsとamとgearを例にクロス集計表を作成してみます。
as.factor(df$gear)を参照してみます。
1 2 3 | > as.factor(df$gear) [1] 4 4 4 3 3 3 3 4 4 4 4 3 3 3 3 3 3 4 4 4 3 3 3 3 3 4 5 5 5 5 5 4 Levels: 3 4 5 |
df$gearは上の3つのlevelsをもつfactor型のデータであることと、クロス集計表の作成からdfのvsとamとgearのクロス集計表は次の12パターンのセルから成る表であることが分かります。
gear | 3 | 4 | 5 | |
vs | am | |||
0 | 0 | vs=0かつam=0かつgear=3 | vs=0かつam=0かつgear=4 | vs=0かつam=0かつgear=5 |
1 | vs=0かつam=1かつgear=3 | vs=0かつam=1かつgear=4 | vs=0かつam=1かつgear=5 | |
1 | 0 | vs=1かつam=0かつgear=3 | vs=1かつam=0かつgear=4 | vs=1かつam=0かつgear=5 |
1 | vs=1かつam=1かつgear=3 | vs=1かつam=1かつgear=4 | vs=1かつam=1かつgear=5 |
クロス集計(3元)
2元の場合と同様に、まずxtabsを用いないでクロス集計表を作ってみます。
上の表にある条件式を用いて各セルの度数を計算してみます。
次のようにして、上の表の12通りのパターンを計算することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #1. vsとamとgearに関する度数 tableList <- NULL #分割表のリストを初期化 sumTableList <- NULL meanTableList <- NULL for(i in 1:nlevels(as.factor(df$gear))){ gearLevels <- levels(as.factor(df$gear)) table_11 <- nrow(df[df$vs == 0 & df$am == 0 & df$gear == gearLevels[i], ]) #vs=0かつam=0かつgear=gearLevels[i] table_12 <- nrow(df[df$vs == 0 & df$am == 1 & df$gear == gearLevels[i], ]) #vs=0かつam=1かつgear=gearLevels[i] table_21 <- nrow(df[df$vs == 1 & df$am == 0 & df$gear == gearLevels[i], ]) #vs=1かつam=0かつgear=gearLevels[i] table_22 <- nrow(df[df$vs == 1 & df$am == 1 & df$gear == gearLevels[i], ]) #vs=1かつam=1かつgear=gearLevels[i] sumTable_11 <- sum(df$mpg[df$vs == 0 & df$am == 0 & df$gear == levels(df$gear)[i]]) #vs=0かつam=0かつgear=gearLevels[i] sumTable_12 <- sum(df$mpg[df$vs == 0 & df$am == 1 & df$gear == levels(df$gear)[i]]) #vs=0かつam=1かつgear=gearLevels[i] sumTable_21 <- sum(df$mpg[df$vs == 1 & df$am == 0 & df$gear == levels(df$gear)[i]]) #vs=1かつam=0かつgear=gearLevels[i] sumTable_22 <- sum(df$mpg[df$vs == 1 & df$am == 1 & df$gear == levels(df$gear)[i]]) #vs=1かつam=1かつgear=gearLevels[i] table <- data.frame(c(table_11, table_21), c(table_12, table_22)) sumTable <- data.frame(c(sumTable_11, sumTable_21), c(sumTable_12, sumTable_22)) rownames(table) <- c(0, 1) colnames(table) <- c(0, 1) rownames(sumTable) <- c(0, 1) colnames(sumTable) <- c(0, 1) tmp <- list(gear = NULL, table = NULL) tmp$gear <- gearLevels[i] tmp$table <- table tableList[[i]] <- tmp tmp$table <- sumTable sumTableList[[i]] <- tmp tmp$table <- sumTable / table meanTableList[[i]] <- tmp } |
2元のときと違うのは、for(i in 1:nlevels(as.factor(df$gear))){. . . }でdf$gearの各levelについての2元クロス集計表を作っている点です。6~14行目のように、gear=3, 4, 5の3通りに対する2×2の表を作っているのが分かります。
16~22行目では、度数と和についての2×2のデータフレームtableとsumTableを作り、各行名と列名を指定しています。
最後に24行目以降では、tmp <- list(gear = NULL, table = NULL)で各df$geaerのlevelに対する表を格納するリストを初期化しています。この場合list(gear, table)の最初のgearにはdf$gearの各levelが格納され、tableに各levelの2×2のデータフレームが格納されます。
上を実行すると、度数、和、平均についてのクロス集計表がそれぞれtableList、sumTableList 、meanTableList に格納されます。
例として、tableListをコンソール上で確認すると、vs、am、mpgについての度数の集計表ができていることが分かります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | > tableList #度数 [[1]] [[1]]$gear [1] "3" [[1]]$table 0 1 0 12 0 1 3 0 [[2]] [[2]]$gear [1] "4" [[2]]$table 0 1 0 0 2 1 4 6 [[3]] [[3]]$gear [1] "5" [[3]]$table 0 1 0 0 4 1 0 1 |
xtabsを用いた作成
2元のクロス集計の場合と同様に、xtabsを用いることで、上で紹介したような各セルの計算をしなくても3元以上のクロス集計表を作ることができます。
またftableを用いると、3元以上のクロス集計表はピボットテーブルに変換され、さらに見栄えが良くなります。
3元以上の度数のクロス集計
xtabsの引数を次のように指定することで、3元以上の度数のクロス集計表を作成できます。
1 2 | #1. 度数 table <- xtabs(~ vs + am + gear, data = df) |
最初の引数の式に"vs+am+mpg"というように列名を"+"で加えることで3元以上のクロス集計表を作れます。
tableを参照すると、次のようにdf$gearのlevelsごとでクロス集計されていることが確認できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | > table , , gear = 3 am vs 0 1 0 12 0 1 3 0 , , gear = 4 am vs 0 1 0 0 2 1 4 6 , , gear = 5 am vs 0 1 0 0 4 1 0 1 |
また、次のようにftableにクロス集計表を適用すると、クロス集計表がピボットテーブルへと変換されます。
1 2 | #ftableを用いたピボットテーブルへの変換 table <- ftable(table) |
tableを参照すると、次のようにクロス集計表であったものがピボットテーブルへと変わっていることが分かります。
1 2 3 4 5 6 7 | > table gear 3 4 5 vs am 0 0 12 0 0 1 0 2 4 1 0 3 4 0 1 0 6 1 |
3元以上の和のクロス集計
2元の場合と同様に、3元以上の和についてのクロス集計を行うことができます。
xtabsの引数を次のよう指定することで、和についてのクロス集計が行われます。
1 2 | #2. 和 sumTable <- xtabs(mpg ~ vs + am + gear, data = df) |
xtabsの最初の引数の式の"~"の前に和をとりたい列名を指定することで、和についてのクロス集計ができます。
この場合vsとamとgearに関するmpgの和についてのクロス集計表が作成されます。
sumTableは次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | > sumTable , , gear = 3 am vs 0 1 0 180.6 0.0 1 61.0 0.0 , , gear = 4 am vs 0 1 0 0.0 42.0 1 84.2 168.2 , , gear = 5 am vs 0 1 0 0.0 76.5 1 0.0 30.4 |
度数の場合と同様に、ftableを用いることで、ピボットテーブルを作成できます。
1 2 3 4 5 6 7 8 | > sumTable <- ftable(sumTable) > sumTable gear 3 4 5 vs am 0 0 180.6 0.0 0.0 1 0.0 42.0 76.5 1 0 61.0 84.2 0.0 1 0.0 168.2 30.4 |
3元以上の平均のクロス集計
上で作成した度数と和についてのクロス集計表を用いて、3元に上の平均についてのクロス集計表を作ることができます。
2元の時と同様に、割り算/を用いることで、次のように作成することができます。
1 2 | #3. 平均 meanTable <- table / sumTable |
meanTableを参照すると、平均についての3元のクロス集計表ができていることが分かります。
1 2 3 4 5 6 7 | > meanTable gear 3 4 5 vs am 0 0 0.06644518 NaN NaN 1 NaN 0.04761905 0.05228758 1 0 0.04918033 0.04750594 NaN 1 NaN 0.03567182 0.03289474 |
度数が0であるセルは、平均を計算することができないため、NaNが挿入されます。
同様に、ftableを用いて、ピボットテーブルに変換できます。
1 2 3 4 5 6 7 8 | > meanTable <- ftable(meanTable) > meanTable gear 3 4 5 vs am 0 0 0.06644518 NaN NaN 1 NaN 0.04761905 0.05228758 1 0 0.04918033 0.04750594 NaN 1 NaN 0.03567182 0.03289474 |
csvファイルへの出力(3元以上)
まずint型のリストで構成されているtable 、sumTable、meanTableをmatrixに変換します。
行列にすることで、行名や列名や変数名を変更するのが容易になります。
1 2 3 4 | #csvファイルへの出力 matrixTable <- as.matrix(table) #扱いやすよう行列にする matrixSumTable <- as.matrix(sumTable) matrixMeanTable <- as.matrix(meanTable) |
次に、2元の場合と同様に、rbindとcbindを用いて、行名、列名、変数名を整理します。
1 2 3 4 5 6 | table <- cbind(c("gear", "vs_am", rownames(matrixTable)), rbind(colnames(matrixTable), rep("", 3), matrixTable)) sumTable <- cbind(c("gear", "vs_am", rownames(matrixTable)), rbind(colnames(matrixTable), rep("", 3), matrixTable)) meanTable <- cbind(c("gear", "vs_am", rownames(matrixTable)), rbind(colnames(matrixTable), rep("", 3), matrixTable)) |
3元の度数についてのピボットテーブルは次のように、行名、列名、変数名が整理されていることが分かります。
1 2 3 4 5 6 7 8 | > table 3 4 5 "gear" "3" "4" "5" "vs_am" "" "" "" 0_0 "0_0" "12" "0" "0" 0_1 "0_1" "0" "2" "4" 1_0 "1_0" "3" "4" "0" 1_1 "1_1" "0" "6" "1" |
最後にwrite.tableを用いて、これらのピボットテーブルtable、sumTable、meanTableをcsvファイルへと出力します。
1 2 3 | write.table(table, "多元分割表(度数).csv", quote = F, sep = ",", row.names = F, col.names = F) write.table(sumTable, "多元分割表(和).csv", quote = F, sep = ",", row.names = F, col.names = F) write.table(meanTable, "多元分割表(平均).csv", quote = F, sep = ",", row.names = F, col.names = F) |
"多元分割表(度数).csv"を開くと、次の画像のようなピボットテーブルが出力されていることが確認できます。
まとめ
R言語でのクロス集計表やピボットテーブルの作成方法を学んでいきました。
クロス集計表とピボットテーブルはデータの集計に便利である他にも、検定方法の一種である適合度検定を行う際にも便利です。
データを集計する際や適合度検定を行う際に参考にしてください。