vcrts01 - Combining Vectors

Page content

I. 개요

vctrs 패키지. Vector Helpers 패키지1라고 불리운다. 벡터를 활용할 때, 어려운 부분은 데이터와 조합해서 사용할 때다. 특히 서로다른 성질의 Vectors를 Combining 할 때 발생하는 에러에 대해 효과적으로 해결할 수 있는 대안을 제시한다.

II. Vectors

벡터에 관한 기초 부분은 여기에서 생략하고, 필자가 작성한 기초 부분에서 참조하기를 바란다.

(1) 벡터의 정의

R의 기본문법에서 벡터의 정의는 다음과 같다.

c(1, 2, 3)
## [1] 1 2 3
c("a", "b", "c")
## [1] "a" "b" "c"

(2) tidyverse

벡터와 관련되어서 일반적으로 다음과 같은 함수에서 넓게 활용된다.

  • dplyr::mutate()dplyr::summarise()은 각 그룹에서 나오는 결과물들을 벡터화해서 처리한다.
  • dplyr::bind_rows()는 서로 다른 데이터셋에 존재하는 vector들을 연결한다.

III. Problems

이렇게, 데이터 프레임의 기본연산으로 벡터는 매우 중요하게 다뤄지는 것이 R의 기본문법이다. 그런데, R의 기본문법에는 비슷하지만, 조금씩 다른 벡터의 성질이 있다.

다음 코드를 보자.

c(factor("x"), factor("y"))
## [1] 1 1
  • 즉, c()함수를 활용해 factor 범주화 하는 것은 허용되지 않고, integer level로 바뀌는 것을 볼 수 있다.

이번엔 날짜와 관련된 코드를 보자. 사실 누구나 경험하는 에러일 것이다. 또한 대처법도 쉽지가 않다.

today <- as.Date("2020-04-21")
now <- as.POSIXct("2020-04-21 10:34")

c(today, now)
## [1] "2020-04-21"    "4348213-07-01"

즉, Date 형식과, POSIXct 형식에서 c()함수는 약간 다르게 인식하는 것을 확인할 수 있다. 문제는 이렇게 다른 형식이라 할지라도 class는 동일하게 Date로 인식한다.

class(c(today, now))
## [1] "Date"

상상해보자. 만약 1000개의 데이터가 있는데, 이 중, 800개는 Date 형식이고, 200개는 POSIXct형식일 때, 일일이 Date를 조회하면서 수정할수는 없다.

이번에는 unclass를 활용해서 다시한번 c()를 확인해보자.

unclass(c(today, now))
## [1]      18373 1587432840

unclass를 활용하니 이번에는 둘다 숫자로 나온다. 이번에는 now, today의 순서를 바꿔보자.

c(now, today)
## [1] "2020-04-21 10:34:00 KST" "1970-01-01 14:06:13 KST"

today의 날짜가 제대로 인식되지 못하는 걸 확인할 수 있다. 이번엔 어떤 데이터 타입인지 class를 사용하여 확인해보자.

class(c(now, today))
## [1] "POSIXct" "POSIXt"

이번엔 POSIxt로 출력되는 걸 확인할 수 있다. unclass를 활용하면 어떻게 될까?

unclass(c(now, today))
## [1] 1587432840      18373

이번에도 숫자로 출력된다. 지금까지 계속 읽어왔다면, 느끼겠지만, 현재 today와 now 값을 통일시키지 않는다면 이러한 에러는 계속 발생할 것이다. 즉, 데이터가 적으면 상관이 없지만 만약 많으면 어떻게 할 것인가? 현재로써 유일한 대안은 사용자 정의 함수를 만들어야 한다.

그런데, 시간이 없다면??

IV. vctrs 패키지 활용

이 때 필요한 것이, vector helpers 패키지를 활용하는 것이다. 이 때, vec_c함수를 사용하는데, 크게 3가지의 원칙을 삼는다.

(1) Symmetry

  • 즉, today, now의 순서가 바뀌어도 일단 값은 동일하게 나온다는 원칙이다. 소스코드를 보며 직접 확인해보자.
library(vctrs)
vec_c(today, now)
## [1] "2020-04-21 00:00:00 KST" "2020-04-21 10:34:00 KST"
vec_c(now, today)
## [1] "2020-04-21 10:34:00 KST" "2020-04-21 00:00:00 KST"

(2) Enrichment

vec_c함수는 조금 더 확장성 있는 레벨의 데이터타입을 변환한다는 뜻이다. 간단히 설명하면, integer와 double의 데이터가 섞여 있으면, 조금더 유연한 double로 반환하다는 것이고, 앞에서 본것 처럼, 날짜의 경우, Date와 POSIXct의 데이터는 POSIXct의 유형으로 결과값이 반환된다는 뜻이다.

  • Integer and Double
vec_c(1, 1.5)
## [1] 1.0 1.5
  • Date and POSIXct
vec_c(today, now)
## [1] "2020-04-21 00:00:00 KST" "2020-04-21 10:34:00 KST"

(3) Consistency

R의 기본문법은 서로 다른 데이터 유형이라면, 문자열-숫자형 순으로 자동으로 치환되서 출력된다.

c(1, "2")
## [1] "1" "2"

그런데, vec_c는 데이터의 유형이 완전히 서로 다른 형태라면 반환되지 않고 에러가 발생한다.

  • 에러부터 확인해보자.
vec_c("a", 1)
Error: No common type for `..1` <character> and `..2` <double>.
vec_c(factor("x"), today)
Error: No common type for `..1` <factor<5a425>> and `..2` <date>.

Error 메시지를 보면 No common type이라는 것을 볼 수 있다. 즉, 완전히 다른 형태의 값이 존재한다는 것을 알 수 있다. 결과적으로 조금 더 엄격한 것을 확인할 수 있다.

V. 활용 및 응용

R의 기본문법에서는 에러가 발생 했던 부분을 다시한번 응용해서 적용해보자. 아마 아래와 같이 적용할 수 있을 것 같다.

vec_c(factor("x"), factor("y"))
## [1] x y
## Levels: x y
vec_c("x", factor("y"))
## [1] "x" "y"
vec_c(factor("x"), "y")
## [1] "x" "y"
vec_c(1, as.integer("2"))
## [1] 1 2
vec_c(as.character(1), "2")
## [1] "1" "2"

즉, 이렇게 데이터 형변환을 조금 더 엄격하게 해서 혹시 있을지 모를 데이터의 섞임을 방지하고자 노력하는 것이 위 문법의 취지인 것 같다.

VI. Reference

Wickham, H. (2020, April 27). dplyr 1.0.0 and vctrs. Retrieved April 28, 2020, from https://www.tidyverse.org/blog/2020/04/dplyr-1-0-0-and-vctrs/

R 강의 소개


  1. Hadley Wickham이 주도하는 RStudio팀에서 개발하였으며, 현재 0.2.4버전으로 2020-03-10에 배포되었다. 출처: https://cran.r-project.org/web/packages/vctrs/index.html ↩︎