読者です 読者をやめる 読者になる 読者になる

simudaru's blog

Python, Rなどのメモを残していこうと思います。  よろしくお願いいたします。

【R】reshape2パッケージの関数をだいたい試しました

Rのreshape2パッケージを試してみました。
データフレームを縦持ちにしたり横持ちにしたりしてくれます。
時系列ではおなじみの、airqualityデータで試してみました。
今回はコードを分割してブログ記載していますが、
もとはひとつのコードですので、途中から実行する際は必要なライブラリが読み込まれているか、データ準備されているかなど、ご確認ください。

# ------------------------------------------------------------------------------
# reshape2 パッケージ
# ------------------------------------------------------------------------------
library(reshape2)
library(plyr)

# ------------------------------------------------------------------------------
# データ準備
d <- airquality
names(d) <- tolower(names(d))
summary(d)

dは以下のようなデータです。

ozone solar.r wind temp month day
41 190 7.4 67 5 1
36 118 8.0 72 5 2
12 149 12.6 74 5 3
18 313 11.5 62 5 4
NA NA 14.3 56 5 5
28 NA 14.9 66 5 6
# ■melt(data.frameに対して)
# 横持ちから縦持ちへ変換する
# melt(data, ..., na.rm = FALSE, value.name = "value")
d2 <- melt(d, id=c("month", "day"), na.rm=TRUE)
summary(d2)
d2.a <- melt(d, id=c("month", "day"), value.name="score")
summary(d2.a)

d2はこんなデータ。
dがmonthとdayをPrimaryKeyに「ozone, solar.r, wind, temp」の4つの値を横持ちで持っていたのに対し、
d2はmonthとdayに対して「variable」の値を持つという、縦持ちのデータになっています。

month day variable value
5 1 ozone 41
5 2 ozone 36
5 3 ozone 12
9 28 temp 75
9 29 temp 76
9 30 temp 68
# ■acast(配列化)
# acast(data, formula, fun.aggregate = NULL, ..., margins = NULL,
#       subset = NULL, fill = NULL, drop = TRUE,
#       value.var = guess_value(data))

# 3次元
tmp <- acast(d2, day ~ month ~ variable)
tmp
str(tmp)

3次元配列のデータとなります。
> str(tmp)
num [1:31, 1:5, 1:4] 41 36 12 18 NA 28 23 19 8 NA ...
- attr(*, "dimnames")=List of 3
..$ : chr [1:31] "1" "2" "3" "4" ...
..$ : chr [1:5] "5" "6" "7" "8" ...
..$ : chr [1:4] "ozone" "solar.r" "wind" "temp"

# 2次元
acast(d2, month ~ variable, mean)
acast(d2, month ~ variable, mean, margins = TRUE)
str(acast(d2, month ~ variable, mean))

集約関数をかましながら横持ちにします。
margins=TRUEとすると、総計もつけることが可能です。

ozone solar.r wind temp (all)
23.61538 181.2963 11.622581 65.54839 68.70696
29.44444 190.1667 10.266667 79.10000 87.38384
59.11538 216.4839 8.941935 83.90323 93.49748
59.96154 171.8571 8.793548 83.96774 79.71207
31.44828 167.4333 10.180000 76.90000 71.82689
42.12931 185.9315 9.957516 77.88235 80.05722

なお、acastの返り値は、データフレームではなく、配列です。
> str(acast(d2, month ~ variable, mean))
num [1:5, 1:4] 23.6 29.4 59.1 60 31.4 ...
- attr(*, "dimnames")=List of 2
..$ : chr [1:5] "5" "6" "7" "8" ...
..$ : chr [1:4] "ozone" "solar.r" "wind" "temp"

# ■dcast(データフレーム化(縦持ちから横持ちへ))
# dcast(data, formula, fun.aggregate = NULL, ..., margins = NULL,
#       subset = NULL, fill = NULL, drop = TRUE,
#       value.var = guess_value(data))
dcast(d2, month ~ variable, mean, margins = c("month"))
dcast(d2, month ~ variable, mean, margins = c("variable"))
dcast(d2, month ~ variable, mean, margins = c("month", "variable"))
dcast(d2, month ~ variable, mean, margins = TRUE)
str(dcast(d2, month ~ variable, mean))
dcast(d2, month ~ variable, mean, value.var = "value")

