reshape package

실제 데이터를 접하게 되면 데이터를 Reshaping(aggregation, tabulation, contingency table, etc)하게 되는 것은 흔한 일이다. 이러한 일들을 Excel, SAS, R 에서 종종 해왔다. 특히 R에서도 이러한 기능을 제공하는 function들이 몇 개 있다. 예를 들어 tapply(), by(), aggregate(), summary()와 같은 function들이다. 이같은 function들은 각 function별로 쓰임새가 약간씩 다르고 사용하게 되는 argument도 다르다. 때문에 데이터를 Reshaping하는데 있어서 복잡하고 싫증나고 짜증날 수도 있다.

이러한 불편함을 줄이기 위해 reshape package를 이용하게 되면 매우 편리하다. reshape package는 데이터 형태의 재배열, coningency table 생성, 데이터 summarising등을 할 수 있게 해준다. 본 문서는 reshape package에 있는 melt()와 cast()에 대해 집중적으로 설명하고 그 외에 이 패키지에서 제공하는 편리하고 유용한 function에 대해 간략히 설명하겠다.

1. melt(), cast() function

melt()와 cast()에 대한 개략적인 이해를 위해 'smiths' 데이터를 통해 살펴보자. 'smiths' 데이터 역시 reshape package에 있는 built-in data이다.

melt 와 _cast_는 제철 작업에 있어 철을 용해하고 주조하여 단단한 철을 만들어내는 것과 같이 데이터를 분석에 용이하게 하기 위해 전처리 작업을 하는 것이다.

a. melt()

melt() function을 사용할 때 identifier(이하 id)와 measured variable을 구분하는 것은 매우 중요하다. 즉, 어떤 변수가 measured variable인지 id variable인지 알아야 할 필요가 있다.

##      subject time age weight height
## 1 John Smith    1  33     90   1.87
## 2 Mary Smith    1  NA     NA   1.54

위의 데이터를 melt()를 이용해서 어떻게 변하게 되는지 살펴보자.

melt(smiths, id = c("subject", "time"), measured = c("age", "weight", "height"))
##      subject time variable value
## 1 John Smith    1      age 33.00
## 2 Mary Smith    1      age    NA
## 3 John Smith    1   weight 90.00
## 4 Mary Smith    1   weight    NA
## 5 John Smith    1   height  1.87
## 6 Mary Smith    1   height  1.54
melt(smiths, id = c("subject", "time"))
##      subject time variable value
## 1 John Smith    1      age 33.00
## 2 Mary Smith    1      age    NA
## 3 John Smith    1   weight 90.00
## 4 Mary Smith    1   weight    NA
## 5 John Smith    1   height  1.87
## 6 Mary Smith    1   height  1.54
melt(smiths, id = 1:2, na.rm = T)
##      subject time variable value
## 1 John Smith    1      age 33.00
## 2 John Smith    1   weight 90.00
## 3 John Smith    1   height  1.87
## 4 Mary Smith    1   height  1.54

위에 보이는 코드는 다르나 같은 결과를 나타내고 있다. 즉, id 는 subject, time column이고 measured variable 은 age, weight, height column으로 지정해주었다. 2번째 코드를 보면 알 수 있듯이 id 만 지정하고 measured variable 은 지정하지 않아도 id 로 지정된 변수 외에 것은 measured variable 로 인식을 한다.

output을 보면 알 수 있듯이 id 로 지정한 subject, time으로 정렬을 하고 measured variable 에 해당하는 age, weight, height는 Variable 변수의 값으로 받아들이고, 각 age, weight, height에 해당하는 값은 Value 변수에 들어가게 되는 것을 알 수 있다.

그리고 3번재 코드에서 melt() function안에 'na.rm=T'이라는 argument를 추가해주면 missing value인 'NA'값에 해당하는 observation은 나타나지 않게 해준다.

b. cast()

cast()는 melt() function을 적용한 data frame(혹은 object)을 사용자가 원하는 모양으로 재배열을 할 수 있게 해주는 함수이다.

two required arguments

- data : the molten data set to reshape
- formula : basic form (col_var_1 + col_var_2 ~ row_var_1 + row_var_2)
            만약에 formula를 지정해 주지 않으면 1. measured variables in the columns,
                                                2. all other id variables in the rows.

optional arguments

- fun.aggregate : length(default), mean, sum, ...
- margins : sub total, grand total ("grand_row", "grand_col")

Basic use

- '.' corresponds to no variable. ex) '. ~ x' or 'x ~ .', that is, a single row or column.
- '...' represents all variables

이제 cast() function을 사용해 보자. 앞서 a. melt()에서 melting한 데이터를 가지고 살펴보겠다.

