マルチアンサーのクロス集計     Last modified: Dec 12, 2012

目的

単一のカテゴリー変数と複数の該当・非該当の応答のある変数のクロス集計を行う

使用法

ma(i, j, df, latex=TRUE, caption=NULL, label=NULL, output="")

引数

i, j    データフレーム上で,クロス集計をする二変数が入っている,列の番号または変数名ベクトル
        該当・非該当により答える項目は i, j のどちらに指定してもよい
        実際には 1, 3:10 とか 12:17, 2 のように指定する
        注意:データフレーム上で,該当・非該当のデータの定義を間違わないように(使用例参照)
df      読み込んだデータフレームの名前
latex   LaTeX ソースを出力する。Word 用なら,latex=FALSE にする
caption latex=TRUE の場合,各表の表題を文字列ベクトルとして指定することができる(デフォルトではあり合わせの表題を付ける)。
label   latex=TRUE の場合,各表の label を文字列ベクトルとして指定することができる(デフォルトでは付けない)。
output  出力コネクション
        デフルトはコンソールに出力

ソース

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

#####
#
# マルチアンサー項目と別の 1 つの変数についてクロス集計表を作成する
#
#####

ma <- function(i,                                                            # 表側に来る変数が入っているデータフレーム上の列番号または変数名ベクトル
               j,                                                               # 表側に来る変数が入っているデータフレーム上の列番号または変数名ベクトル
                                                                                # i, j いずれかがマルチアンサー項目を表すのでベクトルになる
               df,                                                              # データフレーム
               latex=TRUE,                                                      # LaTeX 形式で度数分布表を出力する(デフォルトは LaTeX 形式)
               caption=NULL,                                                    # latex=TRUE のときに,各表の表題を表す文字列ベクトルを指定できる(NULL のときはデフォルトの表題)
               label=NULL,                                                      # latex=TRUE のときに,各表の label を表す文字列ベクトルを指定できる(NULL のときは付けない)
               output="",                                                       # ファイルに出力するときはファイル名(デフォルトはコンソールに出力)
               encoding=getOption("encoding"))                                  # ファイルに出力するときのエンコーディング(デフォルトは OS による)
{

# 下請け関数
        is.error <- function(k)                                                      # k 列目の変数が factor であり,かつ,二値変数でなければならない
        {
                if (!is.factor(df[,k])) {                                       # factor でない
                        warning(sprintf("%s を factor にしてください", colnames(df)[k]))
                        return(TRUE)
                }
                else if (nlevels(df[,k]) != 2) {                                # 二値変数でない
                        warning(sprintf("%s が二値データではありません", colnames(df)[k]))
                        return(TRUE)
                }
                return(FALSE)
        }

        getNum <- function(str, df) {                                                # 変数名から列番号を得る
                names <- colnames(df)
                seq_along(names)[names %in% str]
        }

# 関数本体
        if (output != "") {                                                     # 結果をファイルに出力する場合の処理
                output <- file(output, open="w", encoding=encoding)
        }
        if (is.character(i[1])) {
                i <- getNum(i, df)
        }
        if (is.character(j[1])) {
                j <- getNum(j, df)
        }
        if (length(i) == 1 && length(j) > 1) {                                    # i の方が普通の変数(1 つ),j の方がマルチアンサー変数(複数)のとき
                row <- TRUE                                                  # 表頭にマルチアンサー項目,row = TRUE として識別
        }
        else if (length(i) > 1 && length(j) == 1) {                               # i の方がマルチアンサー変数(複数),j  の方が普通の変数(1 つ)のとき
                row <- FALSE                                                 # 表側にマルチアンサー項目,row = FALSE として識別
                temp <- i                                                    # row == TRUE のときと同じように処理するために,i, j の内容を入れ替える
                i <- j
                j <- temp
        }
        else {                                                                  # 普通の変数が複数個指定されるような場合は想定していない
                stop("このプログラムでは,i, j いずれかが要素 1 のスカラー,他方が要素2以上のベクトルであることを仮定しています。使用法に誤りがあります")
        }
        if (any(sapply(j, is.error))) stop("データの準備に問題があります")      # マルチアンサー変数のチェック

        df.i <- as.factor(df[,i])                                            # 普通の変数の方も factor にされている方が望ましいが,そうではないときのために
        ans <- sapply(j, function(k) table(df[,i], df[,k]))[1:nlevels(df.i),]        # マルチアンサー集計表本体を作る
        ans <- cbind(ans, table(df.i))                                               # 合計列を作る(普通の変数の方の度数分布)
        ans <- rbind(ans, colSums(ans))                                              # 合計行を作る
        rownames(ans) <- c(levels(df.i), "合計")                             # 行の名前
        colnames(ans) <- c(colnames(df[,j]), "該当数")                               # 列の名前
        nc <- ncol(ans)                                                              # 列数
        pct <- ans/ans[,nc]*100                                                      # 行方向パーセント
        if (!row) {                                                             # row == FALSE の場合に,
                ans <- t(ans)                                                        # ans を転置
                pct <- t(pct)                                                        # pct を転置
                nc <- ncol(ans)                                                      # 転置後の列数を再計算
        }
        nr <- nrow(ans)                                                              # 最終時点の集計表の行数
        if (latex) {                                                            # LaTeX 形式で集計結果を出力する
                cat("\\begin{table}[htbp]\n", file=output)                      # \begin{table}[htbp] 
                if (is.null(caption)) {
                        cat("\\caption{マルチアンサー項目の集計}\n", file=output) # \caption{マルチアンサー項目の集計}
                }
                else {
                        cat(sprintf("\\caption{%s}\n", caption), file=output)   # 指定した表題
                }
                if (!is.null(label)) {
                        cat(sprintf("\\label{%s}\n", label), file=output)       # 指定したラベル
                }
                cat("\\centering\n", file=output)                                                                       # \centering
                cat("\\begin{tabular}{l", rep("c", nc), "} \\hline\n", sep="", file=output)                             # \begin{tabular}{cc…c} \hline
                if (row) {                                                                                              # 表頭にマルチアンサー項目
                        cat(colnames(df)[i], colnames(ans), sep=" & ", file=output)                                  # 変数名 & マルチアンサー変数i & …
                        cat("\\\\ \\hline\n", file=output)                                                              # \\ \hline
                        for (i in 1:nr) {                                                                               # 各行について,
                                cat(rownames(ans)[i], ans[i,], sep=" & ", file=output)                                       # 行名 & 集計数i & …
                                cat("\\\\\n", file=output)                                                              # \\
                                cat("\\%", sprintf("{\\small \\textit{%.1f}}", pct[i,-nc]), sep=" & ", file=output)  # % & パーセントi & …
                                cat("\\\\", file=output)                                                                # \\
                                if (i >= nr-1) cat("\\hline\n", file=output) else cat("\n", file=output)                # 最終行の前なら \\
                        }
                }
                else {                                                                                                  # 表側にマルチアンサー項目
                        cat(sprintf("& \\multicolumn{%i}{c}{%s}\\\\ \\cline{2-%i}\n", nc-1, colnames(df)[i], nc),    # マルチアンサーではない方の変数名
                            file=output)
                        cat("", colnames(ans), sep=" & ", file=output)                                                       # 列名(変数のカテゴリー名)
                        cat("\\\\ \\hline\n", file=output)                                                              # \\ \hline
                        for (i in 1:nr) {                                                                               # 各行(マルチアンサー項目)ごとに,
                                cat(rownames(ans)[i], ans[i,], sep=" & ", file=output)                                       # 行名 & 集計数i & …
                                cat("\\\\\n", file=output)                                                              # \\
                                if (i < nr) {                                                                                # 最終行でないときは,
                                        cat("\\%", sprintf("{\\small \\textit{%.1f}}", pct[i,]), sep=" & ", file=output)# % & パーセントi & …
                                        cat("\\\\", file=output)                                                        # \\
                                }
                                if (i >= nr-1) cat("\\hline\n", file=output) else cat("\n", file=output)                # 最終行の前なら \\
                        }
                }
                cat("\\end{tabular}\n", file=output)                                                                    # \end{tabular}
                cat("\\end{table}\n", file=output)                                                                      # \end{table}
        }
        else {                                                                  # tab で区切って出力する
                cat("表 マルチアンサー項目の集計\n", file=output)                                                      # マルチアンサー項目の集計
                if (row) {
                        cat("\n", file=output, fill=TRUE)
                        cat(colnames(df)[i], colnames(ans), sep="\t", file=output, fill=TRUE)                           # 変数名 マルチアンサー変数i …
                        for (i in 1:nr) {                                                                               # 各行について,
                                cat(rownames(ans)[i], ans[i,], sep="\t", file=output, fill=TRUE)                        # 行名  集計数i   …
                                cat("%", sprintf("%.1f", pct[i,-nc]), sep="\t", file=output, fill=TRUE)                 # %    パーセントi …
                        }
                }
                else {                                                                                                  # 表側にマルチアンサー項目を置く場合
                        cat("\n", colnames(df)[i], sep="\t", file=output, fill=TRUE)                                    # マルチアンサーではない方の変数名
                        cat("", colnames(ans), sep="\t", file=output, fill=TRUE)                                        # 列名(変数のカテゴリー名)
                        for (i in 1:nr) {                                                                               # 各行(マルチアンサー項目)ごとに,
                                cat(rownames(ans)[i], ans[i,], sep="\t", file=output, fill=TRUE)                        # 行名 集計数i …
                                if (i < nr) {                                                                                # 最終行でないときは,
                                        cat("%", sprintf("%.1f", pct[i,]), sep="\t", file=output, fill=TRUE)            # %   パーセントi …
                                }
                        }
                }
        }
        if (output != "") {                                                     # 結果をファイルに出力した場合の後始末
                close(output)
        }
}


