27  기본 R 필드 가이드

27.1 소개

프로그래밍 섹션을 마무리하기 위해, 이 책에서 다루지 않은 가장 중요한 기본(base) R 함수들을 간단히 살펴보겠습니다. 이 도구들은 프로그래밍을 더 많이 할 때 특히 유용하며, 야생에서 만날 코드를 읽는 데 도움이 될 것입니다.

이 시점에서 tidyverse만이 데이터 과학 문제를 해결하는 유일한 방법이 아니라는 점을 상기시키는 것이 좋겠습니다. 이 책에서 tidyverse를 가르치는 이유는 tidyverse 패키지들이 공통된 디자인 철학을 공유하여 함수 간의 일관성을 높이고 새로운 함수나 패키지를 배우고 사용하기 조금 더 쉽게 만들기 때문입니다. 기본 R을 사용하지 않고는 tidyverse를 사용할 수 없으므로, 패키지를 로드하기 위한 library(), 수치 요약을 위한 sum()mean(), 팩터, 날짜, POSIXct 데이터 유형, 그리고 물론 +, -, /, *, |, &, !와 같은 모든 기본 연산자에 이르기까지 이미 많은 기본 R 함수를 가르쳐 드렸습니다. 지금까지 우리가 집중하지 않았던 것은 기본 R 워크플로우이므로, 이 장에서는 그 중 몇 가지를 강조할 것입니다.

이 책을 읽고 나면 기본 R, data.table 및 기타 패키지를 사용하여 동일한 문제에 대한 다른 접근 방식을 배우게 될 것입니다. 특히 StackOverflow를 사용하는 경우 다른 사람이 작성한 R 코드를 읽기 시작할 때 의심할 여지 없이 이러한 다른 접근 방식을 접하게 될 것입니다. 다양한 접근 방식을 혼합하여 코드를 작성하는 것은 100% 괜찮습니다. 다른 사람의 말에 휘둘리지 마세요!

