5.7 벡터 유형의 강제 변환(Coercion)

한 유형의 벡터를 다른 유형으로 변환하거나 강제 변환하는 방법에는 두 가지가 있습니다.

5.7.1 암묵적 강제 변환

암묵적 강제 변환은 특정 유형의 벡터가 예상되는 특정 상황에서 벡터를 사용할 때 발생합니다. 예를 들어 숫자 요약 함수에 논리형 벡터를 사용하거나, 정수형 벡터가 예상되는데 이중 벡터를 사용하는 경우입니다.

이미 가장 중요한 유형의 암시적 강제 변환 (숫자를 사용하는 상황에서 논리 벡터를 사용)을 살펴본 바 있습니다. 예를 들어 논리형 벡터에서의 TRUE값은 정수형에서는 1로 변환되고 FALSE0으로 변환됩니다.

즉, 논리 벡터의 합은 TRUE의 갯수이고, 논리 벡터의 평균은 TRUE의 비율입니다. 즉, 논리형 벡터가 정수형 벡터로 암묵적으로 강제 변환이 되어 처리가 되는 것입니다.

x <- sample(20, 100, replace = TRUE)      # 1~20 사이의 수에서 무작위로 100개를 중복 추출
y <- x > 10                               # 100개 요소 각각에 대해 10보다 큰가를 비교 : TRUE or FALSE
sum(y)                                    # 10보다 큰 요소의 갯수
## [1] 47
mean(y)                                   # 100개 요소 중 10보다 큰 값을 갖는 요소의 비율
## [1] 0.47

반대로 정수형에서 논리형이 되게하는 반대 방향으로 암묵적 강제 변환에 의존하는 일부 코드 (일반적으로 이전)를 볼 수 있습니다.

if (length(x)) {
  # do something
}

length(x)의 경우 그 값이 0이면 FALSE로 변환되고 그렇지 않으면 모두 TRUE로 변환됩니다. 이로 인해 코드를 이해하기가 더 어려워질 수 있기 때문에 이러한 코드는 length(x) > 0와 같이 명시적으로 해 주는 것이 좋습니다.

c()를 사용하여 여러 유형을 포함하는 벡터를 만들 때 어떤 일이 발생하는지 이해하는 것도 중요합니다. 가장 복잡한 유형이 항상 이깁니다. 벡터의 요소들의 값들이 혼합된 경우 벡터는 논리형 < 정수형 < 실수형 < 문자형 등으로 암묵적으로 강제 변환이 이루어집니다.

typeof(c(TRUE, 1L))       # TURE는 '논리형'이고, 1L은 '정수형'입니다. -> 정수형
## [1] "integer"
typeof(c(1L, 1.5))        # 1L은 '정수형'이지만, 1.5는 '실수형(double)'입니다. -> 실수형
## [1] "double"
typeof(c(1.5, "a"))       # 1.5는 '실수형'이지만, "a"눈 '문자형'입니다  -> 문자형
## [1] "character"
typeof(c(TRUE, "a"))      # TRUE는 '논리형'이고, "a"는 "문자형" -> 문자형
## [1] "character"
typeof(c(TRUE, 1.5))      # TRUE는 '논리형'이고, "a"는 "실수형" -> 실수형
## [1] "double"
typeof(c(1L, "a"))        # 1L은 '정수형'이고, "a"는 "문자형" -> 문자형
## [1] "character"

5.7.2 명시적 강제 변환

5.7.2.1 base 패키지의 강제 변환 함수들

as.logical(), as.integer(), as.double()또는 as.character()와 같은 함수를 이용하면 명시적으로 강제 변환이 이루어집니다. 명시적 강제 변환을 사용하는 자신을 발견 할 때마다 항상 업스트림 수정이 가능한지 확인하여 벡터가 처음에 잘못된 유형을 가지지 않도록 해야 합니다. 예를 들어, readr패키지의 col_types 사양을 조정해야 할 수도 있습니다.

함수 설 명
as.character(x) x를 문자형으로 강제 변환
as.numeric(x) 또는 as.double(x) x를 숫자형 또는 실수형으로 강제 변환
as.integer(x) x를 정수형으로 강제 변환
as.logical(x) x를 논리형으로 강제 변환
as.Date(x) x를 날짜형으로 강제 변환
as.complex(x) x를 복소수형으로 강제 변화
# 데이터
data1 <- 2010:2020

# 강제 변환의 예
conv1 <- as.character(data1); typeof(conv1)     # 정수형을 문자형으로 강제변환
## [1] "character"
conv2 <- as.integer(conv1); typeof(conv1)       # 문자형을 정수형으로 강제변환
## [1] "character"
conv3 <- as.numeric(conv2); typeof(conv3)
## [1] "double"
data2 <- c(0, 2, 0, 1, 1, 0) 
conv4 <- as.logical(data2); typeof(conv4)       # 정수형을 논리형으로 강제변환
## [1] "logical"
data3 <- c("2018-01-01", "2019-01-01", "2020-01-01", "2021-01-10")
conv5 <- as.Date(data3); typeof(conv5)          # 문자형을 날짜형으로 강제변환
## [1] "double"

5.7.2.2 readr 패키지의 강제 변환 함수들

tidyverse 패키지 안에 포함되어 있는 readr 패키지에는 다음과 같은 벡터의 데이터 유형을 강제 변환시키는 parse_*() 함수들이 있습니다. 특히, parse_*() 함수들은 벡터의 요소 값을 결측치로 처리할 수 있게 해주는 na = 인수를 제공하고 있습니다.

library(tidyverse)

parse_logical(x, na = c("", "NA"), locale = default_locale(), trim_ws = TRUE)
parse_integer(x, na = c("", "NA"), locale = default_locale(), trim_ws = TRUE)
parse_double(x, na = c("", "NA"), locale = default_locale(), trim_ws = TRUE)
parse_character(x, na = c("", "NA"), locale = default_locale(), trim_ws = TRUE)

예 :

# 패키지 설치와 불러오기
# install.packages("readr")
library(readr)

# 함수의 이용 예
parse_integer(c("1", "2", "3"))                # 문자형 벡터를 정수형 벡터로 강제변환
## [1] 1 2 3
parse_double(c("1.56", "2.34", "3.56"))        # 문자형 벡터를 실수형 벡터로 강제변환
## [1] 1.56 2.34 3.56
parse_logical(c("true", "false"))              # 문자형 벡터를 논리형 벡터로 강제변환
## [1]  TRUE FALSE
parse_number(c("0%", "10%", "150%"))           # 문자형 벡터를 숫자형 벡터로 강제변환 : 숫자만 선택한다
## [1]   0  10 150
parse_number(c("$1,234.5", "$12.45"))
## [1] 1234.50   12.45
parse_datetime("2010-10-01 21:45")             # 문자형 벡터를 날짜-시간형 벡터로 강제변환
## [1] "2010-10-01 21:45:00 UTC"
parse_date("2010-10-01")                       # 문자형 벡터를 날짜형 벡터로 강제변환
## [1] "2010-10-01"
parse_time("1:00pm")                           # 문자형 벡터를 시간형 벡터로 강제변환
## 13:00:00