使用例

性別	血液型	項目1	項目2	項目3	項目4	項目5
1	1	1	1	0	1	1
2	2	0	1	0	1	1
1	3	0	0	0	0	1
1	4	1	1	1	1	1
1	1	1	0	0	1	0
2	2	0	1	1	1	1
2	3	1	1	0	1	0
1	3	1	1	1	1	0
2	2	1	1	0	0	0
2	1	0	0	1	0	0
のようなファイル test.dat があるとする

入力と変数の定義
df <- read.table("test.dat", header=TRUE)
性別と血液型は通常のカテゴリー変数
df[,1] <- factor(df[,1], levels=1:2, labels=c("男", "女"))
df[,2] <- factor(df[,2], levels=1:4, labels=c("A", "B", "O", "AB"))
項目1〜項目5 は該当なら1,非該当なら0で入力されている
集計したいことを表す数値(この例なら「該当」)を levels の1番目の数値にすること
for (i in 3:7) df[,i] <- factor(df[,i], levels=1:0, labels=c("該当", "非該当"))

コンソールに出力するとき
ma(2, 3:7, df)

ファイルに出力するとき
ma(2, 3:7, df, output="ファイル名", encoding="EUC-JP")

出力結果例

latex=FALSE の場合

> ma(2, 3:7, df, latex=FALSE) # 二番目の引数がマルチアンサー項目の場合

