dplyr을 data.table로 번역하기
패키지 데이터테이블(data.table
)
package:dplyr
과 package:data.table
의 비교
package:data.table
는 대용량의 데이터를 분산 처리 시스템의 도움없이 처리할 수 있는 최선의 방법이다. 여러 벤치마킹 결과는 데이터테이블(data.table
)이 빅데이터를 처리하는데 타의 추종을 불허함을 보여주었다. 그러나 전통적인 R의 문법과 상이하고, 다소 난해한 문법 때문에 널리 사용되지 못하는 듯 하다.- 여기서는 읽기 쉬운
package:dplyr
의 여러 함수(slice
,filter
등)을package:data.table
로 번역하여, 데이터테이블의 접근성을 높이려 하였다. - 함수 번역 순서는 일반적인
package:dplyr
의 작업 순서로 다음과 같다.
slice
–select
–filter
–mutate
/transmute
–group_by
–summarise
–arrange(,by_group=T)
목차
데이터
library(dplyr)
library(data.table)
data(mtcars)
df <- mtcars
TB <- as_tibble(mtcars, rownames='rn')
# rownames='rn'으로 하면 행이름을 열 rn으로 보존한다.
DT <- as.data.table(mtcars, keep.rownames=TRUE)
# keep.rownames = TRUE 로 놓으면 행이름이 열 rn으로 보존된다.
# 데이터테이블과 티블은 행이름(rownames)를 지원하지 않는다.
print(head(TB))
## # A tibble: 6 x 12 ## rn mpg cyl disp hp drat wt qsec vs am gear carb ## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 Mazda RX4 21 6 160 110 3.9 2.62 16.5 0 1 4 4 ## 2 Mazda RX4 W~ 21 6 160 110 3.9 2.88 17.0 0 1 4 4 ## 3 Datsun 710 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1 ## 4 Hornet 4 Dr~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1 ## 5 Hornet Spor~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2 ## 6 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
print(head(DT))
## rn mpg cyl disp hp drat wt qsec vs am gear carb ## 1: Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 ## 2: Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 ## 3: Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 ## 4: Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 ## 5: Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 ## 6: Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
slice
- 행을 선택하는
slice(TB, c(row1, row2, ...))
는 데이터테이블에서DT[c(row1, row2, ...),]
또는DT[c(row1, row2, ...)]
으로 번역할 수 있다. rows = c(row1, row2, ...)
일 때,DT[rows,]
는 데이터프레임(data.frame
)과 동일한 형식이다. 반면DT[rows]
는data.frame
에서와 다른 의미를 나타냄을 주의하자. 데이터테이블에서DT[10]
는 10번째 행(row)을 나타낸다. 반면 데이터프레임에서는mtcars[10]
은 10번째 열(column)을 나타낸다.
TB %>% slice(3)
DT[3, ]
DT[3]
## rn mpg cyl disp hp drat wt qsec vs am gear carb ## 1: Datsun 710 22.8 4 108 93 3.85 2.32 18.61 1 1 4 1
TB %>% slice(c(3, 5))
DT[c(3, 5), ]
DT[c(3, 5)]
## rn mpg cyl disp hp drat wt qsec vs am gear carb ## 1: Datsun 710 22.8 4 108 93 3.85 2.32 18.61 1 1 4 1 ## 2: Hornet Sportabout 18.7 8 360 175 3.15 3.44 17.02 0 0 3 2
rows <- c(1, 5, 6)
TB %>% slice(rows)
DT[rows, ]
DT[rows]
## rn mpg cyl disp hp drat wt qsec vs am gear carb ## 1: Mazda RX4 21.0 6 160 110 3.90 2.62 16.46 0 1 4 4 ## 2: Hornet Sportabout 18.7 8 360 175 3.15 3.44 17.02 0 0 3 2 ## 3: Valiant 18.1 6 225 105 2.76 3.46 20.22 1 0 3 1
filter
- 특정한 조건을 만족시키는 행을 선택하는
filter(TB, cond)
는 데이터테이블에서DT[cond,]
로 번역할 수 있다. (이때cond
는 논리형 벡터이다.) data.table
은dplyr
과 마찬가지로 컬럼이름을 바로 쓸 수 있다. 아래 코드에서 데이터프레임, 티블, 그리고 데이터테이블을 비교한다.
# cyl==4(실린더가 4개)이고 gear==5 인 행
mtcars[mtcars$cyl == 4 & mtcars$gear == 5, ]
TB %>% filter(cyl == 4 & gear == 5)
DT[cyl == 4 & gear == 5, ]
DT[cyl == 4 & gear == 5]
## rn mpg cyl disp hp drat wt qsec vs am gear carb ## 1: Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.7 0 1 5 2 ## 2: Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.9 1 1 5 2
- 컬럼이름을 따옴표 없이 쓸 수 있어서 편리하지만, 컬럼이름이 벡터에 저장되어 있을 때에는 문제가 있다. 다음의 예제에는
eval()
함수를 사용한 해결책을 제시한다.
coln <- c("cyl", "gear")
conds <- c("==4", "==5")
cond <- parse(text=paste0(coln, conds, collapse=" & "))
mtcars[with(mtcars, eval(cond)),]
TB %>% filter(eval(cond))
DT[eval(cond),]
DT[eval(cond)]
DT[get(coln[1])==4 & get(coln[2])==5]
## rn mpg cyl disp hp drat wt qsec vs am gear carb ## 1: Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.7 0 1 5 2 ## 2: Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.9 1 1 5 2
select
컬럼을 이름 또는 순번으로 선택하는 select(TB, cols)
또는 select(TB, colA, colB, ...)
는 DT[,.(cols)]
또는 DT[,.(colA, colB)]
로 번역할 수 있다. 여기서는 mtcars
의 행을 두 개만 선택해서 진행한다.
- 데이터
DF2 <- mtcars[2:3,]; # 데이터프레임(data.frame)
TB2 <- as_tibble(TB) %>% slice(2:3) # 티블(tibble)
DT2 <- DT[2:3,] # 데이터테이블(data.table)
열 선택
- 순번으로 열선택
DF2[, c(3, 5)]
TB2 %>% select(c(3, 5))
DT2[, c(3, 5)]
## cyl hp ## 1: 6 110 ## 2: 4 93
- 이름으로 열선택
DF2[, c("cyl", "hp")]
TB2 %>% select(c(cyl, hp))
DT2[, .(cyl, hp)]
## cyl hp ## 1: 6 110 ## 2: 4 93
- 변수로 열 순번 선택
icols = c(3, 5)
DF2[, icols]
TB2 %>% select(icols)
DT2[, ..icols]
## cyl hp ## 1: 6 110 ## 2: 4 93
- 변수로 열 이름 선택
nacols = c("cyl", "hp")
DF2[, nacols]
TB2 %>% select_at(nacols)
DT2[, ..nacols]
## cyl hp ## 1: 6 110 ## 2: 4 93
위에서 결과 클래스는 선택 전 클래스와 동일하다. 하지만 데이터프레임의 경우 하나의 열을 선택하면 벡터가 된다. 데이터테이블에서 열 하나를 선택해서 벡터를 얻는 방법은 다음과 같다.
## 순번으로 선택
DT2[, 3] #데이터테이블
DT2[, 3][[1]] #벡터
## [1] 6 4
## 이름으로 선택
DT2[, .(cyl)] #데이터테이블
DT2[, cyl] # 벡터
## [1] 6 4
## 변수로 순번 선택
irows = c(3)
DT2[, ..irows] #데이터테이블
DT2[, ..irows][[1]] #벡터
## [1] 6 4
## 변수로 열이름 선택
nrows = c("cyl")
DT2[, ..nrows] # 데이터테이블
DT2[, ..nrows][[1]] #벡터
## [1] 6 4
열 제외
주어진 자료에서 컬럼을 선택할 때에는 필요한 컬럼을 나열할 수도 있지만, 필요없는 컬럼을 제외할 수도 있다.
DT2[, -c(3, 4)] # 순번으로 열 제외
icols = c(3, 4) # 순번 변수로 열 제외
DT2[, -..icols]
DT2[, !..icols]
## rn mpg hp drat wt qsec vs am gear carb ## 1: Mazda RX4 Wag 21.0 110 3.90 2.875 17.02 0 1 4 4 ## 2: Datsun 710 22.8 93 3.85 2.320 18.61 1 1 4 1
coln = c("cyl", "disp") # 열이름 변수로 열 제외
DT2[, !..coln]
DT2[, .SD, .SDcols = coln2]
## rn mpg hp drat wt qsec vs am gear carb ## 1: Mazda RX4 Wag 21.0 110 3.90 2.875 17.02 0 1 4 4 ## 2: Datsun 710 22.8 93 3.85 2.320 18.61 1 1 4 1
mutate
dplyr
의mutate
는 기존의 컬럼을 유지하면서 일부를 수정하거나, 새로운 컬럼을 만들기 위해 쓰인다.data.table
에서는 수정 또는 생성 컬럼이 하나인 경우,DT[ , newcola := ]
를 사용한다. 만약 생성/수정 컬럼이 두 개 이상이라면DT[, c('cola','colb'):=list( , )]
또는DT[,
`:=`
(cola= , colb=)]
을 사용한다.data.table
의:=
는 조금 특별하다.:=
는 새로운 데이터 테이블을 생성하지 않고 기존의 데이터 테이블에 덮어씌우거나(수정), 새로운 컬럼을 추가한다.
다음의 예제는 hp*qsec
을 구해서 wt2
라는 컬럼 이름으로 저장한다. 그리고 hp
, qsec
라는 컬럼은 hp*2
, qsec*2
로 수정한다.
# 데이터
DF3 <- DF2[, c("hp", "qsec")]
TB3 <- TB2 %>% select(hp, qsec)
DT3 <- DT2[, .(hp, qsec)]
- 하나의 컬럼 생성/수정
DF3[, "wt2"] = DF3$hp * DF3$qsec
DF3$wt2 = DF3$hp * DF3$qsec
DF3[["wt2"]] = DF3$hp * DF3$qsec
TB3 %>% mutate(wt2 = hp * qsec)
DT3[, `:=`(wt2, hp * qsec)]
print(DT3)
## hp qsec wt2 ## 1: 110 17.02 1872.20 ## 2: 93 18.61 1730.73
- 둘 이상의 컬럼 생성/수정
DF3[, c("hp", "qsec")] = data.frame(DF3$hp * 2, DF3$qsec * 2)
TB3 <- TB3 %>% mutate(hp = hp * 2, qsec = qsec * 2)
DT3[, `:=`(c("hp", "qsec"), list(hp * 2, qsec * 2))]
DT3[, `:=`(hp = hp * 2, qsec = qsec * 2)]
print(DT3)
## hp qsec wt2 ## 1: 220 34.04 1872.20 ## 2: 186 37.22 1730.73
- 컬럼 이름 변수: 하나의 컬럼 생성/수정
coln = "wt2"
DF3[, coln] = DF3$hp * DF3$qsec
DF3[[coln]] = DF3$hp * DF3$qsec
TB3 <- TB2 %>% mutate_at(coln, funs(hp * qsec))
DT3[, `:=`(c(coln), hp * qsec)]
## hp qsec wt2 cyl disp ## 1: 220 34.04 1872.20 7488.80 7488.80 ## 2: 186 37.22 1730.73 6922.92 6922.92
- 컬럼 이름 변수: 여러 컬럼 생성/수정
coln = c("hp", "qsec")
DF3[, coln] = lapply(DF3[, coln], function(x) x * 2)
DF3[, coln] = do.call(data.frame, lapply(DF3[, coln], function(x) x * 2))
TB3 <- TB3 %>% mutate_at(coln, funs(. * 2))
DT3[, `:=`(c(coln), lapply(.SD, function(x) x * 2)), .SDcols = coln]
print(DT3)
## hp qsec wt2 cyl disp ## 1: 220 34.04 1872.20 14977.60 14977.60 ## 2: 186 37.22 1730.73 13845.84 13845.84
transmute
dplyr
의 transmute
는 기존의 컬럼을 제외하고 새롭게 생성된 컬럼만을 보존한다.
data.table
에서 =
는 새로운 컬럼을 생성하고, 위에서 봤던 :=
는 기존의 컬럼을 수정한다. data.table
에서 =
을 사용할 때에는 결과가 기존의 데이터 테이블과 같은 크기일 필요가 없다.
- 하나의 컬럼 생성/수정
DF4 = data.frame(wt2 = DF3$hp * DF3$qsec)
TB4 <- TB3 %>% transmute(wt2 = hp*qsec)
DT4 <- DT3[, .(wt3=hp*qsec)]; print(DT4)
## wt3 ## 1: 7488.80 ## 2: 6922.92
- 둘 이상의 컬럼 생성/수정
DF4 = data.frame(hp2 = DF3$hp * 2, qsec2 = DF3$qsec * 2)
DF4 = with(DF3, data.frame(hp2 = hp * 2, qsec2 = qsec * 2))
TB4 <- TB3 %>% transmute(hp = hp * 2, qsec = qsec * 2)
TB4 <- TB3 %>% transmute_at(c("hp", "qsec"), funs(. * 2))
DT4 <- DT3[, .(hp2 = hp * 2, qsec2 = qsec * 2)]
DT4 <- DT3[, lapply(.SD, function(x) x * 2), .SDcols = c("hp", "qsec")]
print(DT4)
## hp qsec ## 1: 440 68.08 ## 2: 372 74.44
- 변수: 하나의 컬럼 생성/수정
coln = "wt2"
DF4 = data.frame(DF3$hp * DF3$qsec)
colnames(DF4) = coln
TB4 <- TB3 %>% transmute(hp * qsec)
colnames(TB4) = coln
DT4 <- DT3[, .(hp * qsec)]
colnames(DT4) = coln
print(DT4)
## wt2 ## 1: 7488.80 ## 2: 6922.92
- 변수: 여러 컬럼 생성/수정
coln = c("hp", "qsec")
DF4 <- do.call(data.frame, lapply(DF3[, coln], function(x) x * 2))
TB4 <- TB3 %>% transmute_at(coln, funs(. * 2))
DT4 <- DT3[, lapply(.SD, function(x) x * 2), .SDcols = coln]
print(DT4)
## hp qsec ## 1: 440 68.08 ## 2: 372 74.44
arrange
- 데이터
DF5 <- mtcars[c(2:5), 1:4]
TB5 <- as_tibble(mtcars) %>% slice(2:5) %>% select(1:4)
DT5 <- as.data.table(mtcars, keep.rownames = TRUE)[2:5, c(1:4)]
print(DT5)
## rn mpg cyl disp ## 1: Mazda RX4 Wag 21.0 6 160 ## 2: Datsun 710 22.8 4 108 ## 3: Hornet 4 Drive 21.4 6 258 ## 4: Hornet Sportabout 18.7 8 360
dplyr
의 arrange(TB, col1, desc(col2))
는 데이터테이블에서 DT[order(col1, -col2)]
로 번역할 수 있다. 데이터테이블의 order
는 문자형이나 순위형 컬럼에 대해서도 order(-col)
형태로 쓸 수 있다.
DF5[order(DF5$cyl, -DF5$mpg),]
TB5 %>% arrange(cyl, desc(mpg))
DT5[order(cyl, -mpg),]; DT5[order(cyl, -mpg)]
## rn mpg cyl disp ## 1: Datsun 710 22.8 4 108 ## 2: Hornet 4 Drive 21.4 6 258 ## 3: Mazda RX4 Wag 21.0 6 160 ## 4: Hornet Sportabout 18.7 8 360
group_by
dplyr
의group_by(byG)
는DT[ , , byG]
로 번역할 수 있다.- 보통
group_by
는 홀로 쓰이지 않고,group_by() %>% summarise()
또는group_by() %>% do()
또는group_by() %>% arrange()
로 구문으로 많이 쓰인다. group_by(byG) %>% summarsize(fn_sum)
또는group_by(byG) %>% do(fn_do)
는 모두DT[ , fn_sum, byG]
또는DT[ , fn_do, byG]
로 나타낼 있다.- 보통 데이터 테이블은
DT[i, j, byG]
로 나타내는 데, 여기서j
는 앞에서 봤던 컬럼을 선택하는 것 이상을 수행할 수 있다. 여러 가지 함수를 사용할 수 있는 데 유일한 제한 조건은 그 결과가 리스트여야 한다는 것이다.
DF6 <- mtcars[c(10:2), c("mpg", "cyl", "disp", "hp", "am")]
TB6 <- TB %>% slice(10:2) %>% select(mpg, cyl, disp, hp, am)
DT6 <- DT[10:2, .(mpg, cyl, disp, hp, am)]
print(head(DT6))
## mpg cyl disp hp am ## 1: 19.2 6 167.6 123 0 ## 2: 22.8 4 140.8 95 0 ## 3: 24.4 4 146.7 62 0 ## 4: 14.3 8 360.0 245 0 ## 5: 18.1 6 225.0 105 0 ## 6: 18.7 8 360.0 175 0
cyl
을 기준으로 집단을 분리한 후 각 집단의mpg
평균을 구하는 방법은 다음과 같다. 데이터테이블에서key=
을 쓰면 기준 변수에 대한 정렬이 이루어지지 않으며(변수의 순서는 원 자료의 순서와 같다),keyby=
를 쓰면 정렬이 이루어진다.
aggregate(mpg ~ cyl, data = DF6, FUN = mean)
TB6 %>% group_by(cyl) %>% summarise(mpg = mean(mpg))
DT6[, mean(mpg), cyl] # cyl는 정렬되지 않는다.
DT6[, .(mpg = mean(mpg)), by = cyl] # cyl는 정렬되지 않는다.
DT6[, mean(mpg), keyby = cyl] # cyl는 정렬된다.
## cyl mpg ## 1: 6 19.92500 ## 2: 4 23.33333 ## 3: 8 16.50000
## cyl V1 ## 1: 4 23.33333 ## 2: 6 19.92500 ## 3: 8 16.50000
- 만약 집단을 나누는 기준을 두 변수(
am
,cyl
)로 하고 두 변수(mpg
,hp
)의 평균을 구하고 싶다면 다음과 같다.
aggregate(cbind(mpg, hp) ~ am + cyl, data = DF6, FUN = mean)
TB6 %>% group_by(cyl, am) %>% summarise(mpg = mean(mpg), hp = mean(hp))
DT6[, .(mpg = mean(mpg), hp = mean(hp)), by = .(cyl, am)]
DT6[, .(mpg = mean(mpg), hp = mean(hp)), keyby = .(cyl, am)]
## am cyl mpg hp ## 1 0 4 23.60000 78.5000 ## 2 1 4 22.80000 93.0000 ## 3 0 6 19.56667 112.6667 ## 4 1 6 21.00000 110.0000 ## 5 0 8 16.50000 210.0000
## # A tibble: 5 x 4 ## # Groups: cyl [?] ## cyl am mpg hp ## <dbl> <dbl> <dbl> <dbl> ## 1 4 0 23.6 78.5 ## 2 4 1 22.8 93 ## 3 6 0 19.6 113. ## 4 6 1 21 110 ## 5 8 0 16.5 210
## cyl am mpg hp ## 1: 6 0 19.56667 112.6667 ## 2: 4 0 23.60000 78.5000 ## 3: 8 0 16.50000 210.0000 ## 4: 4 1 22.80000 93.0000 ## 5: 6 1 21.00000 110.0000
## cyl am mpg hp ## 1: 4 0 23.60000 78.5000 ## 2: 4 1 22.80000 93.0000 ## 3: 6 0 19.56667 112.6667 ## 4: 6 1 21.00000 110.0000 ## 5: 8 0 16.50000 210.0000
- 만약 기준으로 사용되지 않은 모든 열에 대해 평균을 구한다면 다음과 같다.
aggregate
에서.
은 나머지 열을 의미한다.
aggregate(. ~ am + cyl, data = DF6, FUN = mean)
TB6 %>% group_by(cyl, am) %>% summarise_all(mean)
DT6[, lapply(.SD, mean), by = .(cyl, am)] # cyl, am에 대해 정렬되지 않음
DT6[, lapply(.SD, mean), keyby = .(cyl, am)] # cyl, am에 대해 정렬
## cyl am mpg disp hp ## 1: 6 0 19.56667 216.8667 112.6667 ## 2: 4 0 23.60000 143.7500 78.5000 ## 3: 8 0 16.50000 360.0000 210.0000 ## 4: 4 1 22.80000 108.0000 93.0000 ## 5: 6 1 21.00000 160.0000 110.0000
## cyl am mpg disp hp ## 1: 4 0 23.60000 143.7500 78.5000 ## 2: 4 1 22.80000 108.0000 93.0000 ## 3: 6 0 19.56667 216.8667 112.6667 ## 4: 6 1 21.00000 160.0000 110.0000 ## 5: 8 0 16.50000 360.0000 210.0000
group_by() %>% summarise() %>% arrange()
의 경우는 다음과 같이[]
의 연쇄를 활용하면 된다.
DF6 <- aggregate(cbind(mpg, hp) ~ am + cyl, data=DF6, FUN=mean);
DF6[order(DF6$mpg),]
TB6 %>% group_by(cyl, am) %>% summarise(mpg=mean(mpg), hp=mean(hp)) %>%
arrange(mpg)
DT6[, .(mpg = mean(mpg), hp = mean(hp)), by=.(cyl, am)][order(mpg)]
DT6[, .(mpg = mean(mpg), hp = mean(hp)), keyby=.(cyl, am)][order(mpg)]
## cyl am mpg hp ## 1: 8 0 16.50000 210.0000 ## 2: 6 0 19.56667 112.6667 ## 3: 6 1 21.00000 110.0000 ## 4: 4 1 22.80000 93.0000 ## 5: 4 0 23.60000 78.5000
## cyl am mpg hp ## 1: 8 0 16.50000 210.0000 ## 2: 6 0 19.56667 112.6667 ## 3: 6 1 21.00000 110.0000 ## 4: 4 1 22.80000 93.0000 ## 5: 4 0 23.60000 78.5000
종합
data.table
의 문법은DT[i, j, by/keyby=, .SDcols= ][]
로 나타낼 수 있다.i
는 행을 선택하거나 순서를 조정한다.j
는 열을 선택하거나, 열 또는 데이터 테이블 전체(.SD
)에 어떤 함수를 적용한다.by
(또는keyby
)는 집단을 나눈다..SDcols=
는j
를 수행하기 이전에 열을 선택한다.- 마지막의
[]
는 생략하거나, 열을 정렬하거나([order()]
),:=
이후에 데이터 테이블을 출력할 때([]
) 사용할 수 있다.
dplyr
과의 비교
dplyr |
data.table |
---|---|
slice(1:10) |
DT[1:10] |
filter(cola == 3) |
DT[cola==3] |
select(cola, colb) |
DT[.(cola, colb)] |
mutate(colc = cola*colb) |
DT[, colc := cola*colb] |
transmute(colc = cola*colb) |
DT[, .(colc=cola*colb)] |
arrange(cola) |
DT[order(cola)] |
group_by(cola) |
DT[,,by=cola] |
example(data.table)
data.table
의 홈페이지에서도 확인할 수 있듯이, example(data.table)
을 통해 data.table
의 주요 기능을 확인할 수 있다. example(data.table)
의 결과를 보고 얼마나 이해할 수 있는지 확인해 보자.
example(data.table)
example(data.table)
의 결과에서 생소한 부분은 on=
, nomatch=
, roll=
, .EACHI
, mult=
, copy()
, setkey()
, haskey()
, .I
, .GRP
, .BY
등이 있다.
이들이 필요한 기능에 따라 구분해 보면 다음과 같다.
- 데이터테이블에 키 설정 및 활용 :
setkey()
,haskey()
,J()
- 두 데이터테이블의 병합(조인) :
on=
,nomatch=
,roll=
,mult=
- 특별한 기능을 하는 변수 :
.I
,.GRP
,.BY
,.EACHI
다음에는 이들에 대해 차례로 알아볼 계획이다.
이 글은 R로 하는 빅데이터 분석: 데이터 전처리와 시각화-개념적 기초에서 심층활용까지의 내용을 조금 각색한 것입니다.
Leave a comment