Aggregate 와 Plyr
Aggregate
Aggregate는 SQL의 group by 와 유사한 기능을 합니다.
require(ggplot2)
## Loading required package: ggplot2
data(diamonds)
head(diamonds)
## # A tibble: 6 × 10
## carat cut color clarity depth table price x y z
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 3 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31
## 4 0.29 Premium I VS2 62.4 58 334 4.20 4.23 2.63
## 5 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75
## 6 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48
# Cut 으로 Price 가 집계됨을 뜻함.
aggregate(price ~ cut, diamonds, mean)
## cut price
## 1 Fair 4358.758
## 2 Good 3928.864
## 3 Very Good 3981.760
## 4 Premium 4584.258
## 5 Ideal 3457.542
# 더하기로 추가 변수를 지정하여 여러개의 변수로 데이터를 그룹화
aggregate(price ~ cut + color, diamonds, mean)
## cut color price
## 1 Fair D 4291.061
## 2 Good D 3405.382
## 3 Very Good D 3470.467
## 4 Premium D 3631.293
## 5 Ideal D 2629.095
## 6 Fair E 3682.312
## 7 Good E 3423.644
## 8 Very Good E 3214.652
## 9 Premium E 3538.914
## 10 Ideal E 2597.550
## 11 Fair F 3827.003
## 12 Good F 3495.750
## 13 Very Good F 3778.820
## 14 Premium F 4324.890
## 15 Ideal F 3374.939
## 16 Fair G 4239.255
## 17 Good G 4123.482
## 18 Very Good G 3872.754
## 19 Premium G 4500.742
## 20 Ideal G 3720.706
## 21 Fair H 5135.683
## 22 Good H 4276.255
## 23 Very Good H 4535.390
## 24 Premium H 5216.707
## 25 Ideal H 3889.335
## 26 Fair I 4685.446
## 27 Good I 5078.533
## 28 Very Good I 5255.880
## 29 Premium I 5946.181
## 30 Ideal I 4451.970
## 31 Fair J 4975.655
## 32 Good J 4574.173
## 33 Very Good J 5103.513
## 34 Premium J 6294.592
## 35 Ideal J 4918.186
aggregate(cbind(price, carat) ~ cut, diamonds, mean)
## cut price carat
## 1 Fair 4358.758 1.0461366
## 2 Good 3928.864 0.8491847
## 3 Very Good 3981.760 0.8063814
## 4 Premium 4584.258 0.8919549
## 5 Ideal 3457.542 0.7028370
aggregate(cbind(price, carat) ~ cut + color, diamonds, mean)
## cut color price carat
## 1 Fair D 4291.061 0.9201227
## 2 Good D 3405.382 0.7445166
## 3 Very Good D 3470.467 0.6964243
## 4 Premium D 3631.293 0.7215471
## 5 Ideal D 2629.095 0.5657657
## 6 Fair E 3682.312 0.8566071
## 7 Good E 3423.644 0.7451340
## 8 Very Good E 3214.652 0.6763167
## 9 Premium E 3538.914 0.7177450
## 10 Ideal E 2597.550 0.5784012
## 11 Fair F 3827.003 0.9047115
## 12 Good F 3495.750 0.7759296
## 13 Very Good F 3778.820 0.7409612
## 14 Premium F 4324.890 0.8270356
## 15 Ideal F 3374.939 0.6558285
## 16 Fair G 4239.255 1.0238217
## 17 Good G 4123.482 0.8508955
## 18 Very Good G 3872.754 0.7667986
## 19 Premium G 4500.742 0.8414877
## 20 Ideal G 3720.706 0.7007146
## 21 Fair H 5135.683 1.2191749
## 22 Good H 4276.255 0.9147293
## 23 Very Good H 4535.390 0.9159485
## 24 Premium H 5216.707 1.0164492
## 25 Ideal H 3889.335 0.7995249
## 26 Fair I 4685.446 1.1980571
## 27 Good I 5078.533 1.0572222
## 28 Very Good I 5255.880 1.0469518
## 29 Premium I 5946.181 1.1449370
## 30 Ideal I 4451.970 0.9130291
## 31 Fair J 4975.655 1.3411765
## 32 Good J 4574.173 1.0995440
## 33 Very Good J 5103.513 1.1332153
## 34 Premium J 6294.592 1.2930941
## 35 Ideal J 4918.186 1.0635937
plyr
plyr 의 핵심은 ddply, llply, ldply 같은 함수들로 구성된다.
ddply
- ddply 는 data.frame을 입력으로 받아 변수에 따라 입력을 분리하고 분리된 각 부분에 대해 지정된 작업을 수행 후 data.frame 형태로 리턴한다.
require(plyr)
## Loading required package: plyr
head(baseball)
## id year stint team lg g ab r h X2b X3b hr rbi sb cs bb so
## 4 ansonca01 1871 1 RC1 25 120 29 39 11 3 0 16 6 2 2 1
## 44 forceda01 1871 1 WS3 32 162 45 45 9 4 0 29 8 0 4 0
## 68 mathebo01 1871 1 FW1 19 89 15 24 3 1 0 10 2 1 2 0
## 99 startjo01 1871 1 NY2 33 161 35 58 5 1 1 34 4 2 3 0
## 102 suttoez01 1871 1 CL1 29 128 35 45 3 7 3 23 3 1 1 0
## 106 whitede01 1871 1 CL1 29 146 40 47 6 5 1 21 2 2 4 1
## ibb hbp sh sf gidp
## 4 NA NA NA NA NA
## 44 NA NA NA NA NA
## 68 NA NA NA NA NA
## 99 NA NA NA NA NA
## 102 NA NA NA NA NA
## 106 NA NA NA NA NA
#출루율 계산방법
# 출루율 = H(안타) + BB(볼넷) + HBP(사구) / AB(타수) + BB(볼넷) + HBP(사구) + SF(희생 플라이)
#데이터 일부 추출
#규칙 변화로 인한 1954년 이전 희생 플라이는 0 으로 처리
baseball$sf[baseball$year < 1954] <- 0
#잘 되었나 확인
any(is.na(baseball$sf))
## [1] FALSE
#hbp 가 NA 인 경우가 있어 NA 를 0으로 설정
baseball$hbp[is.na(baseball$hbp)] <- 0
#제대로 되었나 확인
any(is.na(baseball$hbp))
## [1] FALSE
#한시즌에 50타석 이상인 선수만 남겨둠
baseball <- baseball[baseball$ab >= 50, ]
#특정연도 특정선수 OBP 계산은 vector 연산으로 쉽게 가능
#with 함수는 data frame 의 이름을 명시하지 않고 열을 지정할 수 있도록 해줌
baseball$OBP <- with(baseball, (h+bb+hbp) / sum(ab+bb+hbp+sf))
tail(baseball)
## id year stint team lg g ab r h X2b X3b hr rbi sb cs bb
## 89499 claytro01 2007 1 TOR AL 69 189 23 48 14 0 1 12 2 1 14
## 89502 cirilje01 2007 1 MIN AL 50 153 18 40 9 2 2 21 2 0 15
## 89521 bondsba01 2007 1 SFN NL 126 340 75 94 14 0 28 66 5 0 132
## 89523 biggicr01 2007 1 HOU NL 141 517 68 130 31 3 10 50 4 3 23
## 89530 ausmubr01 2007 1 HOU NL 117 349 38 82 16 3 3 25 6 1 37
## 89533 aloumo01 2007 1 NYN NL 87 328 51 112 19 1 13 49 3 0 27
## so ibb hbp sh sf gidp OBP
## 89499 50 0 1 3 3 8 1.178054e-05
## 89502 13 0 1 3 2 9 1.047159e-05
## 89521 54 43 3 0 2 13 4.282133e-05
## 89523 112 0 3 7 5 5 2.917086e-05
## 89530 74 3 6 4 1 11 2.337409e-05
## 89533 30 5 2 0 3 13 2.636597e-05
#계산 수행하는 함수 만들고 ddply 사용하여 각 선수에 대해 계산 수행
obp <- function(data) {
c(OBP = with(data, sum(h+bb+hbp) / sum(ab+bb+hbp+sf)))
}
#각 선수에 대한 커리어 OBP 를 계산하기 위해 ddply 를 사용
#SQL group by 의 by 에 해당한다. fun 은 function 의 obp
careerOBP <- ddply(baseball, .variables = "id", .fun = obp)
#OBP로 결과를 정렬한다.
careerOBP <- careerOBP[order(careerOBP$OBP, decreasing = TRUE), ]
#결과를 확인한다.
head(careerOBP, 10)
## id OBP
## 1089 willite01 0.4816861
## 875 ruthba01 0.4742209
## 658 mcgrajo01 0.4657478
## 356 gehrilo01 0.4477848
## 85 bondsba01 0.4444622
## 476 hornsro01 0.4339068
## 184 cobbty01 0.4329655
## 327 foxxji01 0.4290509
## 953 speaktr01 0.4283386
## 191 collied01 0.4251246
llply
결과값을 반환할때
theList <- list(A = matrix(1:9, 3), B = 1:5, C = matrix(1:4, 2), D = 2)
lapply(theList, sum)
## $A
## [1] 45
##
## $B
## [1] 15
##
## $C
## [1] 10
##
## $D
## [1] 2
llply(theList, sum)
## $A
## [1] 45
##
## $B
## [1] 15
##
## $C
## [1] 10
##
## $D
## [1] 2
#list로 반환
sapply(theList, sum)
## A B C D
## 45 15 10 2
laply(theList, sum)
## [1] 45 15 10 2
#Vector 로 반환하지만 이름있음
sapply(theList, sum)
## A B C D
## 45 15 10 2
#Vector로 반환하지만 이름 없음
laply(theList, sum)
## [1] 45 15 10 2
plyr 보조함수
each 는 aggregate 함수에 여러 함수 사용 할 수 있게 해준다.
aggregate(price ~ cut, diamonds, each(mean, median))
## cut price.mean price.median
## 1 Fair 4358.758 3282.000
## 2 Good 3928.864 3050.500
## 3 Very Good 3981.760 2648.000
## 4 Premium 4584.258 3185.000
## 5 Ideal 3457.542 1810.000
data.table
require(data.table)
## Loading required package: data.table
# Data Frame 생성
theDF <- data.frame(A = 1:10,
B = letters[1:10],
C = LETTERS[11:20],
D = rep(c("One", "Two", "Three"), length.out = 10))
# 하나의 data.table을 생성
theDT <- data.table(A = 1:10,
B = letters[1:10],
C = LETTERS[11:20],
D = rep(c("One", "Two", "Three"), length.out = 10))
#두개비교
theDF
## A B C D
## 1 1 a K One
## 2 2 b L Two
## 3 3 c M Three
## 4 4 d N One
## 5 5 e O Two
## 6 6 f P Three
## 7 7 g Q One
## 8 8 h R Two
## 9 9 i S Three
## 10 10 j T One
theDT
## A B C D
## 1: 1 a K One
## 2: 2 b L Two
## 3: 3 c M Three
## 4: 4 d N One
## 5: 5 e O Two
## 6: 6 f P Three
## 7: 7 g Q One
## 8: 8 h R Two
## 9: 9 i S Three
## 10: 10 j T One
# Data frame 은 문자 데이터를 factor로 변환
# Data table 은 character 로 남겨둠
class(theDF$B)
## [1] "factor"
class(theDT$B)
## [1] "character"
# Data frame을 Data table 로 변환도 가능
diamondsDT <- data.table(diamonds)
diamondsDT
## carat cut color clarity depth table price x y z
## 1: 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2: 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
## 3: 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31
## 4: 0.29 Premium I VS2 62.4 58 334 4.20 4.23 2.63
## 5: 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75
## ---
## 53936: 0.72 Ideal D SI1 60.8 57 2757 5.75 5.76 3.50
## 53937: 0.72 Good D SI1 63.1 55 2757 5.69 5.75 3.61
## 53938: 0.70 Very Good D SI1 62.8 60 2757 5.66 5.68 3.56
## 53939: 0.86 Premium H SI2 61.0 58 2757 6.15 6.12 3.74
## 53940: 0.75 Ideal D SI2 62.2 55 2757 5.83 5.87 3.64
#Data.table 은 첫 다섯줄과 끝 다섯줄만 출력함
#행의 접근방법은 data.frame 행 접근법과 동일함
theDT[1:2, ]
## A B C D
## 1: 1 a K One
## 2: 2 b L Two
theDT[theDT$A >= 7, ]
## A B C D
## 1: 7 g Q One
## 2: 8 h R Two
## 3: 9 i S Three
## 4: 10 j T One
#data.table 에서는 열들을 character가 아닌 실제 이름의 list 로 명시
theDT[, list(A,C)]
## A C
## 1: 1 K
## 2: 2 L
## 3: 3 M
## 4: 4 N
## 5: 5 O
## 6: 6 P
## 7: 7 Q
## 8: 8 R
## 9: 9 S
## 10: 10 T
#하나의 열만 선택
theDT[, B]
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
#data.table의 구조를 유지하면서 하나의 열을 선택
theDT[, list(B)]
## B
## 1: a
## 2: b
## 3: c
## 4: d
## 5: e
## 6: f
## 7: g
## 8: h
## 9: i
## 10: j
#열 이름이 함수의 인자로 전달될 수도 있기 때문에, character 로 열 이름을 명시해야 한다면 with 를 FALSE 로 둠
b <- "B"
theDT[, b, with = FALSE]
## B
## 1: a
## 2: b
## 3: c
## 4: d
## 5: e
## 6: f
## 7: g
## 8: h
## 9: i
## 10: j
theDT[, c("A", "C"), with = FALSE]
## A C
## 1: 1 K
## 2: 2 L
## 3: 3 M
## 4: 4 N
## 5: 5 O
## 6: 6 P
## 7: 7 Q
## 8: 8 R
## 9: 9 S
## 10: 10 T
# 이러한 사용방식은 list 대신 vector에 열 이름을 지정한 것이다.
키(key)
#몇 가지 data.table이 메모리에 있으며 그것에 대한 많은 정보를 볼 수 있는지 알려줌
tables()
## NAME NROW NCOL MB
## [1,] diamondsDT 53,940 10 4
## [2,] theDT 10 4 1
## COLS KEY
## [1,] carat,cut,color,clarity,depth,table,price,x,y,z
## [2,] A,B,C,D
## Total: 5MB
#Key 는 data.table 열을 인덱싱하는데 사용되며 속도 향상을 제공함
# 키 설정법
setkey(theDT, D)
# data Table 다시보기
tables()
## NAME NROW NCOL MB
## [1,] diamondsDT 53,940 10 4
## [2,] theDT 10 4 1
## COLS KEY
## [1,] carat,cut,color,clarity,depth,table,price,x,y,z
## [2,] A,B,C,D D
## Total: 5MB
key(theDT)
## [1] "D"
#키 열의 값으로도 행 선택이 가능하다.
theDT["One", ]
## A B C D
## 1: 1 a K One
## 2: 4 d N One
## 3: 7 g Q One
## 4: 10 j T One
theDT[c("One", "Two"), ]
## A B C D
## 1: 1 a K One
## 2: 4 d N One
## 3: 7 g Q One
## 4: 10 j T One
## 5: 2 b L Two
## 6: 5 e O Two
## 7: 8 h R Two
# 다수의 열도 키 설정 가능
setkey(diamondsDT, cut, color)
#모든 키에 따라 행에 접근하기 위한 J 함수가 있음
#J 함수는 여러 인자를 취하는데 각각은 선택할 값의 vector 임
diamondsDT[J("Ideal", "E"), ]
## carat cut color clarity depth table price x y z
## 1: 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2: 0.26 Ideal E VVS2 62.9 58 554 4.02 4.06 2.54
## 3: 0.70 Ideal E SI1 62.5 57 2757 5.70 5.72 3.57
## 4: 0.59 Ideal E VVS2 62.0 55 2761 5.38 5.43 3.35
## 5: 0.74 Ideal E SI2 62.2 56 2761 5.80 5.84 3.62
## ---
## 3899: 0.70 Ideal E SI1 61.7 55 2745 5.71 5.74 3.53
## 3900: 0.51 Ideal E VVS1 61.9 54 2745 5.17 5.11 3.18
## 3901: 0.56 Ideal E VVS1 62.1 56 2750 5.28 5.29 3.28
## 3902: 0.77 Ideal E SI2 62.1 56 2753 5.84 5.86 3.63
## 3903: 0.71 Ideal E SI1 61.9 56 2756 5.71 5.73 3.54
diamondsDT[J("Ideal", c("E", "D"))]
## carat cut color clarity depth table price x y z
## 1: 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43
## 2: 0.26 Ideal E VVS2 62.9 58 554 4.02 4.06 2.54
## 3: 0.70 Ideal E SI1 62.5 57 2757 5.70 5.72 3.57
## 4: 0.59 Ideal E VVS2 62.0 55 2761 5.38 5.43 3.35
## 5: 0.74 Ideal E SI2 62.2 56 2761 5.80 5.84 3.62
## ---
## 6733: 0.51 Ideal D VVS2 61.7 56 2742 5.16 5.14 3.18
## 6734: 0.51 Ideal D VVS2 61.3 57 2742 5.17 5.14 3.16
## 6735: 0.81 Ideal D SI1 61.5 57 2748 6.00 6.03 3.70
## 6736: 0.72 Ideal D SI1 60.8 57 2757 5.75 5.76 3.50
## 6737: 0.75 Ideal D SI2 62.2 55 2757 5.83 5.87 3.64
data.table 집계
data.table의 내장된 집계 기능은 상당히 빠르다.
#aggregate group by 하는 경우
aggregate(price ~ cut, diamonds, mean)
## cut price
## 1 Fair 4358.758
## 2 Good 3928.864
## 3 Very Good 3981.760
## 4 Premium 4584.258
## 5 Ideal 3457.542
# data.table을 사용하여 같은 결과 내는 방법
diamondsDT[, mean(price), by = cut]
## cut V1
## 1: Fair 4358.758
## 2: Good 3928.864
## 3: Very Good 3981.760
## 4: Premium 4584.258
## 5: Ideal 3457.542
diamondsDT[, list(price = mean(price)), by = cut]
## cut price
## 1: Fair 4358.758
## 2: Good 3928.864
## 3: Very Good 3981.760
## 4: Premium 4584.258
## 5: Ideal 3457.542
# 여러 열에 대해 집계하기 위해 list() 로 해당 열을 지정
diamondsDT[, mean(price), by = list(cut, color)]
## cut color V1
## 1: Fair D 4291.061
## 2: Fair E 3682.312
## 3: Fair F 3827.003
## 4: Fair G 4239.255
## 5: Fair H 5135.683
## 6: Fair I 4685.446
## 7: Fair J 4975.655
## 8: Good D 3405.382
## 9: Good E 3423.644
## 10: Good F 3495.750
## 11: Good G 4123.482
## 12: Good H 4276.255
## 13: Good I 5078.533
## 14: Good J 4574.173
## 15: Very Good D 3470.467
## 16: Very Good E 3214.652
## 17: Very Good F 3778.820
## 18: Very Good G 3872.754
## 19: Very Good H 4535.390
## 20: Very Good I 5255.880
## 21: Very Good J 5103.513
## 22: Premium D 3631.293
## 23: Premium E 3538.914
## 24: Premium F 4324.890
## 25: Premium G 4500.742
## 26: Premium H 5216.707
## 27: Premium I 5946.181
## 28: Premium J 6294.592
## 29: Ideal D 2629.095
## 30: Ideal E 2597.550
## 31: Ideal F 3374.939
## 32: Ideal G 3720.706
## 33: Ideal H 3889.335
## 34: Ideal I 4451.970
## 35: Ideal J 4918.186
## cut color V1
#aggregate 와 다르게 각 열에 대해 다른 메트릭이 계산될 수 있다.
diamondsDT[, list(price = mean(price), carat = mean(carat)), by = cut]
## cut price carat
## 1: Fair 4358.758 1.0461366
## 2: Good 3928.864 0.8491847
## 3: Very Good 3981.760 0.8063814
## 4: Premium 4584.258 0.8919549
## 5: Ideal 3457.542 0.7028370
diamondsDT[, list(price = mean(price), carat = mean(carat), caratsum = sum(carat)), by = cut]
## cut price carat caratsum
## 1: Fair 4358.758 1.0461366 1684.28
## 2: Good 3928.864 0.8491847 4166.10
## 3: Very Good 3981.760 0.8063814 9742.70
## 4: Premium 4584.258 0.8919549 12300.95
## 5: Ideal 3457.542 0.7028370 15146.84
#다수의 메트릭에 대한 계산과 다수의 변수에 대한 그룹화는 동시에 가능
diamondsDT[, list(price = mean(price), carat = mean(carat)), by = list(cut, color)]
## cut color price carat
## 1: Fair D 4291.061 0.9201227
## 2: Fair E 3682.312 0.8566071
## 3: Fair F 3827.003 0.9047115
## 4: Fair G 4239.255 1.0238217
## 5: Fair H 5135.683 1.2191749
## 6: Fair I 4685.446 1.1980571
## 7: Fair J 4975.655 1.3411765
## 8: Good D 3405.382 0.7445166
## 9: Good E 3423.644 0.7451340
## 10: Good F 3495.750 0.7759296
## 11: Good G 4123.482 0.8508955
## 12: Good H 4276.255 0.9147293
## 13: Good I 5078.533 1.0572222
## 14: Good J 4574.173 1.0995440
## 15: Very Good D 3470.467 0.6964243
## 16: Very Good E 3214.652 0.6763167
## 17: Very Good F 3778.820 0.7409612
## 18: Very Good G 3872.754 0.7667986
## 19: Very Good H 4535.390 0.9159485
## 20: Very Good I 5255.880 1.0469518
## 21: Very Good J 5103.513 1.1332153
## 22: Premium D 3631.293 0.7215471
## 23: Premium E 3538.914 0.7177450
## 24: Premium F 4324.890 0.8270356
## 25: Premium G 4500.742 0.8414877
## 26: Premium H 5216.707 1.0164492
## 27: Premium I 5946.181 1.1449370
## 28: Premium J 6294.592 1.2930941
## 29: Ideal D 2629.095 0.5657657
## 30: Ideal E 2597.550 0.5784012
## 31: Ideal F 3374.939 0.6558285
## 32: Ideal G 3720.706 0.7007146
## 33: Ideal H 3889.335 0.7995249
## 34: Ideal I 4451.970 0.9130291
## 35: Ideal J 4918.186 1.0635938
## cut color price carat