血液型	項目1	項目2	項目3	項目4	項目5	該当数
A	2	1	1	2	1	3
%	66.7	33.3	33.3	66.7	33.3
B	1	3	1	2	2	3
%	33.3	100.0	33.3	66.7	66.7
O	2	2	1	2	1	3
%	66.7	66.7	33.3	66.7	33.3
AB	1	1	1	1	1	1
%	100.0	100.0	100.0	100.0	100.0
合計	6	7	4	7	5	10
%	60.0	70.0	40.0	70.0	50.0

注:% は各項目に答えた数を右端にある該当数で割ったものである。
  マルチアンサーのため,% を合計しても 100% にはならない。

> ma(3:7, 2, df, latex=FALSE) # 一番目の引数がマルチアンサー項目の場合

	血液型
	A	B	O	AB	合計
項目1	2	1	2	1	6
%	66.7	33.3	66.7	100.0	60.0
項目2	1	3	2	1	7
%	33.3	100.0	66.7	100.0	70.0
項目3	1	1	1	1	4
%	33.3	33.3	33.3	100.0	40.0
項目4	2	2	2	1	7
%	66.7	66.7	66.7	100.0	70.0
項目5	1	2	1	1	5
%	33.3	66.7	33.3	100.0	50.0
該当数	3	3	3	1	10

