5.8 스칼라 및 자동반복 규칙

5.8.1 스칼라(scalar)

벡터 간의 상호 호환되도록 벡터의 유형을 암시적으로 강제변환하는 것에 대해 앞에서 살펴 보았습니니다. 그런데 R은 벡터의 길이도 암시적으로 강제변환을 합니다.

5.8.2 자동 반복(recycling)

더 짧은 벡터가 더 긴 벡터와 동일한 길이로 반복(repeat)되거나 자동반복(recycling)되기 때문에이를 벡터 자동반복(recyling)이라고 합니다.

이것은 일반적으로 벡터와 “스칼라”를 혼합할 때 가장 유용합니다. R에는 실제로 스칼라가 없기 때문에 스칼라를 따옴표로 묶었습니다. 대신 단일 숫자는 길이가 1인 벡터입니다. 스칼라가 없기 때문에 대부분의 내장 함수는 벡터화되어 숫자 벡터에서 작동합니다. 이것이 바로 이 코드가 작동하는 이유입니다.

data1 <- sample(10) + 100
data2 <- runif(10) > 0.5

R에서 기본적인 수학 연산은 벡터로 작동합니다. 즉, 간단한 수학적 계산을 수행할 때 명시적 반복을 수행할 필요가 없습니다.

5.8.3 길이가 다른 두 벡터 연산

길이가 같은 벡터 두 개 또는 벡터와 “스칼라”를 더하면 어떤 일이 발생해야 하는지 직관적입니다. 하지만 길이가 다른 두 벡터를 더하면 어떻게 될까요?

1:10 + 1:2     # 1:10는 요소가 10개, 반면에 1:2는 요소가 2개. 즉 10이 2이 5배가 된다. -> 자동 채우기로 연산
##  [1]  2  4  4  6  6  8  8 10 10 12
1:10 + 1:3     # 1:10는 요소가 10개, 그런데 1:3은 요소가 3개. 즉 10은 3의 정수 배수가 안된다. -> 경고메시지
## Warning in 1:10 + 1:3: 두 객체의 길이가 서로 배수관계에 있지 않습니다
##  [1]  2  4  6  5  7  9  8 10 12 11

여기서 R은 가장 짧은 벡터를 가장 긴 벡터와 같은 길이로 확장합니다. 긴 벡터의 요소 갯수가 짧은 벡터의 요소 갯수에 정수 배수가 되면 R은 알아서 짧은 벡터를 자동반복시켜 처리합니다. 그러나 정수 배수가 되지 않으면 R은 경고 메시지를 보여 줍니다.

벡터의 자동반복은 매우 간결하고 영리한 코드를 만드는 데 사용할 수 있지만 문제를 조용히 숨길 수도 있습니다. 이러한 이유로 tidyverse 패키지의 벡터화된 함수는 스칼라가 아닌 다른 것을 자동반복할 때 오류를 발생시킵니다. tidyverse 패키지의 벡터 함수들은 rep() 함수를 사용하여 직접 자동 반복을 수행해야 합니다.

library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.0 --
## √ ggplot2 3.3.3     √ dplyr   1.0.2
## √ tibble  3.0.4     √ stringr 1.4.0
## √ tidyr   1.1.2     √ forcats 0.5.0
## √ purrr   0.3.4
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter()        masks stats::filter()
## x tibble::has_rownames() masks tester::has_rownames()
## x purrr::is_integer()    masks tester::is_integer()
## x purrr::is_vector()     masks tester::is_vector()
## x dplyr::lag()           masks stats::lag()
tibble(x = 1:4, y = 1:3)              #  x컬럼의 요소 갯수는 4개인 반면, y 컬럼의 요소 갯수는 3개. -> Error
## Error: Tibble columns must have compatible sizes.
## * Size 4: Existing data.
## * Size 3: Column `y`.
## i Only values of size one are recycled.
tibble(x = 1:4, y = rep(1:2, 2))      # y 컬럼의 값으로 (1, 2)를 2번 반복함(`rep()` 함수 사용)
## # A tibble: 4 x 2
##       x     y
##   <int> <int>
## 1     1     1
## 2     2     2
## 3     3     1
## 4     4     2