이 장에서는 [를 사용한 부분집합, [[$를 사용한 부분집합, apply 계열 함수, for 루프라는 네 가지 큰 주제에 중점을 둘 것입니다. 마지막으로 두 가지 필수 플롯 함수에 대해 간단히 설명하겠습니다.

27.1.1 선수 지식

이 장은 기본 R에 중점을 두므로 실제 전제 조건은 없지만, 차이점 중 일부를 설명하기 위해 tidyverse를 로드할 것입니다.

library(tidyverse)
#> Warning: package 'ggplot2' was built under R version 4.5.2
#> Warning: package 'readr' was built under R version 4.5.2

27.2 [로 여러 요소 선택하기

[는 벡터와 데이터 프레임에서 하위 구성 요소를 추출하는 데 사용되며 x[i] 또는 x[i, j]와 같이 호출됩니다. 이 섹션에서는 [의 힘을 소개합니다. 먼저 벡터와 함께 사용하는 방법을 보여준 다음, 데이터 프레임과 같은 2차원(2d) 구조로 동일한 원리가 어떻게 간단하게 확장되는지 보여줍니다. 그런 다음 다양한 dplyr 동사가 [의 특수한 경우임을 보여줌으로써 지식을 굳히는 데 도움을 줄 것입니다.

27.2.1 벡터 부분집합하기

벡터를 부분집합할 수 있는, 즉 x[i]에서 i가 될 수 있는 주요 유형은 다섯 가지입니다:

  1. 양의 정수 벡터. 양의 정수로 부분집합하면 해당 위치의 요소가 유지됩니다:

    x <- c("one", "two", "three", "four", "five")
    x[c(3, 2, 5)]
    #> [1] "three" "two"   "five"

    위치를 반복함으로써 실제로 입력보다 더 긴 출력을 만들 수 있으므로 “부분집합”이라는 용어는 다소 부적절할 수 있습니다.

    x[c(1, 1, 5, 5, 5, 2)]
    #> [1] "one"  "one"  "five" "five" "five" "two"
  2. 음의 정수 벡터. 음수 값은 지정된 위치의 요소를 삭제합니다:

    x[c(-1, -3, -5)]
    #> [1] "two"  "four"
  3. 논리형 벡터. 논리형 벡터로 부분집합하면 TRUE 값에 해당하는 모든 값이 유지됩니다. 이것은 비교 함수와 함께 사용할 때 가장 유용합니다.

    x <- c(10, 3, NA, 5, 8, 1, NA)
    
    # x의 모든 결측되지 않은 값
    x[!is.na(x)]
    #> [1] 10  3  5  8  1
    
    # x의 모든 짝수(또는 결측!) 값
    x[x %% 2 == 0]
    #> [1] 10 NA  8 NA

    filter()와 달리 NA 인덱스는 출력에 NA로 포함됩니다.

  4. 문자형 벡터. 명명된 벡터가 있는 경우 문자형 벡터로 부분집합할 수 있습니다:

    x <- c(abc = 1, def = 2, xyz = 5)
    x[c("xyz", "def")]
    #> xyz def 
    #>   5   2

    양의 정수로 부분집합하는 것과 마찬가지로 문자형 벡터를 사용하여 개별 항목을 복제할 수 있습니다.

  5. 없음. 마지막 유형의 부분집합은 아무것도 없는 x[]이며, 이는 완전한 x를 반환합니다. 이것은 벡터를 부분집합하는 데는 유용하지 않지만, 곧 보게 되겠지만 티블과 같은 2차원 구조를 부분집합할 때 유용합니다.

27.2.2 데이터 프레임 부분집합하기

데이터 프레임과 함께 [를 사용할 수 있는 꽤 다양한 방법1이 있지만, 가장 중요한 방법은 df[rows, cols]로 행과 열을 독립적으로 선택하는 것입니다. 여기서 rowscols는 위에서 설명한 벡터입니다. 예를 들어 df[rows, ]df[, cols]는 행만 선택하거나 열만 선택하며, 빈 부분집합을 사용하여 다른 차원을 보존합니다.

다음은 몇 가지 예입니다:

df <- tibble(
  x = 1:3, 
  y = c("a", "e", "f"), 
  z = runif(3)
)

# 첫 번째 행과 두 번째 열 선택
df[1, 2]
#> # A tibble: 1 × 1
#>   y    
#>   <chr>
#> 1 a

# 모든 행과 x, y 열 선택
df[, c("x" , "y")]
#> # A tibble: 3 × 2
#>       x y    
#>   <int> <chr>
#> 1     1 a    
#> 2     2 e    
#> 3     3 f

# `x`가 1보다 큰 행과 모든 열 선택
df[df$x > 1, ]
#> # A tibble: 2 × 3
#>       x y         z
#>   <int> <chr> <dbl>
#> 1     2 e     0.834
#> 2     3 f     0.601

$로 돌아오겠지만 문맥상 df$x가 무엇을 하는지 짐작할 수 있을 것입니다: df에서 x 변수를 추출합니다. 여기서 [는 tidy evaluation을 사용하지 않으므로 x 변수의 출처를 명시해야 하기 때문에 이것을 사용해야 합니다.

[와 관련하여 티블과 데이터 프레임 사이에는 중요한 차이점이 있습니다. 이 책에서 우리는 주로 티블을 사용했는데, 티블은 데이터 프레임이지만 삶을 조금 더 쉽게 만들기 위해 일부 동작을 조정합니다. 대부분의 경우 “티블”과 “데이터 프레임”을 상호 교환적으로 사용할 수 있으므로 R의 내장 데이터 프레임에 특히 주의를 기울이고 싶을 때 data.frame이라고 쓸 것입니다. dfdata.frame인 경우 df[, cols]col이 단일 열을 선택하면 벡터를 반환하고 둘 이상의 열을 선택하면 데이터 프레임을 반환합니다. df가 티블이면 [는 항상 티블을 반환합니다.

df1 <- data.frame(x = 1:3)
df1[, "x"]
#> [1] 1 2 3

df2 <- tibble(x = 1:3)
df2[, "x"]
#> # A tibble: 3 × 1
#>       x
#>   <int>
#> 1     1
#> 2     2
#> 3     3

data.frame의 이러한 모호성을 피하는 한 가지 방법은 drop = FALSE를 명시적으로 지정하는 것입니다:

df1[, "x" , drop = FALSE]
#>   x
#> 1 1
#> 2 2
#> 3 3

27.2.3 dplyr 등가물

여러 dplyr 동사는 [의 특수한 경우입니다:

  • filter()는 결측값을 제외하도록 주의하면서 논리형 벡터로 행을 부분집합하는 것과 같습니다:

    df <- tibble(
      x = c(2, 3, 1, 1, NA), 
      y = letters[1:5],
      z = runif(5)
    )
    df |> filter(x > 1)
    
    # 다음은 동일함
    df[!is.na(df$x) & df$x > 1, ]

    야생에서 흔히 볼 수 있는 또 다른 기술은 결측값을 삭제하는 부작용을 위해 which()를 사용하는 것입니다: df[which(df$x > 1), ].

  • arrange()는 정수 벡터로 행을 부분집합하는 것과 같으며, 보통 order()로 생성됩니다:

    df |> arrange(x, y)
    
    # 다음은 동일함
    df[order(df$x, df$y), ]

    order(decreasing = TRUE)를 사용하여 모든 열을 내림차순으로 정렬하거나 -rank(col)을 사용하여 개별적으로 열을 내림차순으로 정렬할 수 있습니다.

  • select()relocate()는 모두 문자형 벡터로 열을 부분집합하는 것과 비슷합니다:

    df |> select(x, z)
    
    # 다음은 동일함
    df[, c("x", "z")]

기본 R은 subset()이라는 filter()select()2의 기능을 결합한 함수도 제공합니다:

df |> 
  filter(x > 1) |> 
  select(y, z)
#> # A tibble: 2 × 2
#>   y           z
#>   <chr>   <dbl>
#> 1 a     0.157  
#> 2 b     0.00740
# 다음은 동일함
df |> subset(x > 1, c(y, z))

이 함수는 dplyr 구문의 많은 부분에 영감을 주었습니다.

27.2.4 연습문제

  1. 벡터를 입력으로 받아 다음을 반환하는 함수를 만드세요:

    1. 짝수 위치에 있는 요소.
    2. 마지막 값을 제외한 모든 요소.
    3. 짝수 값만(결측값 없음).
  2. x[-which(x > 0)]x[x <= 0]과 같지 않은 이유는 무엇입니까? which()에 대한 문서를 읽고 실험을 통해 알아내세요.

27.3 $[[로 단일 요소 선택하기

많은 요소를 선택하는 [는 단일 요소를 추출하는 [[$와 짝을 이룹니다. 이 섹션에서는 [[$를 사용하여 데이터 프레임에서 열을 뽑아내는 방법을 보여주고, data.frame과 티블 간의 몇 가지 차이점에 대해 논의하며, 리스트와 함께 사용할 때 [[[의 중요한 차이점을 강조합니다.

27.3.1 데이터 프레임

[[$는 데이터 프레임에서 열을 추출하는 데 사용할 수 있습니다. [[는 위치나 이름으로 액세스할 수 있으며 $는 이름에 의한 액세스에 특화되어 있습니다:

tb <- tibble(
  x = 1:4,
  y = c(10, 4, 1, 21)
)

# 위치로
tb[[1]]
#> [1] 1 2 3 4

# 이름으로
tb[["x"]]
#> [1] 1 2 3 4
tb$x
#> [1] 1 2 3 4

또한 기본 R에서 mutate()에 해당하는 새로운 열을 만드는 데에도 사용할 수 있습니다:

tb$z <- tb$x + tb$y
tb
#> # A tibble: 4 × 3
#>       x     y     z
#>   <int> <dbl> <dbl>
#> 1     1    10    11
#> 2     2     4     6
#> 3     3     1     4
#> 4     4    21    25

transform(), with(), within()을 포함하여 새 열을 만드는 다른 여러 기본 R 접근 방식이 있습니다. Hadley는 https://gist.github.com/hadley/1986a273e384fb2d4d752c18ed71bedf에 몇 가지 예제를 모았습니다.

빠른 요약을 수행할 때 $를 직접 사용하는 것이 편리합니다. 예를 들어 가장 큰 다이아몬드의 크기나 cut의 가능한 값을 찾고 싶다면 summarize()를 사용할 필요가 없습니다:

max(diamonds$carat)
#> [1] 5.01

levels(diamonds$cut)
#> [1] "Fair"      "Good"      "Very Good" "Premium"   "Ideal"

dplyr는 Chapter 3 에서 언급하지 않은 [[/$에 해당하는 pull()을 제공합니다. pull()은 변수 이름이나 변수 위치를 취하고 해당 열만 반환합니다. 즉, 위의 코드를 파이프를 사용하도록 다시 쓸 수 있습니다:

diamonds |> pull(carat) |> max()
#> [1] 5.01

diamonds |> pull(cut) |> levels()
#> [1] "Fair"      "Good"      "Very Good" "Premium"   "Ideal"

27.3.2 티블

$와 관련하여 티블과 기본 data.frame 사이에는 몇 가지 중요한 차이점이 있습니다. 데이터 프레임은 변수 이름의 접두사를 일치시키고(부분 일치라고 함) 열이 존재하지 않아도 불평하지 않습니다:

df <- data.frame(x1 = 1)
df$x
#> [1] 1
df$z
#> NULL

티블은 더 엄격합니다: 변수 이름을 정확히 일치시키며 액세스하려는 열이 존재하면 경고를 생성합니다:

tb <- tibble(x1 = 1)

tb$x
#> Warning: Unknown or uninitialised column: `x`.
#> NULL
tb$z
#> Warning: Unknown or uninitialised column: `z`.
#> NULL

이런 이유로 우리는 때때로 티블이 게으르고 무뚝뚝하다고 농담합니다: 덜 일하고 더 많이 불평합니다.

27.3.3 리스트

[[$는 리스트 작업에도 정말 중요하며 [와 어떻게 다른지 이해하는 것이 중요합니다. l이라는 이름의 리스트로 차이점을 설명해 보겠습니다:

l <- list(
  a = 1:3, 
  b = "a string", 
  c = pi,
  d = list(-1, -5)
)
  • [는 하위 리스트를 추출합니다. 추출하는 요소의 수에 관계없이 결과는 항상 리스트입니다.

    str(l[1:2])
    #> List of 2
    #>  $ a: int [1:3] 1 2 3
    #>  $ b: chr "a string"
    
    str(l[1])
    #> List of 1
    #>  $ a: int [1:3] 1 2 3
    
    str(l[4])
    #> List of 1
    #>  $ d:List of 2
    #>   ..$ : num -1
    #>   ..$ : num -5

    벡터와 마찬가지로 논리형, 정수형 또는 문자형 벡터로 부분집합할 수 있습니다.

  • [[$는 리스트에서 단일 구성 요소를 추출합니다. 그들은 리스트에서 계층 구조의 한 수준을 제거합니다.

    str(l[[1]])
    #>  int [1:3] 1 2 3
    
    str(l[[4]])
    #> List of 2
    #>  $ : num -1
    #>  $ : num -5
    
    str(l$a)
    #>  int [1:3] 1 2 3

[[[의 차이점은 리스트의 경우 특히 중요합니다. [[는 리스트를 파고드는 반면 [는 새롭고 더 작은 리스트를 반환하기 때문입니다. 차이점을 기억하는 데 도움이 되도록 Figure 27.1 에 표시된 특이한 후추통을 살펴보세요. 이 후추통이 리스트 pepper라면 pepper[1]은 단일 후추 패킷이 들어 있는 후추통입니다. pepper[2]는 똑같이 보이지만 두 번째 패킷이 들어 있을 것입니다. pepper[1:2]는 두 개의 후추 패킷이 들어 있는 후추통일 것입니다. pepper[[1]]은 후추 패킷 자체를 추출합니다.

세 장의 사진. 왼쪽은 유리 후추통 사진입니다. 후추통에는 후추 대신  단일 후추 패킷이 들어 있습니다. 가운데는 단일 후추 패킷 사진입니다.  오른쪽은 후추 패킷의 내용물 사진입니다.
Figure 27.1: (왼쪽) Hadley가 호텔 방에서 한 번 발견한 후추통. (가운데) pepper[1]. (오른쪽) pepper[[1]]

데이터 프레임에 1차원 [를 사용할 때도 동일한 원칙이 적용됩니다: df["x"]는 1열 데이터 프레임을 반환하고 df[["x"]]는 벡터를 반환합니다.

27.3.4 연습문제

  1. 벡터의 길이보다 큰 양의 정수로 [[를 사용하면 어떻게 됩니까? 존재하지 않는 이름으로 부분집합하면 어떻게 됩니까?

  2. pepper[[1]][1]은 무엇일까요? pepper[[1]][[1]]은 어떻습니까?

27.4 Apply 계열

Chapter 26 에서 dplyr::across() 및 map 함수 계열과 같은 반복을 위한 tidyverse 기술을 배웠습니다. 이 섹션에서는 이들의 기본 등가물인 apply 계열에 대해 배울 것입니다. 이 문맥에서 apply와 map은 동의어입니다. “벡터의 각 요소에 함수를 매핑”하는 것을 “벡터의 각 요소에 함수를 적용(apply)”한다고 말할 수 있기 때문입니다. 여기서는 야생에서 이들을 인식할 수 있도록 이 계열에 대한 빠른 개요를 제공합니다.

이 계열의 가장 중요한 멤버는 lapply()이며, 이는 purrr::map()3과 매우 유사합니다. 실제로 map()의 고급 기능을 사용하지 않았기 때문에 Chapter 26 의 모든 map() 호출을 lapply()로 바꿀 수 있습니다.

across()에 해당하는 정확한 기본 R 등가물은 없지만 lapply()와 함께 [를 사용하여 근접하게 할 수 있습니다. 이것이 작동하는 이유는 내부적으로 데이터 프레임이 열의 리스트이기 때문에 데이터 프레임에서 lapply()를 호출하면 각 열에 함수가 적용되기 때문입니다.

df <- tibble(a = 1, b = 2, c = "a", d = "b", e = 4)

# 먼저 수치형 열 찾기
num_cols <- sapply(df, is.numeric)
num_cols
#>     a     b     c     d     e 
#>  TRUE  TRUE FALSE FALSE  TRUE

# 그런 다음 lapply()로 각 열을 변환한 다음 원래 값을 대체
df[, num_cols] <- lapply(df[, num_cols, drop = FALSE], \(x) x * 2)
df
#> # A tibble: 1 × 5
#>       a     b c     d         e
#>   <dbl> <dbl> <chr> <chr> <dbl>
#> 1     2     4 a     b         8

위의 코드는 새로운 함수 sapply()를 사용합니다. lapply()와 비슷하지만 항상 결과를 단순화하려고 시도하므로 이름에 s가 붙어 있습니다. 여기서는 리스트 대신 논리형 벡터를 생성합니다. 단순화가 실패하여 예상치 못한 유형을 제공할 수 있으므로 프로그래밍에는 사용하지 않는 것이 좋지만 대화형 사용에는 일반적으로 괜찮습니다. purrr에는 Chapter 26 에서 언급하지 않은 map_vec()이라는 유사한 함수가 있습니다.

기본 R은 vapply()라는 sapply()의 더 엄격한 버전을 제공합니다. 이는 vector apply의 줄임말입니다. 이것은 예상되는 유형을 지정하는 추가 인수를 취하여 입력에 관계없이 동일한 방식으로 단순화가 발생하도록 합니다. 예를 들어 위의 sapply() 호출을 is.numeric()이 길이 1의 논리형 벡터를 반환할 것으로 예상한다고 지정하는 이 vapply()로 바꿀 수 있습니다:

vapply(df, is.numeric, logical(1))
#>     a     b     c     d     e 
#>  TRUE  TRUE FALSE FALSE  TRUE

sapply()vapply()의 구별은 함수 내부에 있을 때 정말 중요하지만(비정상적인 입력에 대한 함수의 견고성에 큰 차이를 만들기 때문입니다), 데이터 분석에서는 일반적으로 중요하지 않습니다.

apply 계열의 또 다른 중요한 멤버는 단일 그룹화된 요약을 계산하는 tapply()입니다:

diamonds |> 
  group_by(cut) |> 
  summarize(price = mean(price))
#> # A tibble: 5 × 2
#>   cut       price
#>   <ord>     <dbl>
#> 1 Fair      4359.
#> 2 Good      3929.
#> 3 Very Good 3982.
#> 4 Premium   4584.
#> 5 Ideal     3458.

tapply(diamonds$price, diamonds$cut, mean)
#>      Fair      Good Very Good   Premium     Ideal 
#>  4358.758  3928.864  3981.760  4584.258  3457.542

불행히도 tapply()는 결과를 명명된 벡터로 반환하므로 여러 요약 및 그룹화 변수를 데이터 프레임으로 수집하려면 약간의 체조가 필요합니다(이렇게 하지 않고 자유 부동 벡터로 작업하는 것은 확실히 가능하지만 경험상 작업이 지연될 뿐입니다). tapply() 또는 기타 기본 기술을 사용하여 다른 그룹화된 요약을 수행하는 방법을 보고 싶다면 Hadley가 gist에 몇 가지 기술을 모아두었습니다.

apply 계열의 마지막 멤버는 행렬 및 배열과 함께 작동하는 이름 그대로의 apply()입니다. 특히 lapply(df, something)을 수행하는 느리고 잠재적으로 위험한 방법인 apply(df, 2, something)을 주의하세요. 우리는 일반적으로 행렬이 아닌 데이터 프레임으로 작업하기 때문에 데이터 과학에서는 거의 나타나지 않습니다.

27.5 for 루프

for 루프는 apply 및 map 계열 모두 내부적으로 사용하는 반복의 기본 구성 요소입니다. for 루프는 더 경험이 많은 R 프로그래머가 됨에 따라 배워야 할 강력하고 일반적인 도구입니다. for 루프의 기본 구조는 다음과 같습니다:

for (element in vector) {
  # 요소로 무언가를 수행
}

for 루프의 가장 간단한 사용은 walk()와 동일한 효과를 얻는 것입니다: 리스트의 각 요소에 대해 부작용이 있는 함수를 호출합니다. 예를 들어, Section 26.4.1 에서 walk()를 사용하는 대신:

paths |> walk(append_file)

for 루프를 사용할 수 있었습니다:

for (path in paths) {
  append_file(path)
}

for 루프의 출력을 저장하려는 경우, 예를 들어 Chapter 26 에서와 같이 디렉토리의 모든 엑셀 파일을 읽으려는 경우 상황이 조금 더 까다로워집니다:

paths <- dir("data/gapminder", pattern = "\\.xlsx$", full.names = TRUE)
files <- map(paths, readxl::read_excel)

사용할 수 있는 몇 가지 다른 기술이 있지만, 출력이 어떻게 보일지 미리 명시하는 것이 좋습니다. 이 경우 paths와 길이가 같은 리스트를 원하므로 vector()로 만들 수 있습니다:

files <- vector("list", length(paths))

그런 다음 paths의 요소를 반복하는 대신 seq_along()을 사용하여 paths의 각 요소에 대한 하나의 인덱스를 생성하여 인덱스를 반복합니다:

seq_along(paths)
#>  [1]  1  2  3  4  5  6  7  8  9 10 11 12

인덱스를 사용하는 것은 입력의 각 위치를 출력의 해당 위치와 연결할 수 있기 때문에 중요합니다:

for (i in seq_along(paths)) {
  files[[i]] <- readxl::read_excel(paths[[i]])
}

티블 리스트를 단일 티블로 결합하려면 do.call() + rbind()를 사용할 수 있습니다:

do.call(rbind, files)
#> # A tibble: 1,704 × 5
#>   country     continent lifeExp      pop gdpPercap
#>   <chr>       <chr>       <dbl>    <dbl>     <dbl>
#> 1 Afghanistan Asia         28.8  8425333      779.
#> 2 Albania     Europe       55.2  1282697     1601.
#> 3 Algeria     Africa       43.1  9279525     2449.
#> 4 Angola      Africa       30.0  4232095     3521.
#> 5 Argentina   Americas     62.5 17876956     5911.
#> 6 Australia   Oceania      69.1  8691212    10040.
#> # ℹ 1,698 more rows

리스트를 만들고 진행하면서 결과를 저장하는 대신, 데이터 프레임을 조각별로 쌓아 올리는 더 간단한 접근 방식이 있습니다:

out <- NULL
for (path in paths) {
  out <- rbind(out, readxl::read_excel(path))
}

벡터가 매우 길어지면 매우 느려질 수 있으므로 이 패턴은 피하는 것이 좋습니다. 이것이 for 루프가 느리다는 지속적인 헛소문의 원인입니다: 루프가 아니라 벡터를 반복적으로 키우는 것이 느린 것입니다.

27.6 플롯

그렇지 않으면 tidyverse를 사용하지 않는 많은 R 사용자가 합리적인 기본값, 자동 범례, 현대적인 모양과 같은 유용한 기능 때문에 플롯을 위해 ggplot2를 선호합니다. 그러나 기본 R 플롯 함수는 매우 간결하기 때문에 여전히 유용할 수 있습니다 — 기본 탐색 플롯을 수행하는 데 입력이 거의 필요하지 않습니다.

야생에서 볼 수 있는 두 가지 주요 유형의 기본 플롯은 각각 plot()hist()로 생성되는 산점도와 히스토그램입니다. 다음은 diamonds 데이터셋의 간단한 예입니다:

# 왼쪽
hist(diamonds$carat)

# 오른쪽
plot(diamonds$carat, diamonds$price)

왼쪽에는 0에서 5캐럿 사이의 다이아몬드 캐럿 히스토그램이 있습니다.  분포는 단봉형이며 오른쪽으로 치우쳐 있습니다. 오른쪽에는 다이아몬드의  가격 대 캐럿 산점도가 있으며, 가격과 캐럿이 모두 증가함에 따라  부채꼴로 퍼지는 양의 관계를 보여줍니다. 산점도는 0에서 3캐럿 사이의  다이아몬드에 비해 3캐럿보다 큰 다이아몬드가 매우 적음을 보여줍니다.

왼쪽에는 0에서 5캐럿 사이의 다이아몬드 캐럿 히스토그램이 있습니다.  분포는 단봉형이며 오른쪽으로 치우쳐 있습니다. 오른쪽에는 다이아몬드의  가격 대 캐럿 산점도가 있으며, 가격과 캐럿이 모두 증가함에 따라  부채꼴로 퍼지는 양의 관계를 보여줍니다. 산점도는 0에서 3캐럿 사이의  다이아몬드에 비해 3캐럿보다 큰 다이아몬드가 매우 적음을 보여줍니다.

기본 플롯 함수는 벡터와 함께 작동하므로 $ 또는 다른 기술을 사용하여 데이터 프레임에서 열을 뽑아내야 합니다.

27.7 요약

이 장에서는 부분집합 및 반복에 유용한 기본 R 함수들을 보여주었습니다. 책의 다른 곳에서 논의된 접근 방식과 비교할 때, 이러한 함수는 데이터 프레임과 일부 열 사양보다는 개별 벡터를 취하는 경향이 있기 때문에 “데이터 프레임” 풍미보다는 “벡터” 풍미가 더 강합니다. 이것은 종종 프로그래밍을 더 쉽게 만들므로 더 많은 함수를 작성하고 자신의 패키지를 작성하기 시작할 때 더 중요해집니다.

이 장으로 책의 프로그래밍 섹션이 끝납니다. 여러분은 R을 사용하는 데이터 과학자가 될 뿐만 아니라 R로 프로그래밍할 수 있는 데이터 과학자가 되는 여정의 확실한 시작을 했습니다. 이 장들이 프로그래밍에 대한 관심을 불러일으켰고 이 책 밖에서 더 배우기를 고대하고 있기를 바랍니다.


  1. https://adv-r.hadley.nz/subsetting.html#subset-multiple을 읽어보고 데이터 프레임을 1차원 객체처럼 부분집합하는 방법과 행렬로 부분집합하는 방법을 확인하세요.↩︎

  2. 하지만 그룹화된 데이터 프레임을 다르게 처리하지 않으며 starts_with()와 같은 선택 도우미 함수를 지원하지 않습니다.↩︎

  3. 진행률 표시줄과 오류 발생 시 문제가 발생한 요소를 보고하는 것과 같은 편리한 기능만 없습니다.↩︎