注:% は各項目に答えた数を最下行にある該当数で割ったものである。
  マルチアンサーのため,% を合計しても 100% にはならない。

latex=TRUE(デフォルト)の場合

> ma(2, 3:7, df) # 二番目の引数がマルチアンサー項目の場合

\begin{table}[htbp]
\begin{center}
\begin{tabular}{lcccccc} \hline
血液型 & 項目1 & 項目2 & 項目3 & 項目4 & 項目5 & 該当数\\ \hline
A & 2 & 1 & 1 & 2 & 1 & 3\\
\% & {\small \textit{66.7}} & {\small \textit{33.3}} & {\small \textit{33.3}} & {\small \textit{66.7}} & {\small \textit{33.3}}\\
B & 1 & 3 & 1 & 2 & 2 & 3\\
\% & {\small \textit{33.3}} & {\small \textit{100.0}} & {\small \textit{33.3}} & {\small \textit{66.7}} & {\small \textit{66.7}}\\
O & 2 & 2 & 1 & 2 & 1 & 3\\
\% & {\small \textit{66.7}} & {\small \textit{66.7}} & {\small \textit{33.3}} & {\small \textit{66.7}} & {\small \textit{33.3}}\\
AB & 1 & 1 & 1 & 1 & 1 & 1\\
\% & {\small \textit{100.0}} & {\small \textit{100.0}} & {\small \textit{100.0}} & {\small \textit{100.0}} & {\small \textit{100.0}}\\\hline
合計 & 6 & 7 & 4 & 7 & 5 & 10\\
\% & {\small \textit{60.0}} & {\small \textit{70.0}} & {\small \textit{40.0}} & {\small \textit{70.0}} & {\small \textit{50.0}}\\\hline
\end{tabular}
\end{center}
\end{table}

> ma(3:7, 2, df) # 一番目の引数がマルチアンサー項目の場合

\begin{table}[htbp]
\begin{center}
\begin{tabular}{lccccc} \hline
& \multicolumn{4}{c}{血液型}\\ \cline{2-5}
 & A & B & O & AB & 合計\\ \hline
項目1 & 2 & 1 & 2 & 1 & 6\\
\% & {\small \textit{66.7}} & {\small \textit{33.3}} & {\small \textit{66.7}} & {\small \textit{100.0}} & {\small \textit{60.0}}\\
項目2 & 1 & 3 & 2 & 1 & 7\\
\% & {\small \textit{33.3}} & {\small \textit{100.0}} & {\small \textit{66.7}} & {\small \textit{100.0}} & {\small \textit{70.0}}\\
項目3 & 1 & 1 & 1 & 1 & 4\\
\% & {\small \textit{33.3}} & {\small \textit{33.3}} & {\small \textit{33.3}} & {\small \textit{100.0}} & {\small \textit{40.0}}\\
項目4 & 2 & 2 & 2 & 1 & 7\\
\% & {\small \textit{66.7}} & {\small \textit{66.7}} & {\small \textit{66.7}} & {\small \textit{100.0}} & {\small \textit{70.0}}\\
項目5 & 1 & 2 & 1 & 1 & 5\\
\% & {\small \textit{33.3}} & {\small \textit{66.7}} & {\small \textit{33.3}} & {\small \textit{100.0}} & {\small \textit{50.0}}\\\hline
該当数 & 3 & 3 & 3 & 1 & 10\\
\hline
\end{tabular}
\end{center}
\end{table}


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

Made with Macintosh