실제 데이터를 접하게 되면 데이터를 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에 대해 간략히 설명하겠다.
melt()와 cast()에 대한 개략적인 이해를 위해 'smiths' 데이터를 통해 살펴보자. 'smiths' 데이터 역시 reshape package에 있는 built-in data이다.
melt 와 _cast_는 제철 작업에 있어 철을 용해하고 주조하여 단단한 철을 만들어내는 것과 같이 데이터를 분석에 용이하게 하기 위해 전처리 작업을 하는 것이다.
melt() function을 사용할 때 identifier(이하 id)와 measured variable을 구분하는 것은 매우 중요하다. 즉, 어떤 변수가 measured variable인지 id variable인지 알아야 할 필요가 있다.
measured variable : 측정 대상이 되는 변수. 쉽게 말하면 categorize되는 변수이다.
melt()는 id variable을 기준으로 하고 measured variable를 categorize하여 Variable이라는 새로운 column을 생성하고 Value라는 column에 Variable에 해당하는 값들을 넣어 주어 새로이 Data frame을 만들어준다.
## 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은 나타나지 않게 해준다.
cast()는 melt() function을 적용한 data frame(혹은 object)을 사용자가 원하는 모양으로 재배열을 할 수 있게 해주는 함수이다.
- 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.
- fun.aggregate : length(default), mean, sum, ...
- margins : sub total, grand total ("grand_row", "grand_col")
- '.' 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
아래에는 이 데이터의 일부분이다.
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
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)
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
Journal of Statistical Software
Hankuk University of Foreign Studies. Dept of Statistics. Daewoo Choi Lab. Yong Cha.
한국외국어대학교 통계학과 최대우 교수 연구실 차용
e-mail : yong.stat@gmail.com