Author : tmlab / Date : 2016. 10. 4. 01:21 / Category : Lecture/R 프로그래밍
reshape2는 Hadley Wickham에 의해 작성된 R 패키지로써 wide와 long포맷으로 쉽게 데이터를 바꿀수 있게 해줍니다
wide 포맷은 각 변수들을 전부 열로 할당한 포맷입니다. 예를 들면 다음과 같습니다.
# ozone wind temp
# 1 23.62 11.623 65.55
# 2 29.44 10.267 79.10
# 3 59.12 8.942 83.90
# 4 59.96 8.794 83.97
long 포맷은 다음과 같습니다
# variable value
# 1 ozone 23.615
# 2 ozone 29.444
# 3 ozone 59.115
# 4 ozone 59.962
# 5 wind 11.623
# 6 wind 10.267
# 7 wind 8.942
# 8 wind 8.794
# 9 temp 65.548
# 10 temp 79.100
# 11 temp 83.903
# 12 temp 83.968
long 포맷 데이터는 가능한 변수들의 타입을 위한 열과 해당 변수들의 값을 위한 열을 가집니다. tidyr의 key와 value 열을 생각하시면 됩니다. 물론 long 포맷 데이터는 딱 두개의 열만 가질 필요는 없습니다. 예를 들면, 매년 일단위당 오존량의 데이터를 가지고 있을 때, 연(year)과 오존량(Ozone measurements)만이 아니라 일단위(1월 21일,22일…etc) 열도 가질 수 있습니다.
데이터 분석을 하다보면 wide 포맷이 필요할 때도 있고, long 포맷이 필요할 때도 있습니다. 현실적으로, long 포맷의 데이터가 일반적으로 많이 사용 하긴 합니다. (e.g., ggplot2(technically tidy data)나 plyr, 그리고 대부분의 모델링 함수들(lm(), glm(), gam() 등등)을 사용할때 long 포맷 데이터를 요구합니다.)
reshape2
는 기본적으로 두개의 핵심 함수를 기반으로 합니다: melt
와 cast
:
melt
함수는 wide 포맷 데이터를 long 포맷으로 변환해주는 함수입니다.
tidyr::gather()
와 유사합니다.이와 반대로 cast
는 long 포맷 데이터를 wide 포맷으로 변환해주는 함수입니다.
tidyr::spread()
와 유사합니다.melt
함수R에 내장되어 있는 airquality라는 데이터셋을 사용할 것입니다.
library(reshape2)
names(airquality) <- tolower(names(airquality))
head(airquality)
## ozone solar.r wind temp month day
## 1 41 190 7.4 67 5 1
## 2 36 118 8.0 72 5 2
## 3 12 149 12.6 74 5 3
## 4 18 313 11.5 62 5 4
## 5 NA NA 14.3 56 5 5
## 6 28 NA 14.9 66 5 6
melt
함수를 적용해보겠습니다.
aql <- melt(airquality) # [a]ir [q]uality [l]ong format
## No id variables; using all as measure variables
head(aql)
## variable value
## 1 ozone 41
## 2 ozone 36
## 3 ozone 12
## 4 ozone 18
## 5 ozone NA
## 6 ozone 28
tail(aql)
## variable value
## 913 day 25
## 914 day 26
## 915 day 27
## 916 day 28
## 917 day 29
## 918 day 30
기본적으로, melt
함수는 숫자 값을 가지고 있는 모든 열들은 value 변수라고 가정합니다. 이런 상황이 종종 내가 바라던 상황 일 수는 있지만, 지금은 일단위 오존량, 태양 복사열, 풍속 그리고 온도를 알고 싶습니다. 이럴 때 “ID variable”을 사용하면 설정을 해 줄 수 있습니다.
aql <- melt(airquality, id.vars = c("month", "day"))
head(aql)
## month day variable value
## 1 5 1 ozone 41
## 2 5 2 ozone 36
## 3 5 3 ozone 12
## 4 5 4 ozone 18
## 5 5 5 ozone NA
## 6 5 6 ozone 28
이제 이렇게 만들어진 long 포맷 데이터의 열 이름까지 지정을 해보도록 하겠습니다.
aql <- melt(airquality, id.vars = c("month", "day"),
variable.name = "climate_variable",
value.name = "climate_value")
head(aql)
## month day climate_variable climate_value
## 1 5 1 ozone 41
## 2 5 2 ozone 36
## 3 5 3 ozone 12
## 4 5 4 ozone 18
## 5 5 5 ozone NA
## 6 5 6 ozone 28
다음과 같은 ChickWeight라는 R 기본 내장 데이터셋이 있습니다.
head(ChickWeight)
## weight Time Chick Diet
## 1 42 0 1 1
## 2 51 2 1 1
## 3 59 4 1 1
## 4 64 6 1 1
## 5 76 8 1 1
## 6 93 10 1 1
해당 데이터셋에서 melt
를 사용하여 ID variable을 time,chick,diet를 주고 weight를 value로 주는 chick_m
이란 변수를 만들어보세요
## Time Chick Diet variable value
## 1 0 1 1 weight 42
## 2 2 1 1 weight 51
## 3 4 1 1 weight 59
## 4 6 1 1 weight 64
## 5 8 1 1 weight 76
## 6 10 1 1 weight 93
cast
함수wide 포맷 데이터에서 long 포맷 데이터로 변환해주는 것은 매우 간단한 반면에 long 포맷에서 wide 포맷으로 변환하는 것은 좀 더 힘들 수도 있습니다.
reshape2 패키지에서는 여러가지 cast
함수가 존재합니다. 하지만 보통 데이터프레임 객체를 사용하기 때문에, dcast
함수에 대해 설명 드리겠습니다.(벡터나 행렬, 배열 등을 반환할땐 acast
를 사용합니다.)
cast
함수를 사용하기 위해 앞에서 연습했던 aql 객체를 다시 만들어서 되돌려보겠습니다.
dcast
는 데이터의 형태를 묘사하는 식을 사용합니다.
aql <- melt(airquality, id.vars = c("month", "day"))
head(aql)
## month day variable value
## 1 5 1 ozone 41
## 2 5 2 ozone 36
## 3 5 3 ozone 12
## 4 5 4 ozone 18
## 5 5 5 ozone NA
## 6 5 6 ozone 28
aqw <- dcast(aql, month + day ~ variable)
head(aqw)
## month day ozone solar.r wind temp
## 1 5 1 41 190 7.4 67
## 2 5 2 36 118 8.0 72
## 3 5 3 12 149 12.6 74
## 4 5 4 18 313 11.5 62
## 5 5 5 NA NA 14.3 56
## 6 5 6 28 NA 14.9 66
head(airquality)
## ozone solar.r wind temp month day
## 1 41 190 7.4 67 5 1
## 2 36 118 8.0 72 5 2
## 3 12 149 12.6 74 5 3
## 4 18 313 11.5 62 5 4
## 5 NA NA 14.3 56 5 5
## 6 28 NA 14.9 66 5 6
dcast
를 통해 각 열을 재배치하여 원래 형태의 데이터로 복구한 것을 확인 할 수 있습니다.
이해가 잘 안가신다면 다음의 그림을 보세요:
Figure 1: dcast
함수에 대한 설명입니다. 파란색 음영부분은 우리가 각 행에 표시하고 싶은 “ID variables”를 나타냅니다. 빨간색 음영부분은 전환하고 싶은 열의 이름을 나타냅니다. 회색 음영부분은 각 열을 채울 데이터 값입니다.
cast
연습하기앞서 만들었던 chick_m을 dcast
를 사용하여 원래 모양대로 되돌려 출력만 해보세요
## Time Chick Diet weight
## 1 0 18 1 39
## 2 0 16 1 41
## 3 0 15 1 41
## 4 0 13 1 41
## 5 0 9 1 42
## 6 0 20 1 41
casting을 할 때 우리를 혼란스럽게 만들수도 있는 한가지 실수가 있습니다.
다음을 한번 봐보세요.
dcast(aql, month ~ variable)
## Aggregation function missing: defaulting to length
## month ozone solar.r wind temp
## 1 5 31 31 31 31
## 2 6 30 30 30 30
## 3 7 31 31 31 31
## 4 8 31 31 31 31
## 5 9 30 30 30 30
만약 해당 코드를 실행했을 경우, 다음과 같은 warning 메시지를 확인 하실 수 있습니다.
# Aggregation function missing: defaulting to length
출력한 것을 확인해보면, 각 달별로 몇개의 행이 있는지 출력되는 것을 볼 수 있습니다. 이상태로 각 cell 별로 여러가지의 값이 있는 데이터를 cast했을 때, 데이터를 aggregate(e.g., sum, mean, etc..)할 필요가 있습니다.
aggregate 함수를 적용하여 cast를 해보도록 하겠습니다. 해당 데이터셋에는 NA값이 존재함으로 NA값을 제거하는 na.rm=T
인수를 실행 할수도 있고, 하지 않을 수도 있습니다.
dcast(aql, month ~ variable, fun.aggregate = mean,
na.rm = TRUE)
## month ozone solar.r wind temp
## 1 5 23.61538 181.2963 11.622581 65.54839
## 2 6 29.44444 190.1667 10.266667 79.10000
## 3 7 59.11538 216.4839 8.941935 83.90323
## 4 8 59.96154 171.8571 8.793548 83.96774
## 5 9 31.44828 167.4333 10.180000 76.90000
chick_m을 활용해서 dcast
의 aggregation 인수를 사용하여 Diet별로 weight의 평균을 구하여 출력해보세요
## Diet weight
## 1 1 102.6455
## 2 2 122.6167
## 3 3 142.9500
## 4 4 135.2627
Aggregation 적용하여 cast
를 수행할 때, 추가로 margins 인수를 적용 할 수 있습니다. margins=T
를 주게 되면 cast된 모든 부분에 전부 aggregation 함수를 적용하게 됩니다. 또한 주어진 수식의 순서나 위치를 바꾸고 margins를 적용하게 된다면 해당 ID에 따른 각 열의 값에 aggregation 함수를 적용하게 됩니다.
#margins = T
# 달별 합계, 총 합계, 각 variable의 합계를 구하
head(dcast(aql, month + day ~ variable, sum, margins = TRUE),32)
## month day ozone solar.r wind temp (all)
## 1 5 1 41 190 7.4 67 305.4
## 2 5 2 36 118 8.0 72 234.0
## 3 5 3 12 149 12.6 74 247.6
## 4 5 4 18 313 11.5 62 404.5
## 5 5 5 NA NA 14.3 56 NA
## 6 5 6 28 NA 14.9 66 NA
## 7 5 7 23 299 8.6 65 395.6
## 8 5 8 19 99 13.8 59 190.8
## 9 5 9 8 19 20.1 61 108.1
## 10 5 10 NA 194 8.6 69 NA
## 11 5 11 7 NA 6.9 74 NA
## 12 5 12 16 256 9.7 69 350.7
## 13 5 13 11 290 9.2 66 376.2
## 14 5 14 14 274 10.9 68 366.9
## 15 5 15 18 65 13.2 58 154.2
## 16 5 16 14 334 11.5 64 423.5
## 17 5 17 34 307 12.0 66 419.0
## 18 5 18 6 78 18.4 57 159.4
## 19 5 19 30 322 11.5 68 431.5
## 20 5 20 11 44 9.7 62 126.7
## 21 5 21 1 8 9.7 59 77.7
## 22 5 22 11 320 16.6 73 420.6
## 23 5 23 4 25 9.7 61 99.7
## 24 5 24 32 92 12.0 61 197.0
## 25 5 25 NA 66 16.6 57 NA
## 26 5 26 NA 266 14.9 58 NA
## 27 5 27 NA NA 8.0 57 NA
## 28 5 28 23 13 12.0 67 115.0
## 29 5 29 45 252 14.9 81 392.9
## 30 5 30 115 223 5.7 79 422.7
## 31 5 31 37 279 7.4 76 399.4
## 32 5 (all) NA NA 360.3 2032 NA
# month + day ~ variable 식에서 margins="day" 별 sum
head(dcast(aql, month + day ~ variable, sum, margins="day",na.rm=T),32)
## month day ozone solar.r wind temp
## 1 5 1 41 190 7.4 67
## 2 5 2 36 118 8.0 72
## 3 5 3 12 149 12.6 74
## 4 5 4 18 313 11.5 62
## 5 5 5 0 0 14.3 56
## 6 5 6 28 0 14.9 66
## 7 5 7 23 299 8.6 65
## 8 5 8 19 99 13.8 59
## 9 5 9 8 19 20.1 61
## 10 5 10 0 194 8.6 69
## 11 5 11 7 0 6.9 74
## 12 5 12 16 256 9.7 69
## 13 5 13 11 290 9.2 66
## 14 5 14 14 274 10.9 68
## 15 5 15 18 65 13.2 58
## 16 5 16 14 334 11.5 64
## 17 5 17 34 307 12.0 66
## 18 5 18 6 78 18.4 57
## 19 5 19 30 322 11.5 68
## 20 5 20 11 44 9.7 62
## 21 5 21 1 8 9.7 59
## 22 5 22 11 320 16.6 73
## 23 5 23 4 25 9.7 61
## 24 5 24 32 92 12.0 61
## 25 5 25 0 66 16.6 57
## 26 5 26 0 266 14.9 58
## 27 5 27 0 0 8.0 57
## 28 5 28 23 13 12.0 67
## 29 5 29 45 252 14.9 81
## 30 5 30 115 223 5.7 79
## 31 5 31 37 279 7.4 76
## 32 5 (all) 614 4895 360.3 2032
# day + month ~ variable 식에서 margins="month" 별 sum
head(dcast(aql, day + month ~ variable, sum, margins="month",na.rm=T),8)
## day month ozone solar.r wind temp
## 1 1 5 41 190 7.4 67
## 2 1 6 0 286 8.6 78
## 3 1 7 135 269 4.1 84
## 4 1 8 39 83 6.9 81
## 5 1 9 96 167 6.9 91
## 6 1 (all) 311 995 33.9 401
## 7 2 5 36 118 8.0 72
## 8 2 6 0 287 9.7 74
chick_m을 활용하여 dcast
의 aggregation과 margins를 사용하여 Diet별 Time에 따른 weight의 평균을 구하시오
## Diet Time weight
## 1 1 0 41.40000
## 2 1 2 47.25000
## 3 1 4 56.47368
## 4 1 6 66.78947
## 5 1 8 79.68421
## 6 1 10 93.05263
## 7 1 12 108.52632
## 8 1 14 123.38889
## 9 1 16 144.64706
## 10 1 18 158.94118
## 11 1 20 170.41176
## 12 1 21 177.75000
## 13 1 (all) 102.64545
## 14 2 0 40.70000
magrittr 패키지는 연산자(operator)들의 집합들을 제공합니다.
해당 패키지의 장점은 다음과 같습니다.
저희는 그 중에서 데이터 연산을 왼쪽에서 오른쪽 순서로 구조화하는 부분(main operator)만 다뤄보겠습니다. 해당 부분은 dplyr에서도 설명을 드렸지만 f(x)를 x %>% f()로 대체할 수 있습니다. 이 연산자가 main operator인데 해당 기능이 의미 없이 보이시겠지만 여러가지 기능을 결합할 때 그 이점이 더욱 명확해집니다.
library(magrittr)
car_data <-
mtcars %>% #1
subset(hp > 100) %>% #2
aggregate(. ~ cyl, data = ., FUN = . %>% mean %>% round(2)) %>% #3
transform(kpl = mpg %>% multiply_by(0.4251)) %>% #4
print #5
## cyl mpg disp hp drat wt qsec vs am gear carb kpl
## 1 4 25.90 108.05 111.00 3.94 2.15 17.75 1.00 1.00 4.50 2.00 11.010090
## 2 6 19.74 183.31 122.29 3.59 3.12 17.98 0.57 0.43 3.86 3.43 8.391474
## 3 8 15.10 353.10 209.21 3.23 4.00 16.77 0.00 0.14 3.29 3.50 6.419010
해석을 해보도록 하겠습니다.
체인을 사용하지 않고 위의 과정을 작성해보겠습니다.
car_data <-
transform(aggregate(. ~ cyl,
data = subset(mtcars, hp > 100),
FUN = function(x) round(mean(x),2)),
kpl = mpg*0.4251)
car_data
## cyl mpg disp hp drat wt qsec vs am gear carb kpl
## 1 4 25.90 108.05 111.00 3.94 2.15 17.75 1.00 1.00 4.50 2.00 11.010090
## 2 6 19.74 183.31 122.29 3.59 3.12 17.98 0.57 0.43 3.86 3.43 8.391474
## 3 8 15.10 353.10 209.21 3.23 4.00 16.77 0.00 0.14 3.29 3.50 6.419010
어떤 순서로 데이터 처리가 이루어지는지 알기가 힘듭니다.
“.”의 역할에 대해서 알아봅시다. 일반적으로 %>%
연산자만 사용하시게 되면 제일 첫 인수에 자동으로 배정이 됩니다
iris %>% head(3)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
head(iris,3)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
하지만 데이터를 넘겨줘야 할 인수의 위치가 첫번째가 아닐 경우 다음과 같은 에러를 확인할 수 있습니다.
gsub()
는 찾아 바꾸는 함수로써, 사용방법은 gsub(찾을문자나 숫자,바꿀문자나 숫자, 데이터)
입니다.a<-c("bannananana","an apple")
gsub("n","l",a)
## [1] "ballalalala" "al apple"
a %>% gsub("n","l")
## Warning in gsub(., "n", "l"): 인자 'pattern'는 반드시 길이가 1 보다 커야 하
## 고, 오로지 첫번째 요소만이 사용될 것입니다
## [1] "l"
이러한 상황일 때, “.”을 원하는 위치에 넣어주시면 해당 위치에 데이터가 넘어가는 것을 확인 하실 수 있습니다
gsub("n","l",a)
## [1] "ballalalala" "al apple"
a %>% gsub("n","l",.)
## [1] "ballalalala" "al apple"
“.”은 magrittr나 dplyr에만 속해 있는 것이 아니라 R의 base에 정해진 규칙으로 가끔 수식 같은데에 보는 .~cyl
의 사용법과 같습니다.
다음은 2013년 전기판매량 DB 정보입니다.
electro <- read.csv("https://raw.githubusercontent.com/halrequin/data/master/2013%20electronic%20sales.csv",encoding = "utf8",stringsAsFactors = F)
electro
## 년도 월별 발전사업 신재생에너지.사업 구역전기사업 판매량계
## 1 2013년 01월 1007669 19044 80879 1107593
## 2 2013년 02월 896520 20183 58494 975197
## 3 2013년 03월 903324 27337 25720 956382
## 4 2013년 04월 699198 22034 24896 746129
## 5 2013년 05월 359788 31664 34431 425883
## 6 2013년 06월 648183 30766 12542 691492
## 7 2013년 07월 672404 25042 13943 711391
## 8 2013년 08월 692610 5913 17088 715612
## 9 2013년 09월 451409 23978 12205 487593
## 10 2013년 10월 760366 40902 14434 815703
## 11 2013년 11월 931629 107 25797 957535
## 12 2013년 12월 986468 23654 32688 1042812
melt
를 사용하여 id는 년도와 월별을, variable은 나머지 행으로 하여 long 포맷 데이터를 만들어 elec_long 변수를 만들어보세요.## 년도 월별 variable value
## 1 2013년 01월 발전사업 1007669
## 2 2013년 02월 발전사업 896520
## 3 2013년 03월 발전사업 903324
## 4 2013년 04월 발전사업 699198
## 5 2013년 05월 발전사업 359788
## 6 2013년 06월 발전사업 648183
elec_long
변수를 활용하여 dcast
를 적용하여 2013년도 각 열들의 sum을 출력하세요.## 년도 발전사업 신재생에너지.사업 구역전기사업 판매량계
## 1 2013년 9009568 270624 353117 9633322
elec_long
변수를 활용하여 dcast
를 적용하여 2013년도 각 달별로 모든 부분에서의 sum을 출력하세요.## 년도 월별 발전사업 신재생에너지.사업 구역전기사업 판매량계 (all)
## 1 2013년 01월 1007669 19044 80879 1107593 2215185
## 2 2013년 02월 896520 20183 58494 975197 1950394
## 3 2013년 03월 903324 27337 25720 956382 1912763
## 4 2013년 04월 699198 22034 24896 746129 1492257
## 5 2013년 05월 359788 31664 34431 425883 851766
## 6 2013년 06월 648183 30766 12542 691492 1382983
## 7 2013년 07월 672404 25042 13943 711391 1422780
## 8 2013년 08월 692610 5913 17088 715612 1431223
## 9 2013년 09월 451409 23978 12205 487593 975185
## 10 2013년 10월 760366 40902 14434 815703 1631405
## 11 2013년 11월 931629 107 25797 957535 1915068
## 12 2013년 12월 986468 23654 32688 1042812 2085622
## 13 2013년 (all) 9009568 270624 353117 9633322 19266631
## 14 (all) (all) 9009568 270624 353117 9633322 19266631
elec_long
변수를 활용하여 dcast
를 적용하여 원래의 electro의 모양대로 wide 포맷데이터로 변환하여 저장하시오## 년도 월별 발전사업 신재생에너지.사업 구역전기사업 판매량계
## 1 2013년 01월 1007669 19044 80879 1107593
## 2 2013년 02월 896520 20183 58494 975197
## 3 2013년 03월 903324 27337 25720 956382
## 4 2013년 04월 699198 22034 24896 746129
## 5 2013년 05월 359788 31664 34431 425883
## 6 2013년 06월 648183 30766 12542 691492
## 7 2013년 07월 672404 25042 13943 711391
## 8 2013년 08월 692610 5913 17088 715612
## 9 2013년 09월 451409 23978 12205 487593
## 10 2013년 10월 760366 40902 14434 815703
## 11 2013년 11월 931629 107 25797 957535
## 12 2013년 12월 986468 23654 32688 1042812