Rで表計算
RはExcelより圧倒的に楽に複雑な計算が出来ることが多いのだが、Excelで簡単にできるような計算に思わず苦労することがあったりする。というので、Excelで慣れ親しんだ単純な表計算をRを使ってやってみよう。
二次元の表
氏名 | 国語 | 数学 | 社会 | 理科 | 合計 |
---|---|---|---|---|---|
安倍 | 66 | 54 | 57 | 87 | |
飯田 | 64 | 34 | 87 | 55 | |
石黒 | 87 | 欠席 | 65 | 64 | |
中澤 | 98 | 64 | 90 | 65 | |
福田 | 欠席 | 36 | 75 | 72 | |
平均 |
test.point.matrix <- matrix(c(66,54,57,87,64,34,87,55,87,NA,65,64,98,64,90,65,NA,36,75,72), ncol=4, byrow=T) colnames(test.point.matrix) <- c("国語","数学","社会","理科") rownames(test.point.matrix) <- c("安倍","飯田","石黒","中澤","福田")
各要素へのアクセスは一般的なプログラミング言語の二次元配列とは異なり、要素[行番号,列番号]。
#中澤さんの数学 test.point.matrix[4,2]
行列の入れ替え
t関数…行・列の入れ替え
- t(X)
-
表matrixの行列を入れ替える。
- X=表(matrix)データ
t(test.point.matrix[4,2])
「行列の入れ替え(切り替え)」。グラフ作成するときなどに使う。
> test.point.matrix 国語 数学 社会 理科 安倍 66 54 57 87 飯田 64 34 87 55 石黒 87 NA 65 64 中澤 98 64 90 65 福田 NA 36 75 72 > t(test.point.matrix) 安倍 飯田 石黒 中澤 福田 国語 66 64 87 98 NA 数学 54 34 NA 64 36 社会 57 87 65 90 75 理科 87 55 64 65 72
行単位・列単位の計算
上記表で個人ごとの合計と科目ごとの平均を求めたい。
Excelなら相対参照+オートフィル(数式コピー)でちょちょいのちょいだが、Rではどうすれば良いだろうか。
プログラミングになれた人なら、ループを廻して、と思うだろう。
#個人ごとに点数の合計を計算する。 point.sum <- c(rep(0,length(rownames(test.point.matrix)))) for(i in 1:length(point.sum)){ for(j in test.point.matrix[i,]){ point.sum[i] <- sum(point.sum[i],j,na.rm=T) } } point.sum #科目ごとに点数の平均を計算する。 point.sum <- c(rep(0,length(colnames(test.point.matrix)))) count <- c(rep(0,length(point.sum))) for(i in 1:length(point.sum)){ count[i] <- length(na.omit(test.point.matrix[,i])) for(j in test.point.matrix[,i]){ point.sum[i] <- sum(point.sum[i],j,na.rm=T) } } point.sum/count
もちろんこれでも出来るが、Rはこの手の計算に関しては一般的な言語より遙かに関数が充実している。ループを廻すより、なるべく関数で処理する方が良い。
apply関数…行・列単位集計
- apply(X, MARGIN, FUN)
-
表matrixを行単位または列単位に処理を行う。
- X=表(matrix)データ
- MARGIN=行単位1ないし列単位2で集計する
- FUN=関数名ないし関数定義
#個人ごとに点数の合計を計算する。 apply(test.point.matrix,1,function(x) sum(x,na.rm=T)) #科目ごとに点数の平均値を計算する。 apply(test.point.matrix,2,function(x) mean(x,na.rm=T))
> apply(test.point.matrix,1,function(x) sum(x,na.rm=T)) 安倍 飯田 石黒 中澤 福田 264 240 216 317 183 > > apply(test.point.matrix,2,function(x) mean(x,na.rm=T)) 国語 数学 社会 理科 78.75 47.00 74.80 68.60
セルごとの計算
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|
1 | |||||||||
2 | |||||||||
3 | |||||||||
4 | |||||||||
5 | |||||||||
6 | |||||||||
7 | |||||||||
8 | |||||||||
9 |
num <- 9 row.vec <- c(seq(1:num)) col.vec <- c(seq(1:num))
行×列で九九表を作りたい。Excelなら絶対参照と相対参照の組み合わせで、一般的なプログラミング言語なら二重ループでやるところ。
kuku <- matrix(seq(1:(num*num)),ncol=num) for(i in row.vec){ for(j in col.vec){ kuku[i,j] <- i*j } } kuku
Rでは行データ一つ一つに列データを掛け合わせる、という作業を一気に行う。
sapply関数…要素ごとの処理
- sapply(X, FUN)
-
要素ごとに処理を行って、表matrixで答えを返す。
- X=ベクトル(vector)、表(matrix)など複数要素を含むデータ
- FUN=関数名ないし関数定義
sapply(row.vec,function(x) x*col.vec)
> sapply(row.vec,function(x) x*col.vec) [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [1,] 1 2 3 4 5 6 7 8 9 [2,] 2 4 6 8 10 12 14 16 18 [3,] 3 6 9 12 15 18 21 24 27 [4,] 4 8 12 16 20 24 28 32 36 [5,] 5 10 15 20 25 30 35 40 45 [6,] 6 12 18 24 30 36 42 48 54 [7,] 7 14 21 28 35 42 49 56 63 [8,] 8 16 24 32 40 48 56 64 72 [9,] 9 18 27 36 45 54 63 72 81
条件付き集計
経費記録データを集計したい。
- 担当別
- 費目別
- 担当・費目別
それぞれに請求件数・合計額を算出する。
日付 | 担当 | 費目 | 金額 |
---|---|---|---|
5月6日 | 藤本 | 交通費 | 5300 |
5月6日 | 藤本 | 食費 | 2300 |
5月6日 | 藤本 | 消耗品費 | 1500 |
5月6日 | 松浦 | 交通費 | 2400 |
5月6日 | 松浦 | 消耗品費 | 850 |
5月7日 | 藤本 | 交通費 | 2000 |
5月7日 | 藤本 | 食費 | 2500 |
… |
一般的に条件に合うデータの摘出を行うやり方。
data <- read.csv("http://kyoto-edu.sakura.ne.jp/weblesson/statistics/data/expense.csv", fileEncoding = "utf-8") #全請求件数 length(data$金額) #請求金額合計 sum(data$金額) #担当"藤本"である請求金額 sum(data$金額[data$担当=="藤本"]) #担当"藤本"かつ費目"食費"である請求金額合計 sum(data$金額[data$担当=="藤本" & data$費目=="交通費"])
> #全請求件数 > length(data$金額) [1] 21 > #請求金額合計 > sum(data$金額) [1] 37970 > > #担当"藤本"である請求金額 > sum(data$金額[data$担当=="藤本"]) [1] 28810 > #担当"藤本"かつ費目"食費"である請求金額合計 > sum(data$金額[data$担当=="藤本" & data$費目=="交通費"]) [1] 15300
tapply関数…カテゴリー別集計
- tapply(X, INDEX, FUN)
-
要素をグループごとに処理する
- X=ベクトル(vector)、表(matrix)など複数要素を含むデータ
- INDEX=カテゴリー変数
- FUN=関数名ないし関数定義
data <- read.csv("http://kyoto-edu.sakura.ne.jp/weblesson/statistics/data/expense.csv", fileEncoding = "utf-8") #担当別請求金額 tapply(data$金額,data$担当,sum) #費目別請求件数 tapply(data$金額,data$費目,length) #担当別費目別請求金額 tapply(data$金額,list(data$担当,data$費目),sum) #担当別費目別請求件数 tapply(data$金額,list(data$担当,data$費目),length)
> #担当別請求金額 > tapply(data$金額,data$担当,sum) 松浦 藤本 9160 28810 > #費目別請求件数 > tapply(data$金額,data$費目,length) 交通費 消耗品費 食費 8 6 7 > > #担当別費目別請求金額 > tapply(data$金額,list(data$担当,data$費目),sum) 交通費 消耗品費 食費 松浦 5350 1500 2310 藤本 15300 5450 8060 > #担当別費目別請求件数 > tapply(data$金額,list(data$担当,data$費目),length) 交通費 消耗品費 食費 松浦 4 2 3 藤本 4 4 4
クロス集計
table関数
- table(...)
-
水準ごとの度数を集計する
- カテゴリー変数
data <- read.csv("http://kyoto-edu.sakura.ne.jp/weblesson/statistics/data/expense.csv", fileEncoding = "utf-8") #費目別請求件数 table(data$費目) #担当別費目別請求件数 table(data$担当,data$費目)
> #費目別請求件数 > table(data$費目) 交通費 消耗品費 食費 8 6 7 > #担当別費目別請求件数 > table(data$担当,data$費目) 交通費 消耗品費 食費 松浦 4 2 3 藤本 4 4 4
addmargins関数…表に合計欄を付加
- addmargins(X, MARGIN)
-
表matrixに合計欄を加える。
- X=表(matrix)データ
- MARGIN=全体(省略時)、行単位1、列単位2の合計を出力
data <- read.csv("http://kyoto-edu.sakura.ne.jp/weblesson/statistics/data/expense.csv", fileEncoding = "utf-8") #合計金額欄を付加 addmargins(tapply(data$金額,list(data$担当,data$費目),sum)) #度数クロス集計表に周辺度数を付加 addmargins(table(data$担当,data$費目))
> #合計金額欄を付加 > addmargins(tapply(data$金額,list(data$担当,data$費目),sum)) 交通費 消耗品費 食費 Sum 松浦 5350 1500 2310 9160 藤本 15300 5450 8060 28810 Sum 20650 6950 10370 37970 > #度数クロス集計表に周辺度数を付加 > addmargins(table(data$担当,data$費目)) 交通費 消耗品費 食費 Sum 松浦 4 2 3 9 藤本 4 4 4 12 Sum 8 6 7 21
比率
prop.table関数…比率計算
- prop.table(X, MARGIN)
-
表matrix内データの比率計算をする。
- X=表(matrix)データ
- MARGIN=全体(省略時)、行単位1、列単位2の比率を出力
data <- read.csv("http://kyoto-edu.sakura.ne.jp/weblesson/statistics/data/expense.csv", fileEncoding = "utf-8") #総合計金額に占める各項目(担当*費目)の比率 prop.table(tapply(data$金額,list(data$担当,data$費目),sum)) #費目別比率 prop.table(addmargins(tapply(data$金額,list(data$担当,data$費目),sum),margin=1),margin=1) #担当別比率 prop.table(addmargins(tapply(data$金額,list(data$担当,data$費目),sum),margin=2),margin=2)
> #総合計金額に占める各項目(担当*費目)の比率 > prop.table(tapply(data$金額,list(data$担当,data$費目),sum)) 交通費 消耗品費 食費 松浦 0.1409007 0.03950487 0.0608375 藤本 0.4029497 0.14353437 0.2122728 > #費目別比率 > prop.table(addmargins(tapply(data$金額,list(data$担当,data$費目),sum),margin=1),margin=1) 交通費 消耗品費 食費 松浦 0.5840611 0.1637555 0.2521834 藤本 0.5310656 0.1891704 0.2797640 Sum 0.5438504 0.1830392 0.2731104 > #担当別比率 > prop.table(addmargins(tapply(data$金額,list(data$担当,data$費目),sum),margin=2),margin=2) 交通費 消耗品費 食費 Sum 松浦 0.2590799 0.2158273 0.222758 0.2412431 藤本 0.7409201 0.7841727 0.777242 0.7587569