smithsm <- melt(smiths, id = 1:2)  # smithsm : molten data 'smiths'
cast(smithsm, subject + time ~ variable)
##      subject time age weight height
## 1 John Smith    1  33     90   1.87
## 2 Mary Smith    1  NA     NA   1.54
cast(smithsm, ... ~ variable)
##      subject time age weight height
## 1 John Smith    1  33     90   1.87
## 2 Mary Smith    1  NA     NA   1.54

위의 결과는 melting 하기 전의 data와 같음을 알 수 있다.

cast(smithsm, ... ~ subject, sum, margins = c("grand_row", "grand_col"))
##    time variable John Smith Mary Smith (all)
## 1     1      age      33.00         NA    NA
## 2     1   weight      90.00         NA    NA
## 3     1   height       1.87       1.54  3.41
## 4 (all)    (all)     124.87         NA    NA

2. Case study

a. built-in data set french_fries description

다른 종류의 frying oil이 French fries의 맛에 미치는 영향에 대해 조사한 실험에 대한 데이터이다.

아래에는 이 데이터의 일부분이다.

library(reshape)
ffm <- melt(french_fries, id = 1:4, na.rm = TRUE)
head(ffm, 6)
##   time treatment subject rep variable value
## 1    1         1       3   1   potato   2.9
## 2    1         1       3   2   potato  14.0
## 3    1         1      10   1   potato  11.0
## 4    1         1      10   2   potato   9.9
## 5    1         1      15   1   potato   1.2
## 6    1         1      15   2   potato   8.8

b. Investigating balance

cast(ffm, subject ~ time, length, margins = T)
##    subject   1   2   3   4   5   6   7   8   9  10 (all)
## 1        3  30  30  30  30  30  30  30  30  30   0   270
## 2       10  30  30  30  30  30  30  30  30  30  30   300
## 3       15  30  30  30  30  25  30  30  30  30  30   295
## 4       16  30  30  30  30  30  30  30  29  30  30   299
## 5       19  30  30  30  30  30  30  30  30  30  30   300
## 6       31  30  30  30  30  30  30  30  30   0  30   270
## 7       51  30  30  30  30  30  30  30  30  30  30   300
## 8       52  30  30  30  30  30  30  30  30  30  30   300
## 9       63  30  30  30  30  30  30  30  30  30  30   300
## 10      78  30  30  30  30  30  30  30  30  30  30   300
## 11      79  30  30  30  30  30  30  29  28  30   0   267
## 12      86  30  30  30  30  30  30  30  30   0  30   270
## 13   (all) 360 360 360 360 355 360 359 357 300 300  3471
cast(ffm, subject ~ time, function(x) 30 - length(x))
##    subject 1 2 3 4 5 6 7 8  9 10
## 1        3 0 0 0 0 0 0 0 0  0 30
## 2       10 0 0 0 0 0 0 0 0  0  0
## 3       15 0 0 0 0 5 0 0 0  0  0
## 4       16 0 0 0 0 0 0 0 1  0  0
## 5       19 0 0 0 0 0 0 0 0  0  0
## 6       31 0 0 0 0 0 0 0 0 30  0
## 7       51 0 0 0 0 0 0 0 0  0  0
## 8       52 0 0 0 0 0 0 0 0  0  0
## 9       63 0 0 0 0 0 0 0 0  0  0
## 10      78 0 0 0 0 0 0 0 0  0  0
## 11      79 0 0 0 0 0 0 1 2  0 30
## 12      86 0 0 0 0 0 0 0 0 30  0
cast(ffm, variable ~ ., c(min, max))  # range of values that each variable takes
##   variable min  max
## 1   potato   0 14.9
## 2  buttery   0 11.2
## 3   grassy   0 11.1
## 4   rancid   0 14.9
## 5   painty   0 13.1
library(ggplot2)
ggplot(ffm, aes(x = value)) + geom_bar() + facet_grid(. ~ variable)

plot of chunk unnamed-chunk-8

c. Tables of means

options(digits = 2)
cast(ffm, treatment ~ variable, mean, margins = T)
##   treatment potato buttery grassy rancid painty (all)
## 1         1    6.9     1.8   0.65    4.1    2.6   3.2
## 2         2    7.0     2.0   0.66    3.6    2.5   3.1
## 3         3    7.0     1.7   0.68    3.9    2.5   3.2
## 4     (all)    7.0     1.8   0.66    3.9    2.5   3.2

Reference

Journal of Statistical Software


Hankuk University of Foreign Studies. Dept of Statistics. Daewoo Choi Lab. Yong Cha.
한국외국어대학교 통계학과 최대우 교수 연구실 차용
e-mail : yong.stat@gmail.com