値は先ほどと同じですが、dcastの場合、返り値はデータフレームです。
> str(dcast(d2, month ~ variable, mean))
'data.frame': 5 obs. of 5 variables:
$ month : int 5 6 7 8 9
$ ozone : num 23.6 29.4 59.1 60 31.4
$ solar.r: num 181 190 216 172 167
$ wind : num 11.62 10.27 8.94 8.79 10.18
$ temp : num 65.5 79.1 83.9 84 76.9

# fillを指定すると存在しない場合を任意の値で埋める
dcast(d2, month + day ~ variable, sum, fill=NaN)
month day ozone solar.r wind temp
5 1 41 190 7.4 67
5 2 36 118 8.0 72
5 3 12 149 12.6 74
5 4 18 313 11.5 62
5 5 NaN NaN 14.3 56
5 6 28 NaN 14.9 66
# drop=Fにすると、存在しない組み合わせも表示する。
# 例えば、6月31日など
tmp1 <- dcast(d2, month + day ~ variable, sum, value.var = "value", drop=T)
nrow(tmp1)
tmp2 <- dcast(d2, month + day ~ variable, sum, value.var = "value", drop=F)
nrow(tmp2)
tmp2
month day ozone solar.r wind temp
6 29 0 31 14.9 77
6 30 0 138 8.0 83
6 31 0 0 0.0 0
7 1 135 269 4.1 84
# subsetの例
# .()記法はplyrによるもの
acast(d2, variable ~ month, mean, subset = .(variable == "ozone"))
5 6 7 8 9
ozone 23.61538 29.44444 59.11538 59.96154 31.44828
acast(d2, variable ~ month, mean, subset = .(month < 8))
5 6 7
ozone 23.61538 29.44444 59.115385
solar.r 181.29630 190.16667 216.483871
wind 11.62258 10.26667 8.941935
temp 65.54839 79.10000 83.903226
# ■recast(data, formula, ..., id.var, measure.var)
# meltとcastを一度に行う
recast(d, month ~ variable, na.rm=T, mean, id.var = c("month", "day"))
month ozone solar.r wind temp
5 23.61538 181.2963 11.622581 65.54839
6 29.44444 190.1667 10.266667 79.10000
7 59.11538 216.4839 8.941935 83.90323
8 59.96154 171.8571 8.793548 83.96774
9 31.44828 167.4333 10.180000 76.90000

# ■colsplit
# colsplit(string, pattern, names)
# 区切り文字で区切って、別のカラムとする。
# うまい使い方はすぐには出てこないが。
x <- c("a_1", "a_2", "b_2", "c_3")
vars <- colsplit(x, "_", c("trt", "time"))
vars
str(vars)
trt time
a 1
a 2
b 2
c 3
# 区切り文字なしで区切ってくれると嬉しいのだが、できない?
x <- c("11", "10", "00", "01")
vars <- colsplit(x, "", c("trt", "time"))
vars
str(vars)
trt time
NA 11
NA 10
NA 0
NA 1
# 一応以下で動くには動くが、いかにも汚い。
tmp <- sapply(x, function(x){strsplit(x,"")})
vars <- data.frame(t(data.frame(tmp)))
vars
str(vars)
trt time
1 1
1 0
0 0
0 1
# ■melt(arrayに対して)
a <- array(c(1:23, NA), c(2,3,4))
melt(a)
melt(a, na.rm = TRUE)
melt(a, varnames=c("X","Y","Z"))
dimnames(a) <- lapply(dim(a), function(x) LETTERS[1:x])
melt(a)
melt(a, varnames=c("X","Y","Z"))
dimnames(a)[1] <- list(NULL)
melt(a)


# ■melt(listに対して)
a <- as.list(c(1:4, NA))
melt(a)
names(a) <- letters[1:4]
melt(a)
a <- list(matrix(1:4, ncol=2), matrix(1:6, ncol=2))
melt(a)
a <- list(matrix(1:4, ncol=2), array(1:27, c(3,3,3)))
melt(a)
melt(list(1:5, matrix(1:4, ncol=2)))
melt(list(list(1:3), 1, list(as.list(3:4), as.list(1:2))))


# ■add_margins
# add_margins後にdcast関数とか?用途がイマイチ不明
add_margins(d, "Species", margins = TRUE)

このあたりはあまり使わないかな。