지난번 포스팅에서는 R data.table에서 .SD[]와 by를 사용해서 그룹별로 부분집합 가져오기 (Group Subsetting) 하는 방법을 소개하였습니다. (rfriend.tistory.com/611)
이번 포스팅에서는 R data.table에서 .SD[which.max()], .SD[which.min()]과 by 를 사용해서 그룹별로 최소값 행, 최대값 행을 indexing해서 가져오는 방법(Group Optima)을 소개하겠습니다.
(1) 그룹별로 특정 칼럼의 최대값인 행 가져오기 (get the minumum row for each group)
(2) 그룹별로 특정 칼럼의 최소값인 행 가져오기 (get the maximum row for each group)
먼저, data.table 패키지를 불러오고, 예제로 사용할 데이터로 Lahman 패키지에 들어있는 야구 팀들의 통계 데이터인 'Teams' 데이터셋을 Data.Table로 참조해서 불러오겠습니다.
library(data.table)
## Lahman database on baseball
#install.packages("Lahman")
library(Lahman)
data("Teams")
## coerce lists and data.frame to data.table by reference
setDT(Teams)
str(Teams)
# Classes 'data.table' and 'data.frame': 2925 obs. of 48 variables:
# $ yearID : int 1871 1871 1871 1871 1871 1871 1871 1871 1871 1872 ...
# $ lgID : Factor w/ 7 levels "AA","AL","FL",..: 4 4 4 4 4 4 4 4 4 4 ...
# $ teamID : Factor w/ 149 levels "ALT","ANA","ARI",..: 24 31 39 56 90 97 111 136 142 8 ...
# $ franchID : Factor w/ 120 levels "ALT","ANA","ARI",..: 13 36 25 56 70 85 91 109 77 9 ...
# $ divID : chr NA NA NA NA ...
# $ Rank : int 3 2 8 7 5 1 9 6 4 2 ...
# $ G : int 31 28 29 19 33 28 25 29 32 58 ...
# $ Ghome : int NA NA NA NA NA NA NA NA NA NA ...
# $ W : int 20 19 10 7 16 21 4 13 15 35 ...
# $ L : int 10 9 19 12 17 7 21 15 15 19 ...
# $ DivWin : chr NA NA NA NA ...
# $ WCWin : chr NA NA NA NA ...
# $ LgWin : chr "N" "N" "N" "N" ...
# $ WSWin : chr NA NA NA NA ...
# $ R : int 401 302 249 137 302 376 231 351 310 617 ...
# $ AB : int 1372 1196 1186 746 1404 1281 1036 1248 1353 2571 ...
# $ H : int 426 323 328 178 403 410 274 384 375 753 ...
# $ X2B : int 70 52 35 19 43 66 44 51 54 106 ...
# $ X3B : int 37 21 40 8 21 27 25 34 26 31 ...
# $ HR : int 3 10 7 2 1 9 3 6 6 14 ...
# $ BB : int 60 60 26 33 33 46 38 49 48 29 ...
# $ SO : int 19 22 25 9 15 23 30 19 13 28 ...
# $ SB : int 73 69 18 16 46 56 53 62 48 53 ...
# $ CS : int 16 21 8 4 15 12 10 24 13 18 ...
# $ HBP : int NA NA NA NA NA NA NA NA NA NA ...
# $ SF : int NA NA NA NA NA NA NA NA NA NA ...
# $ RA : int 303 241 341 243 313 266 287 362 303 434 ...
# $ ER : int 109 77 116 97 121 137 108 153 137 166 ...
# $ ERA : num 3.55 2.76 4.11 5.17 3.72 4.95 4.3 5.51 4.37 2.9 ...
# $ CG : int 22 25 23 19 32 27 23 28 32 48 ...
# $ SHO : int 1 0 0 1 1 0 1 0 0 1 ...
# $ SV : int 3 1 0 0 0 0 0 0 0 1 ...
# $ IPouts : int 828 753 762 507 879 747 678 750 846 1548 ...
# $ HA : int 367 308 346 261 373 329 315 431 371 573 ...
# $ HRA : int 2 6 13 5 7 3 3 4 4 3 ...
# $ BBA : int 42 28 53 21 42 53 34 75 45 63 ...
# $ SOA : int 23 22 34 17 22 16 16 12 13 77 ...
# $ E : int 243 229 234 163 235 194 220 198 218 432 ...
# $ DP : int 24 16 15 8 14 13 14 22 20 22 ...
# $ FP : num 0.834 0.829 0.818 0.803 0.84 0.845 0.821 0.845 0.85 0.83 ...
# $ name : chr "Boston Red Stockings" "Chicago White Stockings" "Cleveland Forest Citys" "Fort Wayne Kekiongas" ...
# $ park : chr "South End Grounds I" "Union Base-Ball Grounds" "National Association Grounds" "Hamilton Field" ...
# $ attendance : int NA NA NA NA NA NA NA NA NA NA ...
# $ BPF : int 103 104 96 101 90 102 97 101 94 106 ...
# $ PPF : int 98 102 100 107 88 98 99 100 98 102 ...
# $ teamIDBR : chr "BOS" "CHI" "CLE" "KEK" ...
# $ teamIDlahman45: chr "BS1" "CH1" "CL1" "FW1" ...
# $ teamIDretro : chr "BS1" "CH1" "CL1" "FW1" ...
# - attr(*, ".internal.selfref")=<externalptr>
(1) 그룹별로 특정 칼럼의 최대값인 행 가져오기
(get the minumum row for each group)
팀 ID 그룹 별로 (by = teamID) 승리 회수가 최대인 행(which.max(W))을 indexing 해서 가져오기 (.SD[which.max(W)] 해보겠습니다. .SD 는 data.table 그 자체를 참조하는데요, 여기에 .SD[which.max(W)]로 W 가 최대인 index 의 위치의 행 전체를 subset 해오는 것입니다. indexing 해오는 위치가 특정 숫자로 고정된 것이 아니라 which.max() 로 최대값의 위치를 동적으로 (dynamic indexing) 가져오게 할 수 있습니다.
## (1) Get the best year for each team, as measured by 'W'(Win)
Teams[ , .SD[which.max(W)]
, .SDcols = c('teamID', 'yearID', 'lgID', 'franchID', 'divID', 'Rank', 'W')
, by = teamID]
# teamID teamID yearID lgID franchID divID Rank W
# 1: BS1 BS1 1875 NA BNA <NA> 1 71
# 2: CH1 CH1 1871 NA CNA <NA> 2 19
# 3: CL1 CL1 1871 NA CFC <NA> 8 10
# 4: FW1 FW1 1871 NA KEK <NA> 7 7
# 5: NY2 NY2 1872 NA NNA <NA> 3 34
# ---
# 145: ANA ANA 2000 AL ANA W 3 82
# 146: ARI ARI 1999 NL ARI W 1 100
# 147: MIL MIL 1999 NL MIL C 5 74
# 148: TBA TBA 2009 AL TBD E 3 84
# 149: MIA MIA 2017 NL FLA E 2 77
(2) 그룹별로 특정 칼럼의 최소값인 행 가져오기
(get the maximum row for each group)
팀 ID 그룹별로(by = teamID) 승리 회수가 최소인 년도의 행 전체를 가져오려면 .SD[which.min(W)] 로 dynamic indexing 을 해서 그룹별 부분집합을 가져오면 됩니다.
.SDcols 는 원하는 특정 칼럼들만 선별적으로 가져올 때 사용합니다.
## (2) Get the worst year for each team, as measured by 'W'(Win)
Teams[ , .SD[which.min(W)]
, .SDcols = c('teamID', 'yearID', 'lgID', 'franchID', 'divID', 'Rank', 'W')
, by = teamID]
# teamID teamID yearID lgID franchID divID Rank W
# 1: BS1 BS1 1871 NA BNA <NA> 3 20
# 2: CH1 CH1 1871 NA CNA <NA> 2 19
# 3: CL1 CL1 1872 NA CFC <NA> 7 6
# 4: FW1 FW1 1871 NA KEK <NA> 7 7
# 5: NY2 NY2 1871 NA NNA <NA> 5 16
# ---
# 145: ANA ANA 1999 AL ANA W 4 70
# 146: ARI ARI 2004 NL ARI W 5 51
# 147: MIL MIL 2002 NL MIL C 6 56
# 148: TBA TBA 2002 AL TBD E 5 55
# 149: MIA MIA 2019 NL FLA E 5 57
참고로, .SD[which(조건, condition)] 을 해서 특정 조건을 만족하는 행을 동적으로 인덱싱 (dynamic indexing with conditions) 해서 부분집합을 가져올 수 도 있습니다.
아래 예에서는 야구팀 그룹(by = teamID)별로 승리 회수가 100회 이상 (.SD[which(W >= 100)] 인 년도의 행들의 부분집합을 가져온 것입니다.
## Get the year over 100 Wins for each team
Teams[ , .SD[which(W >= 100)]
, .SDcols = c('teamID', 'yearID', 'lgID', 'franchID', 'divID', 'Rank', 'W')
, by = teamID]
# ## or equivalently
# Teams[W >= 100 , .SD
# , .SDcols = c('teamID', 'yearID', 'lgID', 'franchID', 'divID', 'Rank', 'W')
# , by = teamID]
# teamID teamID yearID lgID franchID divID Rank W
# 1: BSN BSN 1892 NL ATL <NA> 1 102
# 2: BSN BSN 1898 NL ATL <NA> 1 102
# 3: CHN CHN 1906 NL CHC <NA> 1 116
# 4: CHN CHN 1907 NL CHC <NA> 1 107
# 5: CHN CHN 1909 NL CHC <NA> 2 104
# ---
# 105: OAK OAK 2001 AL OAK W 2 102
# 106: OAK OAK 2002 AL OAK W 1 103
# 107: KCA KCA 1977 AL KCR W 1 102
# 108: SEA SEA 2001 AL SEA W 1 116
# 109: ARI ARI 1999 NL ARI W 1 100
[ Reference ]
* R data.table vignettes 'Using .SD for Data Analysis'
: cran.r-project.org/web/packages/data.table/vignettes/datatable-sd-usage.html
이번 포스팅이 많은 도움이 되었기를 바랍니다.
행복한 데이터 과학자 되세요! :-)
728x90
반응형