5.4 R 반복 함수
5.4.1 apply()
apply(X, MARGIN, FUN, …)
는 X를 입력받아 행 또는 열 방향으로 함수를 적용하여 결과값을 반환합니다. MARGIN 인수가 1이면 행 방향으로, 2이면 열 방향으로 연산이 됩니다.
apply 함수에 입력하는 데이터(X)는 배열, 매트릭스만 가능하고, 만일 데이터프레임이 모두 같은 데이터 타입이면 가능합니다. 반환되는 값은 벡터나 행렬입니다.
(x <- matrix(1:12, c(3,4)))
#> [,1] [,2] [,3] [,4]
#> [1,] 1 4 7 10
#> [2,] 2 5 8 11
#> [3,] 3 6 9 12
apply(x, 1, mean) # 행 방향으로 평균
#> [1] 5.5 6.5 7.5
apply(x, 2, mean, na.rm = TRUE) # 열 방향으로 평균, mean함수 옵션 추가
#> [1] 2 5 8 11
벡터는 apply에 입력데이터로 사용할 수 없습니다(에러 발생). 만일 벡터를 사용하고자 한다면 배열로 변환하여 사용하여야 합니다.
x <- 1:12
dim(x) <- c(1, length(x)); x # 벡터를 배열로 변환
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
#> [1,] 1 2 3 4 5 6 7 8 9 10 11 12
apply(x, 1, mean)
#> [1] 6.5
함수는 사용자 정의 함수를 만들어서 사용할 수 있습니다.
(x <- matrix(1:12, c(3,4)))
#> [,1] [,2] [,3] [,4]
#> [1,] 1 4 7 10
#> [2,] 2 5 8 11
#> [3,] 3 6 9 12
apply(x, 2, function(x) {x*2})
#> [,1] [,2] [,3] [,4]
#> [1,] 2 8 14 20
#> [2,] 4 10 16 22
#> [3,] 6 12 18 24
# 행방향으로 하면 행과 열이 바뀝니다.
apply(x, 1, function(x) {x})
#> [,1] [,2] [,3]
#> [1,] 1 2 3
#> [2,] 4 5 6
#> [3,] 7 8 9
#> [4,] 10 11 12
apply(x, 1, function(x) {x*2})
#> [,1] [,2] [,3]
#> [1,] 2 4 6
#> [2,] 8 10 12
#> [3,] 14 16 18
#> [4,] 20 22 24
데이터프레임도 데이터가 모두 같은 타입이라면 apply를 적용할 수 있습니다. R의 기본 데이터셋인 iris에서 Factor 타입인 Species를 제거한 후 apply에 사용하도록 하겠습니다.
str(iris)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
x <- iris[, -5]; str(x)
#> 'data.frame': 150 obs. of 4 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
apply(x, 2, mean, na.rm = TRUE)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 5.84 3.06 3.76 1.20
apply(x, 2, function(x) {median(x*2-1, na.rm = TRUE)})
#> Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 10.6 5.0 7.7 1.6
5.4.2 lapply()
lapply(X, FUN, …)
는 X를 입력받아 함수를 적용하여 결과값을 반환합니다.
lapply 함수에 입력하는 데이터(X)는 벡터, 리스트 등도 가능하고, 반환되는 값은 리스트입니다.
apply는 X의 행이나 열 방향의 데이터가 한꺼번에 함수로 전달되는 반면에, lapply는 X의 데이터 요소가 하나 하나 함수로 전달됩니다. 행렬이나 배열의 요소는 기본적으로 벡터의 요소와 같은 방식이기 때문에 값이 하나 하나 전달됩니다.
# 아래와 같이 코드를 실행하면 x의 평균이 반환되지 않습니다.
# x값이 하나 하나 mean 함수에 전달되어 각각 계산되기 때문입니다.
x <- matrix(1:6, c(2,3))
lapply(x, mean, na.rm = TRUE)
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 2
#>
#> [[3]]
#> [1] 3
#>
#> [[4]]
#> [1] 4
#>
#> [[5]]
#> [1] 5
#>
#> [[6]]
#> [1] 6
lapply는 리스트로 반환이 됩니다. 이를 벡터로 변환하고자 한다면 unlist 함수를 적용합니다.
x <- 1:3
lapply(x, function(x) {x*2+1}) # 리스트 형태로 반환
#> [[1]]
#> [1] 3
#>
#> [[2]]
#> [1] 5
#>
#> [[3]]
#> [1] 7
unlist(lapply(x, function(x) {x*2+1})) # 리스트를 벡터로 변환하여 반환
#> [1] 3 5 7
데이터프레임도 lapply 함수에 입력데이터로 사용 가능합니다. 데이터프레임의 각 요소 즉 각 변수별로 한꺼번에 함수에 전달됩니다.
str(iris)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
lapply(iris, mean, na.rm = TRUE)
#> Warning in mean.default(X[[i]], ...): argument is not numeric or logical:
#> returning NA
#> $Sepal.Length
#> [1] 5.84
#>
#> $Sepal.Width
#> [1] 3.06
#>
#> $Petal.Length
#> [1] 3.76
#>
#> $Petal.Width
#> [1] 1.2
#>
#> $Species
#> [1] NA
리스트가 입력되면 리스트의 각 요소가 한꺼번에 함수에 전달됩니다. 예를 들어 mean함수를 사용하면 리스트 각 요소별 평균값을 반환합니다.
x <- list(a = 1:10,
beta = exp(-3:3),
logic = c(TRUE,FALSE,FALSE,TRUE))
x
#> $a
#> [1] 1 2 3 4 5 6 7 8 9 10
#>
#> $beta
#> [1] 0.0498 0.1353 0.3679 1.0000 2.7183 7.3891 20.0855
#>
#> $logic
#> [1] TRUE FALSE FALSE TRUE
lapply(x, mean)
#> $a
#> [1] 5.5
#>
#> $beta
#> [1] 4.54
#>
#> $logic
#> [1] 0.5
lapply(x, quantile, probs = (1:3)/4)
#> $a
#> 25% 50% 75%
#> 3.25 5.50 7.75
#>
#> $beta
#> 25% 50% 75%
#> 0.252 1.000 5.054
#>
#> $logic
#> 25% 50% 75%
#> 0.0 0.5 1.0
5.4.3 sapply()
sapply(X, FUN, …, simplify = TRUE, USE.NAMES = TRUE)
는 단순화된(simplify) lapply 함수라 할 수 있습니다. lapply는 리스트 형태로 반환되기 때문에 사용하기 불편한 점이 있는데 sapply는 기본적으로 벡터나 행렬 형태로 반환합니다. 만일 옵션 simplify = FALSE이면 lapply와 동일하게 리스트 형태로 반환됩니다.
str(iris)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
sapply(iris, mean, na.rm = TRUE)
#> Warning in mean.default(X[[i]], ...): argument is not numeric or logical:
#> returning NA
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 5.84 3.06 3.76 1.20 NA
x <- list(a = 1:10,
beta = exp(-3:3),
logic = c(TRUE,FALSE,FALSE,TRUE))
x
#> $a
#> [1] 1 2 3 4 5 6 7 8 9 10
#>
#> $beta
#> [1] 0.0498 0.1353 0.3679 1.0000 2.7183 7.3891 20.0855
#>
#> $logic
#> [1] TRUE FALSE FALSE TRUE
sapply(x, mean)
#> a beta logic
#> 5.50 4.54 0.50
sapply(x, quantile, probs = (1:3)/4)
#> a beta logic
#> 25% 3.25 0.252 0.0
#> 50% 5.50 1.000 0.5
#> 75% 7.75 5.054 1.0
5.4.4 vapply()
vapply(X, FUN, FUN.VALUE, …, USE.NAMES = TRUE)
는 sapply와 유사합니다. 차이점은 반환되는 결과의 양식을 지정할 수 있습니다.
str(iris)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
# sapply로 fivenum 출력
sapply(iris[, 1:4], fivenum, na.rm = TRUE)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width
#> [1,] 4.3 2.0 1.00 0.1
#> [2,] 5.1 2.8 1.60 0.3
#> [3,] 5.8 3.0 4.35 1.3
#> [4,] 6.4 3.3 5.10 1.8
#> [5,] 7.9 4.4 6.90 2.5
# vapply로 fivenum 출력, 출력양식 지정
vapply(iris[, 1:4], fivenum,
c("최소값" = 0, "1사분위수" = 0, "중위수" = 0,
"3사분위수" = 0, "최대값" = 0),
na.rm = TRUE)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 최소값 4.3 2.0 1.00 0.1
#> 1사분위수 5.1 2.8 1.60 0.3
#> 중위수 5.8 3.0 4.35 1.3
#> 3사분위수 6.4 3.3 5.10 1.8
#> 최대값 7.9 4.4 6.90 2.5
5.4.5 tapply()
tapply(X, INDEX, FUN = NULL, ..., default = NA, simplify = TRUE)
는 요인(factor) 변수를 기준으로 그룹별로 나누어서 함수를 적용합니다. X는 벡터입니다. INDEX는 요인 또는 요인 리스트가 들어가는 인수입니다. 만일 X에 데이터프레임을 넣고 싶으면 by()
함수를 쓰면 됩니다.
# iris 데이터의 요인변수 Species 별로 평균 구하기
str(iris)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
tapply(iris$Sepal.Length, iris$Species, mean, na.rm = TRUE)
#> setosa versicolor virginica
#> 5.01 5.94 6.59
# 팩터변수가 2개가 되면 교차표가 만들어짐
# x[, -1]은 wool과 tension으로 구성된 데이터프레임
str(x <- warpbreaks)
#> 'data.frame': 54 obs. of 3 variables:
#> $ breaks : num 26 30 54 25 70 52 51 26 67 18 ...
#> $ wool : Factor w/ 2 levels "A","B": 1 1 1 1 1 1 1 1 1 1 ...
#> $ tension: Factor w/ 3 levels "L","M","H": 1 1 1 1 1 1 1 1 1 2 ...
tapply(x$breaks, x[, -1], sum)
#> tension
#> wool L M H
#> A 401 216 221
#> B 254 259 169
# 데이터 무작위 30개 만들어 x에 할당
set.seed(234)
x <- c(rnorm(10), runif(10), rnorm(10, 1))
str(x)
#> num [1:30] 0.661 -2.053 -1.499 1.471 1.459 ...
# 팩터 변수 생성(값 30개)
# gl(n, k)는 1부터 n까지 정수로된 팩터 레벨을 k만큼 반복해서 만듬
fac <- gl(3, 10) # factor(rep(1:3, each = 10), levels = 1:3)와 동일
fac
#> [1] 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3
#> Levels: 1 2 3
tapply(x, fac, mean)
#> 1 2 3
#> -0.422 0.606 1.116
tapply(x, fac, range)
#> $`1`
#> [1] -3.04 1.47
#>
#> $`2`
#> [1] 0.192 0.883
#>
#> $`3`
#> [1] 0.0699 2.0163
5.4.6 mapply()
mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE)
는
sapply의 다변량 버전이라 할 수 있습니다. 여러 개의 인자를 입력할 수 있고,
반환하는 값은 리스트, 벡터, 배열 등이 가능합니다.
MoreArgs는 함수에 들어갈 또다른 인수 리스트입니다.
# rep(1, 4), rep(2, 3), ..., rep(x = 4, times = 1) => 리스트 반환
mapply(rep, 1:4, 4:1)
#> [[1]]
#> [1] 1 1 1 1
#>
#> [[2]]
#> [1] 2 2 2
#>
#> [[3]]
#> [1] 3 3
#>
#> [[4]]
#> [1] 4
# rep(1, 3), rep(2, 3), ..., rep(x = 4, times = 3) => 행렬 반환
mapply(rep, 1:4, 3)
#> [,1] [,2] [,3] [,4]
#> [1,] 1 2 3 4
#> [2,] 1 2 3 4
#> [3,] 1 2 3 4
# rep(times = 1, x = 4), rep(times = 2, x = 3), ...
mapply(rep, times = 1:4, x = 4:1)
#> [[1]]
#> [1] 4
#>
#> [[2]]
#> [1] 3 3
#>
#> [[3]]
#> [1] 2 2 2
#>
#> [[4]]
#> [1] 1 1 1 1
# rep(x = 23, times = 1), rep(x = 23, times = 2), ...
mapply(rep, 1:4, MoreArgs = list(x = 23))
#> [[1]]
#> [1] 23
#>
#> [[2]]
#> [1] 23 23
#>
#> [[3]]
#> [1] 23 23 23
#>
#> [[4]]
#> [1] 23 23 23 23
# sprintf(" %d%s ", 1, "a"), ....
mapply(function(i, s) {
sprintf(" %d%s ", i, s)
},
i = 1:3, s = c("a", "b", "c"))
#> [1] " 1a " " 2b " " 3c "
MoreArgs 인수는 여러 개의 데이터를 한꺼번에 함수에 넣어줍니다. 이 것을 사용하지 않으면 데이터가 하나씩 함수에 들어갑니다.
sumsq <- function(x, mean = 0, sd = 1) {
sum(((x - mean) / sd)^2)
}
set.seed(123)
x <- rnorm(10000)
# sumsq(x, mean = 1, sd = 1), sumsq(x, mean = 2, sd = 2), ...
mapply(sumsq, mean = 1:100, sd = 1:100, MoreArgs = list(x = x))
#> [1] 20019 12517 11124 10635 10408 10285 10210 10162 10128 10104 10087 10073
#> [13] 10063 10054 10047 10042 10037 10033 10030 10027 10025 10023 10021 10019
#> [25] 10018 10017 10015 10014 10013 10013 10012 10011 10011 10010 10009 10009
#> [37] 10009 10008 10008 10007 10007 10007 10006 10006 10006 10006 10006 10005
#> [49] 10005 10005 10005 10005 10004 10004 10004 10004 10004 10004 10004 10004
#> [61] 10003 10003 10003 10003 10003 10003 10003 10003 10003 10003 10003 10003
#> [73] 10003 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002
#> [85] 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002
#> [97] 10002 10002 10001 10001
# 만일 이렇게 mapply(sumsq, mean = 1:100, sd = 1:100, x = x) 하면
# sumsq(x = x[1], mean = 1, sd = 1), ... 이런식으로 계산되어
# 원하는 결과가 나오지 않음. 여기서 x[1]은 -0.560475647임
5.4.7 eapply()
eapply(env, FUN, ..., all.names = FALSE, USE.NAMES = TRUE)
는 환경(Environment)에 있는 변수나 함수들을 반복 계산해 줍니다.
# 새로운 환경 만들기; R에서 전역환경은 .GlobalEnv 임
env <- new.env()
env$a <- 10
env$b <- 20:23
env$c <- 30:35
# 전역변수 자료형 확인하기
eapply(env, typeof)
#> $a
#> [1] "double"
#>
#> $b
#> [1] "integer"
#>
#> $c
#> [1] "integer"
# env 환경변수의 각 요소에 2를 곱하기
eapply(env, function(x) {x * 2})
#> $a
#> [1] 20
#>
#> $b
#> [1] 40 42 44 46
#>
#> $c
#> [1] 60 62 64 66 68 70
5.4.8 by()
by(data, INDICES, FUN, …, simplify = TRUE)
는 데이터프레임을 위한 tapply라 할 수 있다. 요인(factor) 변수를 기준으로 그룹별로 나누어서 함수를 적용합니다. data는 데이터프레임이나 행렬입니다. INDEX는 요인 또는 요인 리스트가 들어가는 인수입니다.
str(iris)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
by(iris, iris$Species, summary)
#> iris$Species: setosa
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> Min. :4.30 Min. :2.30 Min. :1.00 Min. :0.100 setosa :50
#> 1st Qu.:4.80 1st Qu.:3.20 1st Qu.:1.40 1st Qu.:0.200 versicolor: 0
#> Median :5.00 Median :3.40 Median :1.50 Median :0.200 virginica : 0
#> Mean :5.01 Mean :3.43 Mean :1.46 Mean :0.246
#> 3rd Qu.:5.20 3rd Qu.:3.67 3rd Qu.:1.57 3rd Qu.:0.300
#> Max. :5.80 Max. :4.40 Max. :1.90 Max. :0.600
#> ------------------------------------------------------------
#> iris$Species: versicolor
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> Min. :4.90 Min. :2.00 Min. :3.00 Min. :1.00 setosa : 0
#> 1st Qu.:5.60 1st Qu.:2.52 1st Qu.:4.00 1st Qu.:1.20 versicolor:50
#> Median :5.90 Median :2.80 Median :4.35 Median :1.30 virginica : 0
#> Mean :5.94 Mean :2.77 Mean :4.26 Mean :1.33
#> 3rd Qu.:6.30 3rd Qu.:3.00 3rd Qu.:4.60 3rd Qu.:1.50
#> Max. :7.00 Max. :3.40 Max. :5.10 Max. :1.80
#> ------------------------------------------------------------
#> iris$Species: virginica
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> Min. :4.90 Min. :2.20 Min. :4.50 Min. :1.40 setosa : 0
#> 1st Qu.:6.22 1st Qu.:2.80 1st Qu.:5.10 1st Qu.:1.80 versicolor: 0
#> Median :6.50 Median :3.00 Median :5.55 Median :2.00 virginica :50
#> Mean :6.59 Mean :2.97 Mean :5.55 Mean :2.03
#> 3rd Qu.:6.90 3rd Qu.:3.17 3rd Qu.:5.88 3rd Qu.:2.30
#> Max. :7.90 Max. :3.80 Max. :6.90 Max. :2.50
# 팩터변수가 2개가 되면 그만큼 그룹으로 더 나뉘어짐
# x[, -1]은 wool과 tension으로 구성된 데이터프레임
str(warpbreaks)
#> 'data.frame': 54 obs. of 3 variables:
#> $ breaks : num 26 30 54 25 70 52 51 26 67 18 ...
#> $ wool : Factor w/ 2 levels "A","B": 1 1 1 1 1 1 1 1 1 1 ...
#> $ tension: Factor w/ 3 levels "L","M","H": 1 1 1 1 1 1 1 1 1 2 ...
by(warpbreaks[, 1], warpbreaks[, -1], summary)
#> wool: A
#> tension: L
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 25.0 26.0 51.0 44.6 54.0 70.0
#> ------------------------------------------------------------
#> wool: B
#> tension: L
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 14.0 20.0 29.0 28.2 31.0 44.0
#> ------------------------------------------------------------
#> wool: A
#> tension: M
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 12 18 21 24 30 36
#> ------------------------------------------------------------
#> wool: B
#> tension: M
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 16.0 21.0 28.0 28.8 39.0 42.0
#> ------------------------------------------------------------
#> wool: A
#> tension: H
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 10.0 18.0 24.0 24.6 28.0 43.0
#> ------------------------------------------------------------
#> wool: B
#> tension: H
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 13.0 15.0 17.0 18.8 21.0 28.0
5.4.9 split()
split(x, f, drop = FALSE, ...)
은 f에 정의된 그룹(보통 팩터 또는 리스트)에 따라 벡터 x를 분리합니다. 반환되는 값은 리스트입니다.unsplit(value, f, drop = FALSE)
은 분리된 벡터 리스트 또는 데이터프레임인 value를 f에 정의된 그룹기준으로 원상태로 되돌립니다. 반환되는 값은 벡터나 데이터프레임입니다.
str(iris)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
# iris 데이터프레임을 Species 기준으로 분리합니다. (결과 리스트 형태)
x <- split(iris, iris$Species)
str(x)
#> List of 3
#> $ setosa :'data.frame': 50 obs. of 5 variables:
#> ..$ Sepal.Length: num [1:50] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> ..$ Sepal.Width : num [1:50] 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> ..$ Petal.Length: num [1:50] 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> ..$ Petal.Width : num [1:50] 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> ..$ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
#> $ versicolor:'data.frame': 50 obs. of 5 variables:
#> ..$ Sepal.Length: num [1:50] 7 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 ...
#> ..$ Sepal.Width : num [1:50] 3.2 3.2 3.1 2.3 2.8 2.8 3.3 2.4 2.9 2.7 ...
#> ..$ Petal.Length: num [1:50] 4.7 4.5 4.9 4 4.6 4.5 4.7 3.3 4.6 3.9 ...
#> ..$ Petal.Width : num [1:50] 1.4 1.5 1.5 1.3 1.5 1.3 1.6 1 1.3 1.4 ...
#> ..$ Species : Factor w/ 3 levels "setosa","versicolor",..: 2 2 2 2 2 2 2 2 2 2 ...
#> $ virginica :'data.frame': 50 obs. of 5 variables:
#> ..$ Sepal.Length: num [1:50] 6.3 5.8 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2 ...
#> ..$ Sepal.Width : num [1:50] 3.3 2.7 3 2.9 3 3 2.5 2.9 2.5 3.6 ...
#> ..$ Petal.Length: num [1:50] 6 5.1 5.9 5.6 5.8 6.6 4.5 6.3 5.8 6.1 ...
#> ..$ Petal.Width : num [1:50] 2.5 1.9 2.1 1.8 2.2 2.1 1.7 1.8 1.8 2.5 ...
#> ..$ Species : Factor w/ 3 levels "setosa","versicolor",..: 3 3 3 3 3 3 3 3 3 3 ...
# 분리된 것을 다시 원상태로 돌립니다. (결과 데이터프레임)
y <- unsplit(x, iris$Species)
str(y)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
두 개 칼럼을 기준으로 분리할 수 있습니다. 2개 이상의 칼럼을 기준으로 할 때에는 리스트 구조로 묶어줍니다.
str(infert) # R 내장 데이터 infert
#> 'data.frame': 248 obs. of 8 variables:
#> $ education : Factor w/ 3 levels "0-5yrs","6-11yrs",..: 1 1 1 1 2 2 2 2 2 2 ...
#> $ age : num 26 42 39 34 35 36 23 32 21 28 ...
#> $ parity : num 6 1 6 4 3 4 1 2 1 2 ...
#> $ induced : num 1 1 2 2 1 2 0 0 0 0 ...
#> $ case : num 1 1 1 1 1 1 1 1 1 1 ...
#> $ spontaneous : num 2 0 0 0 1 1 0 0 1 0 ...
#> $ stratum : int 1 2 3 4 5 6 7 8 9 10 ...
#> $ pooled.stratum: num 3 1 4 2 32 36 6 22 5 19 ...
x <- split(infert, list(infert$spontaneous, infert$education))
str(x, max.level = 1)
#> List of 9
#> $ 0.0-5yrs :'data.frame': 9 obs. of 8 variables:
#> $ 1.0-5yrs :'data.frame': 1 obs. of 8 variables:
#> $ 2.0-5yrs :'data.frame': 2 obs. of 8 variables:
#> $ 0.6-11yrs:'data.frame': 71 obs. of 8 variables:
#> $ 1.6-11yrs:'data.frame': 33 obs. of 8 variables:
#> $ 2.6-11yrs:'data.frame': 16 obs. of 8 variables:
#> $ 0.12+ yrs:'data.frame': 61 obs. of 8 variables:
#> $ 1.12+ yrs:'data.frame': 37 obs. of 8 variables:
#> $ 2.12+ yrs:'data.frame': 18 obs. of 8 variables:
행의 갯수를 지정해서 데이터를 분리할 수 있습니다. 인수 f에 데이터를 나눌 기준이 될 벡터을 만들면 됩니다. 그러면 같은 수를 가진 행끼리 하나의 그룹으로 만들어집니다. 단, 이 기준 벡터의 수와 데이터의 갯수가 같아야 오류가 나지 않습니다.
# infert 데이터의 전체 행을 10개씩 구분하는 기준 벡터를 만듭니다.
df <- iris # 데이터
gnum <- 10 # 그룹의 갯수
f <- c(rep(1:floor((nrow(df)/gnum)), each = gnum),
rep(ceiling(nrow(df)/gnum), each = nrow(df)%%gnum))
x <- split(df, f)
print(x[1:2]); cat("... 이하 생략 ...")
#> $`1`
#> 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
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5.0 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosa
#> 7 4.6 3.4 1.4 0.3 setosa
#> 8 5.0 3.4 1.5 0.2 setosa
#> 9 4.4 2.9 1.4 0.2 setosa
#> 10 4.9 3.1 1.5 0.1 setosa
#>
#> $`2`
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 11 5.4 3.7 1.5 0.2 setosa
#> 12 4.8 3.4 1.6 0.2 setosa
#> 13 4.8 3.0 1.4 0.1 setosa
#> 14 4.3 3.0 1.1 0.1 setosa
#> 15 5.8 4.0 1.2 0.2 setosa
#> 16 5.7 4.4 1.5 0.4 setosa
#> 17 5.4 3.9 1.3 0.4 setosa
#> 18 5.1 3.5 1.4 0.3 setosa
#> 19 5.7 3.8 1.7 0.3 setosa
#> 20 5.1 3.8 1.5 0.3 setosa
#> ... 이하 생략 ...
# 위 예제에서 분리된 것을 같은 기준으로 하나로 묶습니다.
y <- unsplit(x, f)
str(y)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
5.4.10 Vectorize()
Vectorize(FUN, vectorize.args = arg.names, SIMPLIFY = TRUE, USE.NAMES = TRUE)
함수는 인자 FUN에 들어간 함수가 벡터 방식으로 작동하도록 만드는 함수입니다. 함수 중에는 함수의 인자가 단 하나의 값만 들어가야 하는 경우가 있어 인자에 여러 개의 값 즉 벡터형식으로 넣을 수 없는 함수들이 있습니다. Vectorize() 함수는 이 문제를 해결하여 줍니다. 이때 벡터형식으로 들어갈 인자를 vectorize.args에 지정합니다. 반환되는 결과는 벡터로 들어간 인자들이 각각 투입된 만큼의 결과들이 행렬이나 배열로 묶여서 나옵니다.
아래 예제는 iris$Species에서 vi나 se로 시작하는 행을 추출하고자 하는 것입니다.
# grepl함수는 pattern 인수에 단 하나의 값만 넣을 수 있습니다.
# 만일 아래 같이 벡터형식으로 값을 여러 개 넣으면 첫번째 요소만 사용되어
# 원하는 결과를 얻을 수없습니다.
x <- grepl(pattern = c("^vi", "^se"), x = iris$Species)
#> Warning in grepl(pattern = c("^vi", "^se"), x = iris$Species): 인자 'pattern'는
#> 반드시 길이가 1 보다 커야 하고, 오로지 첫번째 요소만이 사용될 것입니다
head(x)
#> [1] FALSE FALSE FALSE FALSE FALSE FALSE
# grepl 함수를 벡터작업이 가능한 함수 vgrepl로 만듭니다.
# 벡터로 들어갈 인수는 pattern으로 지정합니다.
vgrepl <- Vectorize(grepl, vectorize.args = "pattern")
x <- vgrepl(pattern = c("^vi", "^se"), x = iris$Species)
head(x)
#> ^vi ^se
#> [1,] FALSE TRUE
#> [2,] FALSE TRUE
#> [3,] FALSE TRUE
#> [4,] FALSE TRUE
#> [5,] FALSE TRUE
#> [6,] FALSE TRUE
# 조건에 맞는 행들을 추출합니다.
str(iris[rowSums(x) > 0, ])
#> 'data.frame': 100 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
물론 Vectorize() 함수를 사용하지 않고 sapply() 함수를 사용하여 같은 결과를 얻을 수 있습니다.
x <- sapply(c("^vi", "^se"),
function(pattern) {grepl(pattern = pattern, x = iris$Species)})
head(x)
#> ^vi ^se
#> [1,] FALSE TRUE
#> [2,] FALSE TRUE
#> [3,] FALSE TRUE
#> [4,] FALSE TRUE
#> [5,] FALSE TRUE
#> [6,] FALSE TRUE
sumsq <- function(x, mean = 0, sd = 1) {
sum(((x - mean) / sd)^2)}
set.seed(123)
x <- rnorm(10000)
# mapply(sumsq, mean = 1:100, sd = 1:100, MoreArgs = list(x = x))와 같은 결과
vsumsq <- Vectorize(sumsq, c("mean", "sd"))
vsumsq(x, 1:100, 1:100)
#> [1] 20019 12517 11124 10635 10408 10285 10210 10162 10128 10104 10087 10073
#> [13] 10063 10054 10047 10042 10037 10033 10030 10027 10025 10023 10021 10019
#> [25] 10018 10017 10015 10014 10013 10013 10012 10011 10011 10010 10009 10009
#> [37] 10009 10008 10008 10007 10007 10007 10006 10006 10006 10006 10006 10005
#> [49] 10005 10005 10005 10005 10004 10004 10004 10004 10004 10004 10004 10004
#> [61] 10003 10003 10003 10003 10003 10003 10003 10003 10003 10003 10003 10003
#> [73] 10003 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002
#> [85] 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002
#> [97] 10002 10002 10001 10001
sumsq <- function(x, mean = 0, sd = 1) {
sum(((x - mean) / sd)^2)
}
set.seed(123)
x <- rnorm(10000)
# sumsq(x, mean = 1, sd = 1), sumsq(x, mean = 2, sd = 2), ...
mapply(sumsq, mean = 1:100, sd = 1:100, MoreArgs = list(x = x))
#> [1] 20019 12517 11124 10635 10408 10285 10210 10162 10128 10104 10087 10073
#> [13] 10063 10054 10047 10042 10037 10033 10030 10027 10025 10023 10021 10019
#> [25] 10018 10017 10015 10014 10013 10013 10012 10011 10011 10010 10009 10009
#> [37] 10009 10008 10008 10007 10007 10007 10006 10006 10006 10006 10006 10005
#> [49] 10005 10005 10005 10005 10004 10004 10004 10004 10004 10004 10004 10004
#> [61] 10003 10003 10003 10003 10003 10003 10003 10003 10003 10003 10003 10003
#> [73] 10003 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002
#> [85] 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002 10002
#> [97] 10002 10002 10001 10001
# 만일 이렇게 mapply(sumsq, mean = 1:100, sd = 1:100, x = x) 하면
# sumsq(x = x[1], mean = 1, sd = 1), ... 이런식으로 계산되어
# 원하는 결과가 나오지 않음. 여기서 x[1]은 -0.560475647임
5.4.11 replicate()
replicate(n, expr, simplify = "array")
함수는 sapply()
함수의 간소화 버전이라 할 수 있습니다. expr 인자를 n번 만큼 반복수행합니다. expr 인자에는 주로 함수들이 많이 들어갑니다. 반환되는 결과는 기본적으로 배열입니다. 만일 반환되는 값을 리스트 형태로 받고자 한다면 simplify = FALSE
로 지정합니다.
아래 예제는 rnorm(5, mean = 0, sd = 1)
을 3번 반복하여 그 결과를 행렬형태로 얻는 것입니다.
5.4.12 rep()
rep(x, ...)
함수는 특정값을 반복해서 만들어 반환해주는 함수입니다. ...
에는 인자로 times, length.out, each가 들어갈 수 있습니다. times는 x를 몇 번 반복할지를 정해주는 인수입니다. length.out은 최종 반환되는 값들의 길이를 정해주는 인수입니다. each는 x가 여러개의 값으로 구성된 벡터일 경우 각각 몇 번 반복할지를 정해주는 인수 입니다.
rep.int(x, times)
와 rep_len(x, length.out)
는 rep()
함수와 기능이 거의 같으나 인수가 제한됩니다. 이 함수들은 rep()
함수보다 더 빠릅니다.
rep(1:5, 2) # rep(x = 1:4, times = 2)와 동일
#> [1] 1 2 3 4 5 1 2 3 4 5
rep(1:5, each = 2)
#> [1] 1 1 2 2 3 3 4 4 5 5
rep(1:5, c(2, 3, 2, 1, 2)) # rep(1:5, times = c(2, 3, 2, 1, 2)) 동일
#> [1] 1 1 2 2 2 3 3 4 5 5
rep(1:5, each = 2, len = 5)
#> [1] 1 1 2 2 3
rep(1:2, each = 2, len = 7) # 길이를 채우기 위해 다시 반복
#> [1] 1 1 2 2 1 1 2
rep(1:3, each = 2, times =3)
#> [1] 1 1 2 2 3 3 1 1 2 2 3 3 1 1 2 2 3 3
rep(2, 5.9) # 소수점 이하는 버리고 반복
#> [1] 2 2 2 2 2
rep(c("abc", "123"), times = 3)
#> [1] "abc" "123" "abc" "123" "abc" "123"
rep(c("abc", "123"), each = 3)
#> [1] "abc" "abc" "abc" "123" "123" "123"
rep.int(c("abc", "123"), 3) # 기본인자는 times임. each 인자는 사용할 수 없음
#> [1] "abc" "123" "abc" "123" "abc" "123"
rep_len(c("abc", "123"), 5) # 기본인자는 length.out임
#> [1] "abc" "123" "abc" "123" "abc"
5.4.13 seq()
seq(...)
함수는 일련번호 숫자를 생성하여 반환합니다. ...
에는 인자로 from, to, by, length.out, along.with가 들어갈 수 있습니다.
- from : 시작 숫자
- to : 끝 숫자
- by : 증가 간격
- length.out : 생성되는 일련번호의 길이
- along.with : 인자에 들어가는 값들의 길이만큼 일련번호 생성
seq.int()
는 seq() 함수와 거의 동일하고, seq_along(along.with)
와 seq_len(length.out)
는 무조건 시작이 1이고, 각각 하나의 인자를 받아 일련번호를 생성합니다. 이 함수들은 1부터 시작하는 일련번호를 seq()
함수보다 약간 더 빠르게 만들어 줍니다.
가장 많이 사용하는 형태는 다음과 같습니다.
- seq(from, to)
- seq(from, to, by = )
- seq(from, to, length.out = )
- seq(along.with = )
- seq(from)
- seq(length.out = )
seq(2, 7) # seq(from = 2, to = 7과 동일)
#> [1] 2 3 4 5 6 7
seq(7, 2)
#> [1] 7 6 5 4 3 2
seq(2, 10, by = 2)
#> [1] 2 4 6 8 10
seq(2, 10, by = pi)
#> [1] 2.00 5.14 8.28
seq(2, 10, length.out = 3)
#> [1] 2 6 10
seq(along.with = c(2:7)) # c(2:7)의 길이는 6이므로 6개 생성
#> [1] 1 2 3 4 5 6
seq(2, 10, along.with = c(2:7))
#> [1] 2.0 3.6 5.2 6.8 8.4 10.0
seq(7) # 1부터 7까지 생성
#> [1] 1 2 3 4 5 6 7
seq(length.out = 12)
#> [1] 1 2 3 4 5 6 7 8 9 10 11 12
seq.int(2, 10, by = pi)
#> [1] 2.00 5.14 8.28
seq_len(12) # seq(length.out = 12)와 동일하나 약간 더 빠름
#> [1] 1 2 3 4 5 6 7 8 9 10 11 12
seq_along(c(2:7))
#> [1] 1 2 3 4 5 6
n <- 999999999999999
start <- proc.time()
x <- seq(length.out = n)
end <- proc.time()
end - start
#> user system elapsed
#> 0 0 0
start <- proc.time()
x <- seq_len(n)
end <- proc.time()
end - start
#> user system elapsed
#> 0 0 0
일련 날짜를 생성할 수 있습니다.
# 1년 간격
seq(as.Date("2001/1/1"), as.Date("2020/1/1"), "years")
#> [1] "2001-01-01" "2002-01-01" "2003-01-01" "2004-01-01" "2005-01-01"
#> [6] "2006-01-01" "2007-01-01" "2008-01-01" "2009-01-01" "2010-01-01"
#> [11] "2011-01-01" "2012-01-01" "2013-01-01" "2014-01-01" "2015-01-01"
#> [16] "2016-01-01" "2017-01-01" "2018-01-01" "2019-01-01" "2020-01-01"
# 월 간격
seq(as.Date("2001/1/1"), by = "month", length.out = 12)
#> [1] "2001-01-01" "2001-02-01" "2001-03-01" "2001-04-01" "2001-05-01"
#> [6] "2001-06-01" "2001-07-01" "2001-08-01" "2001-09-01" "2001-10-01"
#> [11] "2001-11-01" "2001-12-01"
# 분기 간격
seq(as.Date("2015/1/1"), as.Date("2020/1/1"), by = "quarter")
#> [1] "2015-01-01" "2015-04-01" "2015-07-01" "2015-10-01" "2016-01-01"
#> [6] "2016-04-01" "2016-07-01" "2016-10-01" "2017-01-01" "2017-04-01"
#> [11] "2017-07-01" "2017-10-01" "2018-01-01" "2018-04-01" "2018-07-01"
#> [16] "2018-10-01" "2019-01-01" "2019-04-01" "2019-07-01" "2019-10-01"
#> [21] "2020-01-01"
# 월 간격 반대로
seq(as.Date("2020-1-7"), as.Date("2019-1-17"), by = "-1 month")
#> [1] "2020-01-07" "2019-12-07" "2019-11-07" "2019-10-07" "2019-09-07"
#> [6] "2019-08-07" "2019-07-07" "2019-06-07" "2019-05-07" "2019-04-07"
#> [11] "2019-03-07" "2019-02-07"
seq(ISOdate(2015,1,1), ISOdate(2020,1,1), "years")
#> [1] "2015-01-01 12:00:00 GMT" "2016-01-01 12:00:00 GMT"
#> [3] "2017-01-01 12:00:00 GMT" "2018-01-01 12:00:00 GMT"
#> [5] "2019-01-01 12:00:00 GMT" "2020-01-01 12:00:00 GMT"
seq(c(ISOdate(2020,3,20)), by = "DSTday", length.out = 10)
#> [1] "2020-03-20 21:00:00 KST" "2020-03-21 21:00:00 KST"
#> [3] "2020-03-22 21:00:00 KST" "2020-03-23 21:00:00 KST"
#> [5] "2020-03-24 21:00:00 KST" "2020-03-25 21:00:00 KST"
#> [7] "2020-03-26 21:00:00 KST" "2020-03-27 21:00:00 KST"
#> [9] "2020-03-28 21:00:00 KST" "2020-03-29 21:00:00 KST"
seq(c(ISOdate(2020,3,20)), by = "7 DSTdays", length.out = 5)
#> [1] "2020-03-20 21:00:00 KST" "2020-03-27 21:00:00 KST"
#> [3] "2020-04-03 21:00:00 KST" "2020-04-10 21:00:00 KST"
#> [5] "2020-04-17 21:00:00 KST"
seq(as.POSIXct("2015-3-14 17:22:15"), as.POSIXct("2015-3-15 9:12:25"),
by = "hours")
#> [1] "2015-03-14 17:22:15 KST" "2015-03-14 18:22:15 KST"
#> [3] "2015-03-14 19:22:15 KST" "2015-03-14 20:22:15 KST"
#> [5] "2015-03-14 21:22:15 KST" "2015-03-14 22:22:15 KST"
#> [7] "2015-03-14 23:22:15 KST" "2015-03-15 00:22:15 KST"
#> [9] "2015-03-15 01:22:15 KST" "2015-03-15 02:22:15 KST"
#> [11] "2015-03-15 03:22:15 KST" "2015-03-15 04:22:15 KST"
#> [13] "2015-03-15 05:22:15 KST" "2015-03-15 06:22:15 KST"
#> [15] "2015-03-15 07:22:15 KST" "2015-03-15 08:22:15 KST"
5.4.14 sequence()
sequence(nvec, ...)
함수는 연속적인 숫자를 만들어 내는 함수입니다.
인자 nvec에 들어간 숫자 벡터들 만큼 seq()
함수가 수행되어 연속적인 숫자가 만들어집니다. 예를 들면 nvec = c(3, 2)
이면 seq(3)
, seq(2)
가 수행됩니다.
sequence(nvec = c(3, 2)) # c(seq(3), seq(2)) 또는 c(1:3, 1:2)와 동일
#> [1] 1 2 3 1 2
sequence(nvec = c(3, 2, 5))
#> [1] 1 2 3 1 2 1 2 3 4 5
sequence(c(3, 2), from = 2) # 시작숫자 지정
#> [1] 2 3 4 2 3
sequence(c(3, 2), from = 2, by = -2) # 시작숫자, 간격 지정
#> [1] 2 0 -2 2 0
sequence(c(3, 2), by = c(2, -2))
#> [1] 1 3 5 1 -1
5.4.15 gl()
gl(n, k, length = n*k, labels = seq_len(n), ordered = FALSE)
함수는
요인 수준을 반복적으로 생성하여 반환합니다. gl은 generate levels의 약자로 생각됩니다.
- n : 수준을 나태내는 숫자. n = 2이면 label을 따로 지정하지 않은 경우 수준이 1, 2로 표현됩니다.
- k : 수준을 반복할 숫자. k = 8이면 8번 반복합니다.
- length : 생성되는 총 데이터의 갯수
- labels : 수준에 대한 이름
- ordered : TRUE이면 요인의 순서가 정해집니다. (순서형 데이터)
gl(n = 2, k = 8) # 수준 1, 2를 각각 8번 반복
#> [1] 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2
#> Levels: 1 2
gl(n = 2, k = 8, labels = c("Contol", "Treat")) # 수준 이름 지정
#> [1] Contol Contol Contol Contol Contol Contol Contol Contol Treat Treat
#> [11] Treat Treat Treat Treat Treat Treat
#> Levels: Contol Treat
gl(n = 2, k = 1, length = 10) # 수준 1, 2가 각각 1번씩 반복되며 10개 생성
#> [1] 1 2 1 2 1 2 1 2 1 2
#> Levels: 1 2
gl(n = 2, k = 2, length = 10) # 수준 1, 2가 각각 2번씩 반복되며 10개 생성
#> [1] 1 1 2 2 1 1 2 2 1 1
#> Levels: 1 2
# 수준 1, 2가 M과 F로 순서있게 네이밍 되고, 각각 3번씩 반복되며 10개 생성
gl(2, 3, 10, labels = c("M", "F"), ordered = TRUE)
#> [1] M M M F F F M M M F
#> Levels: M < F
5.4.16 sweep()
sweep(x, MARGIN, STATS, FUN = "-", check.margin = TRUE, ...)
함수는
행렬, 데이터프레임 등에 통계량과 함수를 적용하여 그 결과를 반환하는 함수입니다.
데이터 x에 일률적으로 특정 숫자만큼 더하거나 빼기를 할 때 많이 사용합니다.
- x : 입력 데이터로서 배열, 행렬, 데이터프레임
- MARGIN : 행과 열 방향 지정. 1이면 열방향, 2이면 행방향
- STATS : 적용할 요약 통계량 또는 수치
- FUN : 적용할 함수 (기본값은 “-” 임)
x <- matrix(1:12, ncol = 3); x
#> [,1] [,2] [,3]
#> [1,] 1 5 9
#> [2,] 2 6 10
#> [3,] 3 7 11
#> [4,] 4 8 12
# 행렬 x를 행방향(2)으로 1씩 빼줌
sweep(x, MARGIN = 2, STATS = 1, FUN = "-")
#> [,1] [,2] [,3]
#> [1,] 0 4 8
#> [2,] 1 5 9
#> [3,] 2 6 10
#> [4,] 3 7 11
# 행렬 x를 열방향(1)으로 각각 1, 2, 3, 4를 더해줌
sweep(x, 1, c(1,2,3,4), FUN = "+")
#> [,1] [,2] [,3]
#> [1,] 2 6 10
#> [2,] 4 8 12
#> [3,] 6 10 14
#> [4,] 8 12 16
# 행 기준 비율 계산
round(sweep(x, 1, apply(x, 1, sum), FUN = "/") * 100, 1)
#> [,1] [,2] [,3]
#> [1,] 6.7 33.3 60.0
#> [2,] 11.1 33.3 55.6
#> [3,] 14.3 33.3 52.4
#> [4,] 16.7 33.3 50.0
# 열 기준 비율 계산
round(sweep(x, 2, apply(x, 2, sum), FUN = "/") * 100, 1)
#> [,1] [,2] [,3]
#> [1,] 10 19.2 21.4
#> [2,] 20 23.1 23.8
#> [3,] 30 26.9 26.2
#> [4,] 40 30.8 28.6
# 전체 기준 비율 계산
round(sweep(x, 2, sum(x), FUN = "/") * 100, 1)
#> [,1] [,2] [,3]
#> [1,] 1.3 6.4 11.5
#> [2,] 2.6 7.7 12.8
#> [3,] 3.8 9.0 14.1
#> [4,] 5.1 10.3 15.4
# 데이터프레임의 숫자 열에 각각 1씩 빼기
str(iris)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
y <- sweep(iris[1:4], MARGIN = 2, STATS = 1, FUN = "-")
str(y)
#> 'data.frame': 150 obs. of 4 variables:
#> $ Sepal.Length: num 4.1 3.9 3.7 3.6 4 4.4 3.6 4 3.4 3.9 ...
#> $ Sepal.Width : num 2.5 2 2.2 2.1 2.6 2.9 2.4 2.4 1.9 2.1 ...
#> $ Petal.Length: num 0.4 0.4 0.3 0.5 0.4 0.7 0.4 0.5 0.4 0.5 ...
#> $ Petal.Width : num -0.8 -0.8 -0.8 -0.8 -0.8 -0.6 -0.7 -0.8 -0.8 -0.9 ...
5.4.17 aggregate()
aggregate(x, ...)
함수는 데이터 x의 그룹별로 함수를 적용하여 그 결과를 반환합니다.
- x : 입력 데이터
- by : 그룹핑 변수(열)로서 리스트 형식이어야 함
- FUN : 적용할 함수
str(iris)
#> 'data.frame': 150 obs. of 5 variables:
#> $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
#> $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
#> $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
#> $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
#> $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
# 종류별로 평균을 구함
aggregate(iris[1:4], by = list(iris$Species), mean, na.rm = TRUE)
#> Group.1 Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 1 setosa 5.01 3.43 1.46 0.246
#> 2 versicolor 5.94 2.77 4.26 1.326
#> 3 virginica 6.59 2.97 5.55 2.026
# 그룹핑 그룹에 이름을 지정할 수 있음(종류)
aggregate(iris[1:4], by = list(종류 = iris$Species), mean, na.rm = TRUE)
#> 종류 Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 1 setosa 5.01 3.43 1.46 0.246
#> 2 versicolor 5.94 2.77 4.26 1.326
#> 3 virginica 6.59 2.97 5.55 2.026
# 적용할 함수에 인자들을 지정할 수 있음
aggregate(iris[1:4], by = list(종류 = iris$Species), mean, na.rm = TRUE, trim = 0.1)
#> 종류 Sepal.Length Sepal.Width Petal.Length Petal.Width
#> 1 setosa 5.00 3.42 1.46 0.238
#> 2 versicolor 5.94 2.78 4.29 1.325
#> 3 virginica 6.57 2.96 5.51 2.033
str(infert) # R 내장 데이터 infert
#> 'data.frame': 248 obs. of 8 variables:
#> $ education : Factor w/ 3 levels "0-5yrs","6-11yrs",..: 1 1 1 1 2 2 2 2 2 2 ...
#> $ age : num 26 42 39 34 35 36 23 32 21 28 ...
#> $ parity : num 6 1 6 4 3 4 1 2 1 2 ...
#> $ induced : num 1 1 2 2 1 2 0 0 0 0 ...
#> $ case : num 1 1 1 1 1 1 1 1 1 1 ...
#> $ spontaneous : num 2 0 0 0 1 1 0 0 1 0 ...
#> $ stratum : int 1 2 3 4 5 6 7 8 9 10 ...
#> $ pooled.stratum: num 3 1 4 2 32 36 6 22 5 19 ...
# 2개 변수로 그룹핑
aggregate(infert[2:3], by = list(infert$education, infert$spontaneous),
mean, na.rm = TRUE)
#> Group.1 Group.2 age parity
#> 1 0-5yrs 0 36.6 4.11
#> 2 6-11yrs 0 33.7 1.72
#> 3 12+ yrs 0 29.7 1.66
#> 4 0-5yrs 1 34.0 4.00
#> 5 6-11yrs 1 31.2 2.45
#> 6 12+ yrs 1 28.9 1.70
#> 7 0-5yrs 2 30.0 5.00
#> 8 6-11yrs 2 32.4 3.06
#> 9 12+ yrs 2 31.6 2.89