Online Appendix A — R 필수 사항

선수 지식

핵심 개념 및 기술

소프트웨어 및 패키지

A.1 서론

이 장에서는 통계 프로그래밍 언어 R(R Core Team 2024)을 사용하여 데이터로 이야기를 하는 데 필요한 기초적인 기술에 초점을 맞춥니다. 처음에는 이해가 안 될 수도 있지만, 이것들은 우리가 자주 사용할 기술과 접근 방식입니다. 처음에는 이 장을 빠르게 훑어보고 이해가 안 되는 부분을 메모하십시오. 그런 다음 책의 나머지 부분을 계속 진행하면서 이 장으로 돌아오십시오. 그렇게 하면 다양한 부분이 어떻게 맥락에 맞는지 알 수 있을 것입니다.

R은 통계 프로그래밍을 위한 오픈 소스 언어입니다. 종합 R 아카이브 네트워크(CRAN)에서 R을 무료로 다운로드할 수 있습니다. RStudio는 R을 더 쉽게 사용할 수 있도록 하는 R용 통합 개발 환경(IDE)이며, Posit 여기에서 무료로 다운로드할 수 있습니다.

지난 10여 년은 tidyverse의 사용 증가로 특징지어졌습니다. 이것은 “…데이터 과학을 위해 설계된 R 패키지의 의견이 반영된 컬렉션입니다. 모든 패키지는 기본 설계 철학, 문법 및 데이터 구조를 공유합니다”(Wickham 2020). 세 가지 구별을 명확히 해야 합니다. 즉, 일반적으로 “base”라고 불리는 원본 R 언어; base 위에 구축된 일관된 패키지 모음인 tidyverse; 그리고 다른 패키지입니다.

본질적으로 tidyverse에서 수행하는 모든 작업은 base R에서도 가능합니다. 하지만 tidyverse는 특히 데이터 과학을 위해 설계되었기 때문에, 학습 과정에서 훨씬 직관적이고 편리하게 느껴집니다. 또한 tidyverse의 기능 대부분은 다른 패키지로도 대체할 수 있지만, tidyverse는 패키지들 사이에 설계 철학이 일관되어 있어 통합적인 학습이 용이합니다. 결국 상황에 따라 tidyverse의 편리함과 효율성을 base R이나 다른 특화된 패키지의 기능과 적절히 교환하며 사용하는 판단력이 필요합니다. 실제로 Chapter 10 에서는 대규모 데이터를 다룰 때 SQL이 제공하는 압도적인 효율성을 소개합니다. 예를 들어, tidyverse가 대용량 처리에서 다소 느려질 경우 수천 개의 CSV 파일을 읽기 위해 read_csv() 대신 다른 대안을 찾는 것은 매우 합리적인 선택입니다. 특정 도구에 대한 독단적인 고집을 버리고 base R 및 비-tidyverse 패키지들을 상황에 맞게 적재적소에 활용하는 것은 데이터 과학자로서 한 단계 더 도약했음을 보여주는 지표입니다.

통계 프로그래밍 언어 R을 사용하는 데 있어 핵심은 데이터이며, 우리가 다루는 대부분의 데이터는 인간의 활동을 투영하고 있습니다. 데이터를 기계적으로 처리하다 보면 자칫 인간이라는 본질을 간과하여 과도한 일반화나 윤리적으로 문제가 있는 결과로 이어질 위험이 있습니다. 분석 전 과정에서 데이터가 갖는 의미를 성찰하고 그 결과가 세상에 미칠 영향을 깊이 인식하는 것 또한 데이터 과학자의 중요한 역량입니다.

실제로, 나는 의미에 대한 질문에서 멀어지는 것이 아니라, 정량적 데이터가 당신에게 그것들을 직면하도록 강요한다는 것을 발견합니다. 숫자가 당신을 끌어들입니다. 이런 식으로 데이터를 다루는 것은 겸손의 끝없는 연습이며, 당신이 무엇을 보고 무엇을 볼 수 없는지 끊임없이 생각하게 하고, 측정값이 실제로 무엇을 포착하는지, 즉 그것들이 무엇을 의미하고 누구를 위한 것인지 이해하도록 끊임없이 초대합니다.

Healy (2020)

A.2 R, RStudio, 그리고 Posit Cloud

R과 RStudio는 상호 보완적이지만, 동일한 것은 아닙니다. Müller, Schieferdecker, and Schratz (2019)R은 엔진과 같고 RStudio는 자동차와 같다고 비유하여 그들의 관계를 설명합니다. 우리는 엔진을 다양한 상황에서 사용할 수 있으며, 자동차에만 국한되지 않지만, 이 조합은 특히 유용합니다.

A.2.1 R

R은 일반 통계에 중점을 둔 오픈 소스 무료 프로그래밍 언어입니다. 이 맥락에서 무료는 가격이 0이라는 것을 의미하는 것이 아니라, 개발자들이 사용자에게 원하는 대로 자유롭게 사용할 수 있도록 허용한다는 것을 의미합니다(물론 가격도 0입니다). 이는 Python과 같이 범용으로 설계된 오픈 소스 프로그래밍 언어 또는 Stan과 같이 확률에 중점을 둔 오픈 소스 프로그래밍 언어와 대조됩니다. 1990년대 오클랜드 대학교의 로스 이아카와 로버트 젠틀맨이 만들었으며, 1970년대 벨 연구소에서 개발된 S에서 유래했습니다. R Core Team이 유지 관리하며, 이 “base” 코드의 변경은 체계적으로 이루어지며 다양한 우선 순위를 고려합니다.

많은 사람들이 이 안정적인 base 위에 구축하여 R의 기능을 더 잘, 더 빠르게 자신의 필요에 맞게 확장합니다. 그들은 패키지를 생성하여 이를 수행합니다. 일반적으로, 항상 그런 것은 아니지만, 패키지는 R 코드, 주로 함수 모음이며, 이를 통해 원하는 작업을 더 쉽게 수행할 수 있습니다. 이러한 패키지는 CRAN 및 Bioconductor와 같은 저장소에서 관리됩니다.

패키지를 사용하려면 먼저 컴퓨터에 설치해야 하고, 필요할 때마다 이를 로드(load)해야 합니다. 모나쉬 대학교의 디 쿡 박사는 이 과정을 전구에 비유하여 아주 명쾌하게 설명합니다. 방에 불을 밝히기 위해서는 먼저 전구를 소켓에 끼워야 하고, 그다음 스위치를 켜야 합니다. install.packages("tidyverse")와 같이 패키지를 설치하는 것은 전구를 소켓에 끼우는 작업과 같습니다. 한 번 끼워두면 다시 할 필요가 없죠. 하지만 불을 켜고 싶을 때마다 매번 스위치를 올려야 하듯, 분석을 시작할 때마다 library(tidyverse) 명령어로 패키지를 활성화해 주어야 합니다.

거인의 어깨 위에 서서

디 쿡 박사는 모나쉬 대학교의 통계학 특훈 교수입니다. 1993년 럿거스 대학교에서 통계 그래픽에 중점을 둔 통계학 박사 학위를 받은 후, 아이오와 주립 대학교에서 조교수로 임명되었고, 2005년 정교수로 승진했으며, 2015년 모나쉬로 옮겼습니다. 그녀의 연구 분야 중 하나는 데이터 시각화, 특히 대화형 및 동적 그래픽입니다. Buja, Cook, and Swayne (1996) 는 대화형 데이터 시각화의 분류법과 관련 소프트웨어 XGobi를 제안하며, 이는 Cook and Swayne (2007) 의 초점입니다. Cook et al. (1995) 는 탐색적 데이터 분석을 위한 동적 그래픽 도구의 개발 및 탐색을 다루고, Buja et al. (2009) 는 시각적 통계 방법을 평가하기 위한 프레임워크를 개발하며, 여기서 플롯과 인간 인지는 각각 테스트 통계량과 통계 테스트를 대신합니다. 그녀는 미국 통계 학회 펠로우입니다.

컴퓨터에 패키지를 설치하려면(다시, 컴퓨터당 한 번만 하면 됩니다) install.packages()를 사용합니다.

install.packages("tidyverse")

그리고 패키지를 사용하고 싶을 때는 library()를 사용합니다.

library(tidyverse)

다운로드한 후 R을 열고 직접 사용할 수 있습니다. 주로 명령줄을 통해 상호 작용하도록 설계되었습니다. 이것은 기능적이지만, 명령줄이 제공하는 것보다 더 풍부한 환경을 갖는 것이 유용할 수 있습니다. 특히, 자주 사용될 다양한 비트와 조각을 모아주는 애플리케이션인 통합 개발 환경(IDE)을 설치하는 것이 유용할 수 있습니다. R에 대한 일반적인 IDE 중 하나는 RStudio이지만, Visual Studio와 같은 다른 IDE도 사용됩니다.

A.2.2 RStudio

RStudio는 R과 구별되며, 서로 다른 개체입니다. RStudio는 R 위에 구축되어 R을 더 쉽게 사용할 수 있도록 합니다. 이는 명령줄에서 인터넷을 사용할 수 있지만, 대부분의 사람들이 Chrome, Firefox 또는 Safari와 같은 브라우저를 사용하는 것과 같은 방식입니다.

RStudio는 우리가 비용을 지불하지 않는다는 의미에서 무료입니다. 또한 코드를 가져와 수정하고 배포할 수 있다는 의미에서도 무료입니다. 그러나 RStudio의 제작사인 Posit은 B Corp이긴 하지만 회사이므로 현재 상황이 변경될 수 있습니다. Posit 여기에서 다운로드할 수 있습니다.

RStudio를 열면 Figure A.1 와 같이 보일 것입니다.

Figure A.1: RStudio를 처음 열었을 때

왼쪽 창은 콘솔로, R 코드를 한 줄씩 입력하고 실행할 수 있습니다. 프롬프트 “>” 옆을 클릭하고 “2+2”를 입력한 다음 “return/enter”를 눌러 2+2를 시도해 보십시오.

2 + 2
[1] 4

오른쪽 상단 창에는 환경에 대한 정보가 있습니다. 예를 들어, 변수를 만들면 변수 이름과 일부 속성 목록이 거기에 나타납니다. 프롬프트 옆에 다음 코드를 입력하고, Rohan을 자신의 이름으로 바꾼 다음, 다시 엔터를 누르십시오.

my_name <- "로한"

Chapter 2 에서 언급했듯이 <- 또는 “할당 연산자”는 "로한"을 “my_name”이라는 객체에 할당합니다. 변수 이름과 값이 있는 환경 창에 새 값이 나타나는 것을 알 수 있을 것입니다.

오른쪽 하단 창은 파일 관리자입니다. 현재는 R 기록 파일과 R 프로젝트 파일 두 개만 있어야 합니다. 나중에 이것들이 무엇인지 알아볼 것이지만, 지금은 파일을 만들고 저장할 것입니다.

자세한 내용은 너무 걱정하지 말고 다음 코드를 실행하십시오. 파일 목록에 새 “.rds” 파일이 나타나는 것을 볼 수 있을 것입니다.

saveRDS(object = my_name, file = "my_first_file.rds")

A.2.3 Posit Cloud

RStudio를 자신의 컴퓨터에 다운로드해야 하지만, 처음에는 Posit Cloud를 사용하는 것을 권장합니다. 이것은 Posit에서 제공하는 RStudio의 온라인 버전입니다. 우리는 이것을 사용하여 R과 RStudio에 일관된 환경에서 익숙해질 수 있도록 할 것입니다. 이렇게 하면 컴퓨터나 설치 권한 등에 대해 걱정할 필요가 없습니다.

Posit Cloud의 무료 버전은 비용 부담 없이 시작하기에 매우 훌륭합니다. 비록 유료 버전에 비해 성능이 다소 낮거나 속도가 느릴 수 있지만, 데이터 과학의 기초를 학습하고 실습하는 데는 부족함이 전혀 없습니다.

A.3 시작하기

이제 코드를 살펴보겠습니다. 직접 모든 것을 작성하십시오.

콘솔에서 한 줄씩 작업하는 것도 괜찮지만, 전체 스크립트를 작성한 다음 실행하는 것이 더 쉽습니다. R 스크립트(“파일” \(\rightarrow\) “새 파일” \(\rightarrow\) “R 스크립트”)를 만들어 이를 수행할 것입니다. 콘솔 창은 왼쪽 하단으로 이동하고 R 스크립트가 왼쪽 상단에 열릴 것입니다. 호주 연방 정치인 전체를 가져온 다음 총리의 성별에 대한 작은 표를 만드는 코드를 작성할 것입니다. 이 코드 중 일부는 이 단계에서는 이해가 안 될 수도 있지만, 습관을 들이기 위해 모두 입력한 다음 실행하십시오. 전체 스크립트를 실행하려면 “실행”을 클릭하거나 특정 줄을 강조 표시한 다음 “실행”을 클릭하여 해당 줄만 실행할 수 있습니다.

# 필요한 패키지 설치
install.packages("tidyverse")
install.packages("AustralianPoliticians")
# 이번에 사용할 패키지 로드
library(tidyverse)
library(AustralianPoliticians)

# 총리의 성별 개수 표 만들기
get_auspol("all") |> # GitHub에서 데이터 가져오기
  as_tibble() |>
  filter(wasPrimeMinister == 1) |>
  count(gender)
# A tibble: 2 × 2
  gender     n
  <chr>  <int>
1 female     1
2 male      29

2021년 말 기준으로 여성 총리는 한 명(줄리아 길라드)이었고, 나머지 29명의 총리는 남성이었습니다.

프로그래밍에서 중요한 연산자 중 하나는 “파이프”: |>. 우리는 이것을 “그리고 나서”라고 읽습니다. 이것은 코드 줄의 출력을 가져와 다음 코드 줄의 첫 번째 입력으로 사용합니다. 코드를 더 읽기 쉽게 만듭니다. 배경 지식으로, 수년 동안 R 사용자들은 magrittr(Bache and Wickham 2022)에서 온 %>%를 파이프로 사용했으며, 이는 tidyverse의 일부입니다. Base R은 2021년에 우리가 이 책에서 사용하는 파이프 |>를 추가했으므로, 오래된 코드를 보면 이전 파이프가 사용되는 것을 볼 수 있습니다. 대부분의 경우, 서로 교환 가능합니다.

파이프의 아이디어는 데이터셋을 가져와서 무언가를 하는 것입니다. 우리는 이전 예시에서 이것을 사용했습니다. 다음은 head()에 파이프하여 데이터셋의 처음 6줄을 살펴보는 또 다른 예시입니다. head()는 이 예시에서 명시적으로 인수를 취하지 않는다는 점에 유의하십시오. 파이프가 암시적으로 표시할 데이터를 알려주기 때문에 어떤 데이터를 표시할지 알고 있습니다.

get_auspol("all") |> # GitHub에서 데이터 가져오기
  head()
# A tibble: 6 × 20
  uniqueID   surname allOtherNames          firstName commonName displayName    
  <chr>      <chr>   <chr>                  <chr>     <chr>      <chr>          
1 Abbott1859 Abbott  Richard Hartley Smith  Richard   <NA>       Abbott, Richard
2 Abbott1869 Abbott  Percy Phipps           Percy     <NA>       Abbott, Percy  
3 Abbott1877 Abbott  Macartney              Macartney Mac        Abbott, Mac    
4 Abbott1886 Abbott  Charles Lydiard Aubrey Charles   Aubrey     Abbott, Aubrey 
5 Abbott1891 Abbott  Joseph Palmer          Joseph    <NA>       Abbott, Joseph 
6 Abbott1957 Abbott  Anthony John           Anthony   Tony       Abbott, Tony   
# ℹ 14 more variables: earlierOrLaterNames <chr>, title <chr>, gender <chr>,
#   birthDate <date>, birthYear <dbl>, birthPlace <chr>, deathDate <date>,
#   member <dbl>, senator <dbl>, wasPrimeMinister <dbl>, wikidataID <chr>,
#   wikipedia <chr>, adb <chr>, comments <chr>

R 스크립트를 “my_first_r_script.R”로 저장할 수 있습니다(“파일” \(\rightarrow\) “다른 이름으로 저장”). 이 시점에서 작업 공간은 Figure A.2 와 같이 보일 것입니다.

Figure A.2: R 스크립트 실행 후

각 Posit Cloud 작업 공간은 본질적으로 새로운 컴퓨터라는 점을 알아두십시오. 이 때문에 각 작업 공간에서 사용하려는 모든 패키지를 설치해야 합니다. 예를 들어, tidyverse를 사용하기 전에 install.packages("tidyverse")로 설치해야 합니다. 이는 자신의 컴퓨터를 사용하는 것과 대조됩니다.

Posit Cloud에 대한 몇 가지 마지막 참고 사항:

  1. 호주 정치인 예시에서 우리는 GitHub 웹사이트에서 R 패키지를 사용하여 데이터를 가져왔지만, 다양한 방법으로 로컬 컴퓨터에서 작업 공간으로 데이터를 가져올 수 있습니다. 한 가지 방법은 “파일” 패널의 “업로드” 버튼을 사용하는 것입니다. 다른 방법은 tidyverse(Wickham et al. 2019)의 일부인 readr(Wickham, Hester, and Bryan 2022)를 사용하는 것입니다.
  2. Posit Cloud는 어느 정도의 협업을 허용합니다. 예를 들어, 다른 사람에게 자신이 만든 작업 공간에 대한 접근 권한을 부여하고 동시에 동일한 작업 공간에 있을 수도 있습니다. 이는 협업에 유용할 수 있습니다.
  3. Posit Cloud에는 다양한 약점이 있습니다. 특히 RAM 제한이 있습니다. 또한, 다른 웹 애플리케이션과 마찬가지로 때때로 문제가 발생하거나 중단될 수 있습니다.

A.4 dplyr 동사

데이터 조작 측면에서 우리가 사용할 핵심 패키지 중 하나는 tidyverse(Wickham et al. 2019)입니다. tidyverse는 실제로 패키지 모음이며, 이는 tidyverse를 설치할 때 실제로 많은 다른 패키지를 설치한다는 것을 의미합니다. 데이터 조작 측면에서 tidyverse의 핵심 패키지는 dplyr(Wickham et al. 2022)입니다.

정기적으로 사용되는 다섯 가지 dplyr 함수가 있으며, 이제 각각을 살펴보겠습니다. 이들은 일반적으로 dplyr 동사라고 불립니다.

  1. select()
  2. filter()
  3. arrange()
  4. mutate()
  5. summarise() 또는 summarize()

또한 밀접하게 관련된 .bycount()도 다룰 것입니다.

tidyverse를 이미 설치했으므로 로드하기만 하면 됩니다.


library(tidyverse)

그리고 AustralianPoliticians 패키지(Alexander and Hodgetts 2021)의 호주 정치인에 대한 데이터를 다시 사용하는 것으로 시작하겠습니다.

library(AustralianPoliticians)

australian_politicians <-
  get_auspol("all")

head(australian_politicians)
# A tibble: 6 × 20
  uniqueID   surname allOtherNames          firstName commonName displayName    
  <chr>      <chr>   <chr>                  <chr>     <chr>      <chr>          
1 Abbott1859 Abbott  Richard Hartley Smith  Richard   <NA>       Abbott, Richard
2 Abbott1869 Abbott  Percy Phipps           Percy     <NA>       Abbott, Percy  
3 Abbott1877 Abbott  Macartney              Macartney Mac        Abbott, Mac    
4 Abbott1886 Abbott  Charles Lydiard Aubrey Charles   Aubrey     Abbott, Aubrey 
5 Abbott1891 Abbott  Joseph Palmer          Joseph    <NA>       Abbott, Joseph 
6 Abbott1957 Abbott  Anthony John           Anthony   Tony       Abbott, Tony   
# ℹ 14 more variables: earlierOrLaterNames <chr>, title <chr>, gender <chr>,
#   birthDate <date>, birthYear <dbl>, birthPlace <chr>, deathDate <date>,
#   member <dbl>, senator <dbl>, wasPrimeMinister <dbl>, wikidataID <chr>,
#   wikipedia <chr>, adb <chr>, comments <chr>

A.4.1 select()

데이터셋의 특정 열을 선택하려면 select()를 사용합니다. 예를 들어, “firstName” 열을 선택하고 싶을 수 있습니다.

australian_politicians |>
  select(firstName)
# A tibble: 1,783 × 1
   firstName
   <chr>    
 1 Richard  
 2 Percy    
 3 Macartney
 4 Charles  
 5 Joseph   
 6 Anthony  
 7 John     
 8 Eric     
 9 Judith   
10 Dick     
# ℹ 1,773 more rows

R에는 작업을 수행하는 여러 가지 방법이 있습니다. 때로는 동일한 작업을 수행하는 다른 방법이 있고, 때로는 거의 동일한 작업을 수행하는 다른 방법이 있습니다. 예를 들어, 데이터셋의 특정 열을 선택하는 또 다른 방법은 “추출” 연산자 $를 사용하는 것입니다. 이것은 select()와 달리 base에서 온 것입니다.

australian_politicians$firstName |>
  head()
[1] "Richard"   "Percy"     "Macartney" "Charles"   "Joseph"    "Anthony"  

두 가지는 비슷해 보입니다. 둘 다 “firstName” 열을 선택하지만, 반환하는 것의 클래스가 다릅니다. select()는 티블을 반환하고 $는 벡터를 반환합니다. 완전성을 위해 select()pull()을 결합하면 추출 연산자를 사용한 것과 동일한 클래스의 출력, 즉 벡터를 얻습니다.

australian_politicians |>
  select(firstName) |>
  pull() |>
  head()
[1] "Richard"   "Percy"     "Macartney" "Charles"   "Joseph"    "Anthony"  

열 이름을 부정하여 select()를 사용하여 열을 제거할 수도 있습니다.

australian_politicians |>
  select(-firstName)
# A tibble: 1,783 × 19
   uniqueID   surname allOtherNames   commonName displayName earlierOrLaterNames
   <chr>      <chr>   <chr>           <chr>      <chr>       <chr>              
 1 Abbott1859 Abbott  Richard Hartle… <NA>       Abbott, Ri… <NA>               
 2 Abbott1869 Abbott  Percy Phipps    <NA>       Abbott, Pe… <NA>               
 3 Abbott1877 Abbott  Macartney       Mac        Abbott, Mac <NA>               
 4 Abbott1886 Abbott  Charles Lydiar… Aubrey     Abbott, Au… <NA>               
 5 Abbott1891 Abbott  Joseph Palmer   <NA>       Abbott, Jo… <NA>               
 6 Abbott1957 Abbott  Anthony John    Tony       Abbott, To… <NA>               
 7 Abel1939   Abel    John Arthur     <NA>       Abel, John  <NA>               
 8 Abetz1958  Abetz   Eric            <NA>       Abetz, Eric <NA>               
 9 Adams1943  Adams   Judith Anne     <NA>       Adams, Jud… nee Bird           
10 Adams1951  Adams   Dick Godfrey H… <NA>       Adams, Dick <NA>               
# ℹ 1,773 more rows
# ℹ 13 more variables: title <chr>, gender <chr>, birthDate <date>,
#   birthYear <dbl>, birthPlace <chr>, deathDate <date>, member <dbl>,
#   senator <dbl>, wasPrimeMinister <dbl>, wikidataID <chr>, wikipedia <chr>,
#   adb <chr>, comments <chr>

마지막으로, 조건을 기반으로 select()할 수 있습니다. 예를 들어, “birth”로 시작하는 모든 열을 select()할 수 있습니다.

australian_politicians |>
  select(starts_with("birth"))
# A tibble: 1,783 × 3
   birthDate  birthYear birthPlace  
   <date>         <dbl> <chr>       
 1 NA              1859 Bendigo     
 2 1869-05-14        NA Hobart      
 3 1877-07-03        NA Murrurundi  
 4 1886-01-04        NA St Leonards 
 5 1891-10-18        NA North Sydney
 6 1957-11-04        NA London      
 7 1939-06-25        NA Sydney      
 8 1958-01-25        NA Stuttgart   
 9 1943-04-11        NA Picton      
10 1951-04-29        NA Launceston  
# ℹ 1,773 more rows

starts_with(), ends_with(), contains()를 포함한 다양한 유사한 “선택 도우미”가 있습니다. 이에 대한 자세한 정보는 ?select()를 실행하여 접근할 수 있는 select()의 도움말 페이지에서 확인할 수 있습니다.

이 시점에서 select()를 사용하여 데이터셋의 너비를 줄일 것입니다.

australian_politicians <-
  australian_politicians |>
  select(
    uniqueID,
    surname,
    firstName,
    gender,
    birthDate,
    birthYear,
    deathDate,
    member,
    senator,
    wasPrimeMinister
  )

australian_politicians
# A tibble: 1,783 × 10
   uniqueID   surname firstName gender birthDate  birthYear deathDate  member
   <chr>      <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
 1 Abbott1859 Abbott  Richard   male   NA              1859 1940-02-28      0
 2 Abbott1869 Abbott  Percy     male   1869-05-14        NA 1940-09-09      1
 3 Abbott1877 Abbott  Macartney male   1877-07-03        NA 1960-12-30      0
 4 Abbott1886 Abbott  Charles   male   1886-01-04        NA 1975-04-30      1
 5 Abbott1891 Abbott  Joseph    male   1891-10-18        NA 1965-05-07      1
 6 Abbott1957 Abbott  Anthony   male   1957-11-04        NA NA              1
 7 Abel1939   Abel    John      male   1939-06-25        NA NA              1
 8 Abetz1958  Abetz   Eric      male   1958-01-25        NA NA              0
 9 Adams1943  Adams   Judith    female 1943-04-11        NA 2012-03-31      0
10 Adams1951  Adams   Dick      male   1951-04-29        NA NA              1
# ℹ 1,773 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

R을 처음 사용하는 사람들을 혼란스럽게 하는 한 가지는 출력이 객체에 할당되지 않으면 “저장”되지 않는다는 것입니다. 예를 들어, 여기서는 첫 줄이 australian_politicians <- australian_politicians |>이고, 그 다음 select()가 사용됩니다. australian_politicians |>와 비교됩니다. 이렇게 하면 select()에 의해 발생한 변경 사항이 객체에 적용되므로, 코드의 나중에 해당 수정된 버전이 사용됩니다.

A.4.2 filter()

데이터셋의 특정 행을 선택하려면 filter()를 사용합니다. 예를 들어, 총리가 된 정치인에게만 관심이 있을 수 있습니다.

australian_politicians |>
  filter(wasPrimeMinister == 1)
# A tibble: 30 × 10
   uniqueID    surname firstName gender birthDate  birthYear deathDate  member
   <chr>       <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
 1 Abbott1957  Abbott  Anthony   male   1957-11-04        NA NA              1
 2 Barton1849  Barton  Edmund    male   1849-01-18        NA 1920-01-07      1
 3 Bruce1883   Bruce   Stanley   male   1883-04-15        NA 1967-08-25      1
 4 Chifley1885 Chifley Joseph    male   1885-09-22        NA 1951-06-13      1
 5 Cook1860    Cook    Joseph    male   1860-12-07        NA 1947-07-30      1
 6 Curtin1885  Curtin  John      male   1885-01-08        NA 1945-07-05      1
 7 Deakin1856  Deakin  Alfred    male   1856-08-03        NA 1919-10-07      1
 8 Fadden1894  Fadden  Arthur    male   1894-04-13        NA 1973-04-21      1
 9 Fisher1862  Fisher  Andrew    male   1862-08-29        NA 1928-10-22      1
10 Forde1890   Forde   Francis   male   1890-07-18        NA 1983-01-28      1
# ℹ 20 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

filter()에 두 가지 조건을 줄 수도 있습니다. 예를 들어, 총리가 되었고 이름이 조셉인 정치인을 “and” 연산자 &를 사용하여 찾을 수 있습니다.

australian_politicians |>
  filter(wasPrimeMinister == 1 & firstName == "Joseph")
# A tibble: 3 × 10
  uniqueID    surname firstName gender birthDate  birthYear deathDate  member
  <chr>       <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
1 Chifley1885 Chifley Joseph    male   1885-09-22        NA 1951-06-13      1
2 Cook1860    Cook    Joseph    male   1860-12-07        NA 1947-07-30      1
3 Lyons1879   Lyons   Joseph    male   1879-09-15        NA 1939-04-07      1
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

앰퍼샌드 대신 쉼표를 사용해도 동일한 결과를 얻습니다.

australian_politicians |>
  filter(wasPrimeMinister == 1, firstName == "Joseph")
# A tibble: 3 × 10
  uniqueID    surname firstName gender birthDate  birthYear deathDate  member
  <chr>       <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
1 Chifley1885 Chifley Joseph    male   1885-09-22        NA 1951-06-13      1
2 Cook1860    Cook    Joseph    male   1860-12-07        NA 1947-07-30      1
3 Lyons1879   Lyons   Joseph    male   1879-09-15        NA 1939-04-07      1
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

마찬가지로, “or” 연산자 |를 사용하여 마일스 또는 루스라는 이름의 정치인을 찾을 수 있습니다.

australian_politicians |>
  filter(firstName == "Myles" | firstName == "Ruth")
# A tibble: 3 × 10
  uniqueID     surname  firstName gender birthDate  birthYear deathDate  member
  <chr>        <chr>    <chr>     <chr>  <date>         <dbl> <date>      <dbl>
1 Coleman1931  Coleman  Ruth      female 1931-09-27        NA 2008-03-27      0
2 Ferricks1875 Ferricks Myles     male   1875-11-12        NA 1932-08-20      0
3 Webber1965   Webber   Ruth      female 1965-03-24        NA NA              0
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

결과를 파이프할 수도 있습니다. 예를 들어, filter()에서 select()로 파이프할 수 있습니다.

australian_politicians |>
  filter(firstName == "Ruth" | firstName == "Myles") |>
  select(firstName, surname)
# A tibble: 3 × 2
  firstName surname 
  <chr>     <chr>   
1 Ruth      Coleman 
2 Myles     Ferricks
3 Ruth      Webber  

관심 있는 특정 행 번호를 알고 있다면 해당 행만 filter()할 수 있습니다. 예를 들어, 853번 행에 관심이 있다고 가정해 봅시다.

australian_politicians |>
  filter(row_number() == 853)
# A tibble: 1 × 10
  uniqueID     surname  firstName gender birthDate  birthYear deathDate member
  <chr>        <chr>    <chr>     <chr>  <date>         <dbl> <date>     <dbl>
1 Jakobsen1947 Jakobsen Carolyn   female 1947-09-11        NA NA             1
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

이를 수행하는 전용 함수도 있습니다. 즉, slice()입니다.

australian_politicians |>
  slice(853)
# A tibble: 1 × 10
  uniqueID     surname  firstName gender birthDate  birthYear deathDate member
  <chr>        <chr>    <chr>     <chr>  <date>         <dbl> <date>     <dbl>
1 Jakobsen1947 Jakobsen Carolyn   female 1947-09-11        NA NA             1
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

이것은 다소 난해해 보일 수 있지만, 부정을 사용하여 특정 행을 제거하거나 특정 행을 복제하려는 경우 특히 유용합니다. 예를 들어, 첫 번째 행을 제거할 수 있습니다.

australian_politicians |>
  slice(-1)
# A tibble: 1,782 × 10
   uniqueID    surname firstName gender birthDate  birthYear deathDate  member
   <chr>       <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
 1 Abbott1869  Abbott  Percy     male   1869-05-14        NA 1940-09-09      1
 2 Abbott1877  Abbott  Macartney male   1877-07-03        NA 1960-12-30      0
 3 Abbott1886  Abbott  Charles   male   1886-01-04        NA 1975-04-30      1
 4 Abbott1891  Abbott  Joseph    male   1891-10-18        NA 1965-05-07      1
 5 Abbott1957  Abbott  Anthony   male   1957-11-04        NA NA              1
 6 Abel1939    Abel    John      male   1939-06-25        NA NA              1
 7 Abetz1958   Abetz   Eric      male   1958-01-25        NA NA              0
 8 Adams1943   Adams   Judith    female 1943-04-11        NA 2012-03-31      0
 9 Adams1951   Adams   Dick      male   1951-04-29        NA NA              1
10 Adamson1857 Adamson John      male   1857-02-18        NA 1922-05-02      0
# ℹ 1,772 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

또한, 예를 들어, 처음 세 행만 유지할 수도 있습니다.

australian_politicians |>
  slice(1:3)
# A tibble: 3 × 10
  uniqueID   surname firstName gender birthDate  birthYear deathDate  member
  <chr>      <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
1 Abbott1859 Abbott  Richard   male   NA              1859 1940-02-28      0
2 Abbott1869 Abbott  Percy     male   1869-05-14        NA 1940-09-09      1
3 Abbott1877 Abbott  Macartney male   1877-07-03        NA 1960-12-30      0
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

마지막으로, 처음 두 행을 복제할 수 있으며, 이는 현재 그룹 크기를 제공하는 n()을 활용합니다.

australian_politicians |>
  slice(1:2, 1:n())
# A tibble: 1,785 × 10
   uniqueID   surname firstName gender birthDate  birthYear deathDate  member
   <chr>      <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
 1 Abbott1859 Abbott  Richard   male   NA              1859 1940-02-28      0
 2 Abbott1869 Abbott  Percy     male   1869-05-14        NA 1940-09-09      1
 3 Abbott1859 Abbott  Richard   male   NA              1859 1940-02-28      0
 4 Abbott1869 Abbott  Percy     male   1869-05-14        NA 1940-09-09      1
 5 Abbott1877 Abbott  Macartney male   1877-07-03        NA 1960-12-30      0
 6 Abbott1886 Abbott  Charles   male   1886-01-04        NA 1975-04-30      1
 7 Abbott1891 Abbott  Joseph    male   1891-10-18        NA 1965-05-07      1
 8 Abbott1957 Abbott  Anthony   male   1957-11-04        NA NA              1
 9 Abel1939   Abel    John      male   1939-06-25        NA NA              1
10 Abetz1958  Abetz   Eric      male   1958-01-25        NA NA              0
# ℹ 1,775 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

A.4.3 arrange()

특정 열의 값을 기반으로 데이터셋의 순서를 변경하려면 arrange()를 사용합니다. 예를 들어, 정치인들을 생년월일순으로 정렬할 수 있습니다.

australian_politicians |>
  arrange(birthYear)
# A tibble: 1,783 × 10
   uniqueID    surname firstName gender birthDate birthYear deathDate  member
   <chr>       <chr>   <chr>     <chr>  <date>        <dbl> <date>      <dbl>
 1 Edwards1842 Edwards Richard   male   NA             1842 1915-10-29      1
 2 Sawers1844  Sawers  William   male   NA             1844 1916-05-19      1
 3 Barker1846  Barker  Stephen   male   NA             1846 1924-06-21      0
 4 Corser1852  Corser  Edward    male   NA             1852 1928-07-31      1
 5 Lee1856     Lee     Henry     male   NA             1856 1927-08-12      1
 6 Grant1857   Grant   John      male   NA             1857 1928-05-19      0
 7 Abbott1859  Abbott  Richard   male   NA             1859 1940-02-28      0
 8 Palmer1859  Palmer  Albert    male   NA             1859 1919-08-14      1
 9 Riley1859   Riley   Edward    male   NA             1859 1943-07-21      1
10 Kennedy1860 Kennedy Thomas    male   NA             1860 1929-02-16      1
# ℹ 1,773 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

desc()를 사용하여 arrange()를 수정하여 오름차순에서 내림차순으로 변경할 수 있습니다.

australian_politicians |>
  arrange(desc(birthYear))
# A tibble: 1,783 × 10
   uniqueID      surname firstName gender birthDate  birthYear deathDate  member
   <chr>         <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
 1 McBain1982    McBain  Kristy    female 1982-09-29      1982 NA              1
 2 Cox1977       Cox     Dorinda   female NA              1977 NA              0
 3 Thorpe1973    Thorpe  Lidia     female 1973-08-18      1973 NA              0
 4 McLachlan1966 McLach… Andrew    male   1966-01-14      1966 NA              0
 5 Wortley1959   Wortley Dana      female NA              1959 NA              0
 6 Baker1903     Baker   Francis   male   NA              1903 1939-03-28      1
 7 Clay1900      Clay    Lionel    male   NA              1900 1965-04-16      1
 8 Breen1898     Breen   John      male   NA              1898 1966-02-05      1
 9 Clasby1891    Clasby  John      male   NA              1891 1932-01-15      1
10 Gander1888    Gander  Joseph    male   NA              1888 1954-11-22      1
# ℹ 1,773 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

빼기 기호를 사용해도 동일한 결과를 얻을 수 있습니다.

australian_politicians |>
  arrange(-birthYear)
# A tibble: 1,783 × 10
   uniqueID      surname firstName gender birthDate  birthYear deathDate  member
   <chr>         <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
 1 McBain1982    McBain  Kristy    female 1982-09-29      1982 NA              1
 2 Cox1977       Cox     Dorinda   female NA              1977 NA              0
 3 Thorpe1973    Thorpe  Lidia     female 1973-08-18      1973 NA              0
 4 McLachlan1966 McLach… Andrew    male   1966-01-14      1966 NA              0
 5 Wortley1959   Wortley Dana      female NA              1959 NA              0
 6 Baker1903     Baker   Francis   male   NA              1903 1939-03-28      1
 7 Clay1900      Clay    Lionel    male   NA              1900 1965-04-16      1
 8 Breen1898     Breen   John      male   NA              1898 1966-02-05      1
 9 Clasby1891    Clasby  John      male   NA              1891 1932-01-15      1
10 Gander1888    Gander  Joseph    male   NA              1888 1954-11-22      1
# ℹ 1,773 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

그리고 하나 이상의 열을 기준으로 정렬할 수도 있습니다. 예를 들어, 두 정치인이 동일한 이름을 가지고 있다면, 생년월일을 기준으로도 정렬할 수 있습니다.

australian_politicians |>
  arrange(firstName, birthYear)
# A tibble: 1,783 × 10
   uniqueID      surname firstName gender birthDate  birthYear deathDate  member
   <chr>         <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
 1 Blain1894     Blain   Adair     male   1894-11-21        NA 1983-04-28      1
 2 Armstrong1909 Armstr… Adam      male   1909-07-01        NA 1982-02-22      1
 3 Bandt1972     Bandt   Adam      male   1972-03-11        NA NA              1
 4 Dein1889      Dein    Adam      male   1889-03-04        NA 1969-05-09      1
 5 Ridgeway1962  Ridgew… Aden      male   1962-09-18        NA NA              0
 6 Bennett1933   Bennett Adrian    male   1933-01-21        NA 2006-05-09      1
 7 Gibson1935    Gibson  Adrian    male   1935-11-03        NA 2015-04-30      1
 8 Wynne1850     Wynne   Agar      male   1850-01-15        NA 1934-05-12      1
 9 Robertson1882 Robert… Agnes     female 1882-07-31        NA 1968-01-29      0
10 Bird1906      Bird    Alan      male   1906-09-28        NA 1962-07-21      1
# ℹ 1,773 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

두 개의 arrange() 인스턴스 사이에 파이프를 사용하여 동일한 결과를 얻을 수 있습니다.

australian_politicians |>
  arrange(birthYear) |>
  arrange(firstName)
# A tibble: 1,783 × 10
   uniqueID      surname firstName gender birthDate  birthYear deathDate  member
   <chr>         <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
 1 Blain1894     Blain   Adair     male   1894-11-21        NA 1983-04-28      1
 2 Armstrong1909 Armstr… Adam      male   1909-07-01        NA 1982-02-22      1
 3 Bandt1972     Bandt   Adam      male   1972-03-11        NA NA              1
 4 Dein1889      Dein    Adam      male   1889-03-04        NA 1969-05-09      1
 5 Ridgeway1962  Ridgew… Aden      male   1962-09-18        NA NA              0
 6 Bennett1933   Bennett Adrian    male   1933-01-21        NA 2006-05-09      1
 7 Gibson1935    Gibson  Adrian    male   1935-11-03        NA 2015-04-30      1
 8 Wynne1850     Wynne   Agar      male   1850-01-15        NA 1934-05-12      1
 9 Robertson1882 Robert… Agnes     female 1882-07-31        NA 1968-01-29      0
10 Bird1906      Bird    Alan      male   1906-09-28        NA 1962-07-21      1
# ℹ 1,773 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

arrange()를 사용할 때는 우선순위를 명확히 해야 합니다. 예를 들어, 생년월일 다음에 이름을 기준으로 변경하면 다른 정렬이 됩니다.

australian_politicians |>
  arrange(birthYear, firstName)
# A tibble: 1,783 × 10
   uniqueID    surname firstName gender birthDate birthYear deathDate  member
   <chr>       <chr>   <chr>     <chr>  <date>        <dbl> <date>      <dbl>
 1 Edwards1842 Edwards Richard   male   NA             1842 1915-10-29      1
 2 Sawers1844  Sawers  William   male   NA             1844 1916-05-19      1
 3 Barker1846  Barker  Stephen   male   NA             1846 1924-06-21      0
 4 Corser1852  Corser  Edward    male   NA             1852 1928-07-31      1
 5 Lee1856     Lee     Henry     male   NA             1856 1927-08-12      1
 6 Grant1857   Grant   John      male   NA             1857 1928-05-19      0
 7 Palmer1859  Palmer  Albert    male   NA             1859 1919-08-14      1
 8 Riley1859   Riley   Edward    male   NA             1859 1943-07-21      1
 9 Abbott1859  Abbott  Richard   male   NA             1859 1940-02-28      0
10 Kennedy1860 Kennedy Thomas    male   NA             1860 1929-02-16      1
# ℹ 1,773 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

다양한 열을 기준으로 정렬하는 좋은 방법은 across()를 사용하는 것입니다. 이는 select()와 관련하여 언급된 starts_with()와 같은 “선택 도우미”를 사용할 수 있게 해줍니다.

australian_politicians |>
  arrange(across(c(firstName, birthYear)))
# A tibble: 1,783 × 10
   uniqueID      surname firstName gender birthDate  birthYear deathDate  member
   <chr>         <chr>   <chr>     <chr>  <date>         <dbl> <date>      <dbl>
 1 Blain1894     Blain   Adair     male   1894-11-21        NA 1983-04-28      1
 2 Armstrong1909 Armstr… Adam      male   1909-07-01        NA 1982-02-22      1
 3 Bandt1972     Bandt   Adam      male   1972-03-11        NA NA              1
 4 Dein1889      Dein    Adam      male   1889-03-04        NA 1969-05-09      1
 5 Ridgeway1962  Ridgew… Aden      male   1962-09-18        NA NA              0
 6 Bennett1933   Bennett Adrian    male   1933-01-21        NA 2006-05-09      1
 7 Gibson1935    Gibson  Adrian    male   1935-11-03        NA 2015-04-30      1
 8 Wynne1850     Wynne   Agar      male   1850-01-15        NA 1934-05-12      1
 9 Robertson1882 Robert… Agnes     female 1882-07-31        NA 1968-01-29      0
10 Bird1906      Bird    Alan      male   1906-09-28        NA 1962-07-21      1
# ℹ 1,773 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>
australian_politicians |>
  arrange(across(starts_with("birth")))
# A tibble: 1,783 × 10
   uniqueID     surname  firstName gender birthDate  birthYear deathDate  member
   <chr>        <chr>    <chr>     <chr>  <date>         <dbl> <date>      <dbl>
 1 Braddon1829  Braddon  Edward    male   1829-06-11        NA 1904-02-02      1
 2 Ferguson1830 Ferguson John      male   1830-03-15        NA 1906-03-30      0
 3 Zeal1830     Zeal     William   male   1830-12-05        NA 1912-03-11      0
 4 Fraser1832   Fraser   Simon     male   1832-08-21        NA 1919-07-30      0
 5 Groom1833    Groom    William   male   1833-03-09        NA 1901-08-08      1
 6 Sargood1834  Sargood  Frederick male   1834-05-30        NA 1903-01-02      0
 7 Fysh1835     Fysh     Philip    male   1835-03-01        NA 1919-12-20      1
 8 Playford1837 Playford Thomas    male   1837-11-26        NA 1915-04-19      0
 9 Solomon1839  Solomon  Elias     male   1839-09-02        NA 1909-05-23      1
10 McLean1840   McLean   Allan     male   1840-02-03        NA 1911-07-13      1
# ℹ 1,773 more rows
# ℹ 2 more variables: senator <dbl>, wasPrimeMinister <dbl>

A.4.4 mutate()

새 열을 만들고 싶을 때 mutate()를 사용합니다. 예를 들어, 어떤 사람이 의원이자 상원 의원인 경우 1이고 그렇지 않으면 0인 새 열을 만들고 싶을 수 있습니다. 즉, 새 열은 상원과 하원 모두에서 봉사한 정치인을 나타냅니다.

australian_politicians <-
  australian_politicians |>
  mutate(was_both = if_else(member == 1 & senator == 1, 1, 0))

australian_politicians |>
  select(member, senator, was_both)
# A tibble: 1,783 × 3
   member senator was_both
    <dbl>   <dbl>    <dbl>
 1      0       1        0
 2      1       1        1
 3      0       1        0
 4      1       0        0
 5      1       0        0
 6      1       0        0
 7      1       0        0
 8      0       1        0
 9      0       1        0
10      1       0        0
# ℹ 1,773 more rows

덧셈과 뺄셈과 같은 수학을 mutate()와 함께 사용할 수 있습니다. 예를 들어, 정치인들의 2022년 나이(또는 나이였을 것)를 계산할 수 있습니다.

library(lubridate)

australian_politicians <-
  australian_politicians |>
  mutate(age = 2022 - year(birthDate))

australian_politicians |>
  select(uniqueID, age)
# A tibble: 1,783 × 2
   uniqueID     age
   <chr>      <dbl>
 1 Abbott1859    NA
 2 Abbott1869   153
 3 Abbott1877   145
 4 Abbott1886   136
 5 Abbott1891   131
 6 Abbott1957    65
 7 Abel1939      83
 8 Abetz1958     64
 9 Adams1943     79
10 Adams1951     71
# ℹ 1,773 more rows

새 열을 구성할 때 특히 유용한 다양한 함수가 있습니다. 여기에는 자연 로그를 계산하는 log(), 값을 한 행 위로 가져오는 lead(), 값을 한 행 아래로 내리는 lag(), 그리고 열의 누적 합계를 생성하는 cumsum()이 포함됩니다.

australian_politicians |>
  select(uniqueID, age) |>
  mutate(log_age = log(age))
# A tibble: 1,783 × 3
   uniqueID     age log_age
   <chr>      <dbl>   <dbl>
 1 Abbott1859    NA   NA   
 2 Abbott1869   153    5.03
 3 Abbott1877   145    4.98
 4 Abbott1886   136    4.91
 5 Abbott1891   131    4.88
 6 Abbott1957    65    4.17
 7 Abel1939      83    4.42
 8 Abetz1958     64    4.16
 9 Adams1943     79    4.37
10 Adams1951     71    4.26
# ℹ 1,773 more rows
australian_politicians |>
  select(uniqueID, age) |>
  mutate(lead_age = lead(age))
# A tibble: 1,783 × 3
   uniqueID     age lead_age
   <chr>      <dbl>    <dbl>
 1 Abbott1859    NA      153
 2 Abbott1869   153      145
 3 Abbott1877   145      136
 4 Abbott1886   136      131
 5 Abbott1891   131       65
 6 Abbott1957    65       83
 7 Abel1939      83       64
 8 Abetz1958     64       79
 9 Adams1943     79       71
10 Adams1951     71      165
# ℹ 1,773 more rows
australian_politicians |>
  select(uniqueID, age) |>
  mutate(lag_age = lag(age))
# A tibble: 1,783 × 3
   uniqueID     age lag_age
   <chr>      <dbl>   <dbl>
 1 Abbott1859    NA      NA
 2 Abbott1869   153      NA
 3 Abbott1877   145     153
 4 Abbott1886   136     145
 5 Abbott1891   131     136
 6 Abbott1957    65     131
 7 Abel1939      83      65
 8 Abetz1958     64      83
 9 Adams1943     79      64
10 Adams1951     71      79
# ℹ 1,773 more rows
australian_politicians |>
  select(uniqueID, age) |>
  drop_na(age) |>
  mutate(cumulative_age = cumsum(age))
# A tibble: 1,718 × 3
   uniqueID      age cumulative_age
   <chr>       <dbl>          <dbl>
 1 Abbott1869    153            153
 2 Abbott1877    145            298
 3 Abbott1886    136            434
 4 Abbott1891    131            565
 5 Abbott1957     65            630
 6 Abel1939       83            713
 7 Abetz1958      64            777
 8 Adams1943      79            856
 9 Adams1951      71            927
10 Adamson1857   165           1092
# ℹ 1,708 more rows

이전 예시에서와 마찬가지로 mutate()across()와 함께 사용할 수도 있습니다. 여기에는 선택 도우미의 잠재적 사용이 포함됩니다. 예를 들어, 이름과 성의 문자 수를 동시에 셀 수 있습니다.

australian_politicians |>
  mutate(across(c(firstName, surname), str_count)) |>
  select(uniqueID, firstName, surname)
# A tibble: 1,783 × 3
   uniqueID   firstName surname
   <chr>          <int>   <int>
 1 Abbott1859         7       6
 2 Abbott1869         5       6
 3 Abbott1877         9       6
 4 Abbott1886         7       6
 5 Abbott1891         6       6
 6 Abbott1957         7       6
 7 Abel1939           4       4
 8 Abetz1958          4       5
 9 Adams1943          6       5
10 Adams1951          4       5
# ℹ 1,773 more rows

마지막으로, 두 개 이상의 조건문(첫 번째 mutate() 예시의 if_else()와 대조적으로)을 기반으로 새 열을 만들어야 할 때 case_when()을 사용합니다. 예를 들어, 몇 년이 있고 그것들을 10년 단위로 그룹화하고 싶을 수 있습니다.

```{

library(lubridate)

australian_politicians |> mutate( year_of_birth = year(birthDate), decade_of_birth = case_when( year_of_birth <= 1929 ~ “1929년 이전”, year_of_birth <= 1939 ~ “1930년대”, year_of_birth <= 1949 ~ “1940년대”, year_of_birth <= 1959 ~ “1950년대”, year_of_birth <= 1969 ~ “1960년대”, year_of_birth <= 1979 ~ “1970년대”, year_of_birth <= 1989 ~ “1980년대”, year_of_birth <= 1999 ~ “1990년대”, TRUE ~ “알 수 없음 또는 오류” ) ) |> select(uniqueID, year_of_birth, decade_of_birth)


일련의 중첩된 `if_else()` 문으로 이를 달성할 수 있지만, `case_when()`이 더 명확합니다. 사례는 순서대로 평가되며, 일치하는 것이 있으면 `case_when()`은 나머지 사례로 계속 진행하지 않습니다. 코드가 그곳에 도달할 경우 우리가 알고 싶을 수 있는 잠재적인 문제를 알리는 포괄적인 것을 끝에 두는 것이 유용할 수 있습니다.

### `summarise()`

새롭고 압축된 요약 변수를 만들고 싶을 때 `summarise()`를 사용합니다. 예를 들어, 어떤 열의 최소값, 평균값, 최대값을 알고 싶을 수 있습니다.


::: {.cell}

```{.r .cell-code}
australian_politicians |>
  summarise(
    youngest = min(age, na.rm = TRUE),
    oldest = max(age, na.rm = TRUE),
    average = mean(age, na.rm = TRUE)
  )
# A tibble: 1 × 3
  youngest oldest average
     <dbl>  <dbl>   <dbl>
1       28    193    101.

:::

여담으로, summarise()summarize()는 동일하며 둘 중 하나를 사용할 수 있습니다. 이 책에서는 summarise()를 사용합니다.

australian_politicians |>
  summarize(
    youngest = min(age, na.rm = TRUE),
    oldest = max(age, na.rm = TRUE),
    average = mean(age, na.rm = TRUE)
  )
# A tibble: 1 × 3
  youngest oldest average
     <dbl>  <dbl>   <dbl>
1       28    193    101.

기본적으로 summarise()는 전체 데이터셋에 대해 한 행의 출력을 제공합니다. 예를 들어, 이전 예시에서 우리는 모든 정치인에 대한 최연소, 최고령 및 평균을 찾았습니다. 그러나 함수 내에서 .by를 사용하여 데이터셋에 더 많은 그룹을 만들 수 있습니다. 그룹을 기반으로 많은 함수를 사용할 수 있지만, summarise() 함수는 .by와 함께 특히 강력합니다. 예를 들어, 성별로 그룹화한 다음 연령 기반 요약 통계를 얻을 수 있습니다.

australian_politicians |>
  summarise(
    youngest = min(age, na.rm = TRUE),
    oldest = max(age, na.rm = TRUE),
    average = mean(age, na.rm = TRUE),
    .by = gender
  )
# A tibble: 2 × 4
  gender youngest oldest average
  <chr>     <dbl>  <dbl>   <dbl>
1 male         28    193   106. 
2 female       32    140    66.0

마찬가지로, 성별별 사망 시 최연소, 최고령 및 평균 연령을 살펴볼 수 있습니다.

australian_politicians |>
  mutate(days_lived = deathDate - birthDate) |>
  drop_na(days_lived) |>
  summarise(
    min_days = min(days_lived),
    mean_days = mean(days_lived) |> round(),
    max_days = max(days_lived),
    .by = gender
  )
# A tibble: 2 × 4
  gender min_days   mean_days  max_days  
  <chr>  <drtn>     <drtn>     <drtn>    
1 male   12380 days 27376 days 36416 days
2 female 14856 days 28857 days 35560 days

따라서 여성 의원들이 남성 의원들보다 평균적으로 약간 더 오래 살았다는 것을 알 수 있습니다.

하나 이상의 그룹을 기준으로 .by를 사용할 수 있습니다. 예를 들어, 성별 및 하원 또는 상원 의원 여부에 따라 평균 생존 일수를 살펴볼 수 있습니다.

australian_politicians |>
  mutate(days_lived = deathDate - birthDate) |>
  drop_na(days_lived) |>
  summarise(
    min_days = min(days_lived),
    mean_days = mean(days_lived) |> round(),
    max_days = max(days_lived),
    .by = c(gender, member)
  )
# A tibble: 4 × 5
  gender member min_days   mean_days  max_days  
  <chr>   <dbl> <drtn>     <drtn>     <drtn>    
1 male        1 12380 days 27496 days 36328 days
2 male        0 13619 days 27133 days 36416 days
3 female      0 21746 days 29517 days 35560 days
4 female      1 14856 days 27538 days 33442 days

count()를 사용하여 그룹별 개수를 생성할 수 있습니다. 예를 들어, 성별별 정치인 수입니다.

australian_politicians |>
  count(gender)
# A tibble: 2 × 2
  gender     n
  <chr>  <int>
1 female   240
2 male    1543

count() 외에도 비율을 계산할 수 있습니다.

australian_politicians |>
  count(gender) |>
  mutate(proportion = n / (sum(n)))
# A tibble: 2 × 3
  gender     n proportion
  <chr>  <int>      <dbl>
1 female   240      0.135
2 male    1543      0.865

count()를 사용하는 것은 summarise() 내에서 n()와 함께 .by를 사용하는 것과 본질적으로 동일하며, 그렇게 하면 동일한 결과를 얻습니다.

australian_politicians |>
  summarise(n = n(),
            .by = gender)
# A tibble: 2 × 2
  gender     n
  <chr>  <int>
1 male    1543
2 female   240

그리고 mutate()와 유사하게 도움이 되는 함수가 있습니다. 즉, add_count()입니다. 차이점은 숫자가 새 열에 추가된다는 것입니다.

australian_politicians |>
  add_count(gender) |>
  select(uniqueID, gender, n)
# A tibble: 1,783 × 3
   uniqueID   gender     n
   <chr>      <chr>  <int>
 1 Abbott1859 male    1543
 2 Abbott1869 male    1543
 3 Abbott1877 male    1543
 4 Abbott1886 male    1543
 5 Abbott1891 male    1543
 6 Abbott1957 male    1543
 7 Abel1939   male    1543
 8 Abetz1958  male    1543
 9 Adams1943  female   240
10 Adams1951  male    1543
# ℹ 1,773 more rows

A.5 Base R

tidyverse는 데이터 과학을 돕기 위해 비교적 최근에 설립되었지만, R은 그 훨씬 이전부터 존재했습니다. R에는 프로그래밍 및 통계학자의 핵심 요구 사항을 중심으로 구축된 많은 기능이 있습니다.

특히 다음을 다룰 것입니다.

  1. class().
  2. 데이터 시뮬레이션.
  3. function(), for(), 그리고 apply().

이러한 기능은 R에 포함되어 있으므로 추가 패키지를 설치하거나 로드할 필요가 없습니다.

A.5.1 class()

일상적인 사용에서 “a, b, c, …”는 글자이고 “1, 2, 3,…”은 숫자입니다. 그리고 우리는 글자와 숫자를 다르게 사용합니다. 예를 들어, 글자를 더하거나 빼지 않습니다. 마찬가지로, R은 다른 클래스의 내용을 구별하고 각 클래스가 가지는 속성, 즉 “어떻게 동작하고 다른 유형의 객체와 어떻게 관련되는지”를 정의하는 방법이 필요합니다(Wickham 2019).

클래스에는 계층 구조가 있습니다. 예를 들어, 우리는 “인간”이며, 그 자체로 “동물”입니다. 모든 “인간”은 “동물”이지만, 모든 “동물”이 “인간”인 것은 아닙니다. 마찬가지로, 모든 정수는 숫자이지만, 모든 숫자가 정수는 아닙니다. R에서 객체의 클래스를 class()로 확인할 수 있습니다.

a_number <- 8
class(a_number)
[1] "numeric"
a_letter <- "a"
class(a_letter)
[1] "character"

여기서 다루는 클래스는 “numeric”, “character”, “factor”, “date”, “data.frame”입니다.

가장 먼저 알아야 할 것은 개구리가 왕자가 될 수 있는 것처럼, R에서 객체의 클래스를 변경할 수 있다는 것입니다. 이를 “캐스팅”이라고 합니다. 예를 들어, “numeric”으로 시작하여 as.character()로 “character”로 변경한 다음, as.factor()로 “factor”로 변경할 수 있습니다. 그러나 as.Date()로 “date”로 만들려고 하면 오류가 발생합니다. 왜냐하면 모든 숫자가 날짜가 되는 데 필요한 속성을 가지고 있지 않기 때문입니다.

a_number <- 8
a_number
[1] 8
class(a_number)
[1] "numeric"
a_number <- as.character(a_number)
a_number
[1] "8"
class(a_number)
[1] "character"
a_number <- as.factor(a_number)
a_number
[1] 8
Levels: 8
class(a_number)
[1] "factor"

“numeric” 및 “character” 클래스와 비교하여 “factor” 클래스는 덜 익숙할 수 있습니다. “factor”는 특정 값만 취할 수 있는 범주형 데이터에 사용됩니다(Wickham 2019). 예를 들어, “factor” 변수의 일반적인 사용은 “낮” 또는 “밤”과 같은 이진 변수입니다. 또한 “18-29”, “30-44”, “45-60”, “60+”과 같은 연령대(종종 “numeric”인 연령과 대조적으로)에도 자주 사용되며, 때로는 교육 수준: “고등학교 미만”, “고등학교”, “대학”, “학부 학위”, “대학원 학위”에도 사용됩니다. levels()를 사용하여 “factor”에 허용되는 수준을 찾을 수 있습니다.

age_groups <- factor(
  c("18-29", "30-44", "45-60", "60+")
)
age_groups
[1] 18-29 30-44 45-60 60+  
Levels: 18-29 30-44 45-60 60+
class(age_groups)
[1] "factor"
levels(age_groups)
[1] "18-29" "30-44" "45-60" "60+"  

날짜는 특히 까다로운 클래스이며 빠르게 복잡해집니다. 그럼에도 불구하고, 기초적인 수준에서 as.Date()를 사용하여 “날짜”처럼 보이는 문자를 실제 “날짜”로 변환할 수 있습니다. 이를 통해 “character”로는 할 수 없는 덧셈과 뺄셈을 수행할 수 있습니다.

looks_like_a_date_but_is_not <- "2022-01-01"
looks_like_a_date_but_is_not
[1] "2022-01-01"
class(looks_like_a_date_but_is_not)
[1] "character"
is_a_date <- as.Date(looks_like_a_date_but_is_not)
is_a_date
[1] "2022-01-01"
class(is_a_date)
[1] "Date"
is_a_date + 3
[1] "2022-01-04"

여기서 다루는 마지막 클래스는 “data.frame”입니다. 이것은 스프레드시트처럼 보이며, 우리가 분석할 데이터를 저장하는 데 일반적으로 사용됩니다. 공식적으로 “데이터 프레임은 길이가 같은 벡터의 목록”입니다(Wickham 2019). 열 이름과 행 이름을 가질 것이며, colnames()rownames()를 사용하여 볼 수 있지만, 종종 행 이름은 숫자일 뿐입니다.

이를 설명하기 위해 AER(Kleiber and Zeileis 2008)의 “ResumeNames” 데이터셋을 사용합니다. 이 패키지는 CRAN의 다른 패키지와 동일한 방식으로 설치할 수 있습니다. 이 데이터셋은 이력서 내용, 특히 이력서에 사용된 이름에 대한 교차 단면 데이터와 4,870개의 가상 이력서에 대한 콜백 여부 정보를 포함합니다. 이 데이터셋은 Bertrand and Mullainathan (2004) 보스턴과 시카고의 구인 광고에 가상 이력서를 보냈는데, 이력서에 “매우 아프리카계 미국인처럼 들리는 이름” 또는 “매우 백인처럼 들리는 이름”이 할당되었는지 여부에 따라 달라졌습니다. 그들은 “백인 이름이 인터뷰 콜백을 50% 더 많이 받는다”는 상당한 차별을 발견했습니다. Hangartner, Kopp, and Siegenthaler (2021) 온라인 스위스 플랫폼을 사용하여 이를 일반화하고, 이민자와 소수 민족 그룹은 채용 담당자로부터 연락을 덜 받고, 직업이 남성 지배적인 경우 여성도 마찬가지라는 것을 발견했습니다.

install.packages("AER")
library(AER)
data("ResumeNames", package = "AER")
ResumeNames |>
  head()
     name gender ethnicity quality call    city jobs experience honors
1 Allison female      cauc     low   no chicago    2          6     no
2 Kristen female      cauc    high   no chicago    3          6     no
3 Lakisha female      afam     low   no chicago    1          6     no
4 Latonya female      afam    high   no chicago    4          6     no
5  Carrie female      cauc    high   no chicago    3         22     no
6     Jay   male      cauc     low   no chicago    2          6    yes
  volunteer military holes school email computer special college minimum equal
1        no       no   yes     no    no      yes      no     yes       5   yes
2       yes      yes    no    yes   yes      yes      no      no       5   yes
3        no       no    no    yes    no      yes      no     yes       5   yes
4       yes       no   yes     no   yes      yes     yes      no       5   yes
5        no       no    no    yes   yes      yes      no      no    some   yes
6        no       no    no     no    no       no     yes     yes    none   yes
      wanted requirements reqexp reqcomm reqeduc reqcomp reqorg
1 supervisor          yes    yes      no      no     yes     no
2 supervisor          yes    yes      no      no     yes     no
3 supervisor          yes    yes      no      no     yes     no
4 supervisor          yes    yes      no      no     yes     no
5  secretary          yes    yes      no      no     yes    yes
6      other           no     no      no      no      no     no
                          industry
1                    manufacturing
2                    manufacturing
3                    manufacturing
4                    manufacturing
5 health/education/social services
6                            trade
class(ResumeNames)
[1] "data.frame"
colnames(ResumeNames)
 [1] "name"         "gender"       "ethnicity"    "quality"      "call"        
 [6] "city"         "jobs"         "experience"   "honors"       "volunteer"   
[11] "military"     "holes"        "school"       "email"        "computer"    
[16] "special"      "college"      "minimum"      "equal"        "wanted"      
[21] "requirements" "reqexp"       "reqcomm"      "reqeduc"      "reqcomp"     
[26] "reqorg"       "industry"    

열 이름으로 지정하여 데이터 프레임을 구성하는 벡터, 즉 열의 클래스를 검사할 수 있습니다.

class(ResumeNames$name)
[1] "factor"
class(ResumeNames$jobs)
[1] "integer"

때로는 많은 열의 클래스를 한 번에 변경할 수 있는 것이 도움이 됩니다. mutate()across()를 사용하여 이를 수행할 수 있습니다.

class(ResumeNames$name)
[1] "factor"
class(ResumeNames$gender)
[1] "factor"
class(ResumeNames$ethnicity)
[1] "factor"
ResumeNames <- ResumeNames |>
  mutate(across(c(name, gender, ethnicity), as.character)) |>
  head()

class(ResumeNames$name)
[1] "character"
class(ResumeNames$gender)
[1] "character"
class(ResumeNames$ethnicity)
[1] "character"

코드가 실행되지 않는 많은 방법이 있지만, 클래스 문제가 항상 가장 먼저 확인해야 할 사항 중 하나입니다. 일반적인 문제는 “character” 또는 “numeric”이어야 한다고 생각하는 변수가 실제로는 “factor”인 경우입니다. 그리고 “numeric”이어야 한다고 생각하는 변수가 실제로는 “character”인 경우입니다.

마지막으로, 벡터의 클래스는 내용의 클래스라는 점을 지적할 가치가 있습니다. Python 및 다른 언어에서 벡터와 유사한 데이터 구조는 “list”입니다. “list”는 자체 클래스이며, “list”의 객체는 자체 클래스를 가집니다(예를 들어, ["a", 1]은 “string” 및 “int” 클래스의 항목을 가진 “list” 클래스의 객체입니다). R을 다른 언어에서 온 경우 벡터가 자체 클래스가 아니라는 것을 보는 것이 직관적이지 않을 수 있습니다.

A.5.2 데이터 시뮬레이션

데이터 시뮬레이션은 데이터로 믿을 수 있는 이야기를 하는 데 핵심적인 기술입니다. 데이터를 시뮬레이션하려면 통계 분포 및 기타 컬렉션에서 무작위로 표본을 추출할 수 있어야 합니다. R에는 이를 더 쉽게 만드는 다양한 함수가 있습니다. 즉, 정규 분포 rnorm(), 균일 분포 runif(), 포아송 분포 rpois(), 이항 분포 rbinom() 등입니다. 항목 컬렉션에서 무작위로 표본을 추출하려면 sample()을 사용할 수 있습니다.

무작위성을 다룰 때, 재현성의 필요성은 역설적으로 무작위성이 반복 가능해야 한다는 것을 중요하게 만듭니다. 즉, 다른 사람이 우리가 추출하는 무작위 숫자를 추출할 수 있어야 합니다. set.seed()를 사용하여 무작위 추출에 대한 시드를 설정하여 이를 수행합니다.

표준 정규 분포에서 관측치를 얻고 그것들을 데이터 프레임에 넣을 수 있습니다.

set.seed(853)

number_of_observations <- 5

simulated_data <-
  data.frame(
    person = c(1:number_of_observations),
    std_normal_observations = rnorm(
      n = number_of_observations,
      mean = 0,
      sd = 1
    )
  )

simulated_data
  person std_normal_observations
1      1             -0.35980342
2      2             -0.04064753
3      3             -1.78216227
4      4             -1.12242282
5      5             -1.00278400

cbind()를 사용하여 원본 데이터셋의 열과 새 데이터셋의 열을 함께 가져와 균일, 포아송, 이항 분포에서 표본을 추가할 수 있습니다.

simulated_data <-
  simulated_data |>
  cbind() |>
  data.frame(
    uniform_observations =
      runif(n = number_of_observations, min = 0, max = 10),
    poisson_observations =
      rpois(n = number_of_observations, lambda = 100),
    binomial_observations =
      rbinom(n = number_of_observations, size = 2, prob = 0.5)
  )

simulated_data
  person std_normal_observations uniform_observations poisson_observations
1      1             -0.35980342            9.6219155                   81
2      2             -0.04064753            7.2269016                   91
3      3             -1.78216227            0.8252921                   84
4      4             -1.12242282            1.0379810                  100
5      5             -1.00278400            3.0942004                   97
  binomial_observations
1                     2
2                     1
3                     1
4                     1
5                     1

마지막으로, sample()을 사용하여 각 관측치에 좋아하는 색상을 추가할 것입니다.

simulated_data <-
  data.frame(
    favorite_color = sample(
      x = c("파란색", "흰색"),
      size = number_of_observations,
      replace = TRUE
    )
  ) |>
  cbind(simulated_data)

simulated_data
  favorite_color person std_normal_observations uniform_observations
1         파란색      1             -0.35980342            9.6219155
2         파란색      2             -0.04064753            7.2269016
3         파란색      3             -1.78216227            0.8252921
4           흰색      4             -1.12242282            1.0379810
5         파란색      5             -1.00278400            3.0942004
  poisson_observations binomial_observations
1                   81                     2
2                   91                     1
3                   84                     1
4                  100                     1
5                   97                     1

“replace” 옵션을 “TRUE”로 설정한 이유는 두 항목 중에서만 선택하지만, 선택할 때마다 둘 중 하나를 선택할 가능성이 있기 때문입니다. 시뮬레이션에 따라 “replace”를 “TRUE” 또는 “FALSE”로 설정해야 할지 생각해야 할 수 있습니다. sample()의 또 다른 유용한 선택적 인수는 각 항목이 추출될 확률을 조정하는 것입니다. 기본값은 모든 옵션이 동일하게 가능하지만, “prob”를 사용하여 원하는 경우 특정 확률을 지정할 수 있습니다. 함수와 마찬가지로, 도움말 파일에서 더 많은 정보를 찾을 수 있습니다. 예를 들어 ?sample.

A.5.3 function(), for(), 그리고 apply()

R은 이른바 “함수형 프로그래밍 언어(Functional Programming Language)”입니다(Wickham 2019). 이는 우리가 특정 작업을 수행하도록 설계된 코드 뭉치인 ’함수’를 중심으로 사고하고, 이를 조합하여 복잡한 문제를 해결해 나간다는 뜻입니다.

R에는 다른 사람들이 작성한 많은 함수가 있으며, 우리는 그것들을 사용할 수 있습니다. 우리가 수행해야 할 거의 모든 일반적인 통계 또는 데이터 과학 작업은 이미 다른 사람이 작성하여 base R 설치 또는 패키지의 일부로 우리에게 제공된 함수를 가지고 있을 가능성이 높습니다. 그러나 때때로, 특히 더 구체적인 작업을 위해 우리 자신의 함수를 작성해야 할 것입니다. function()을 사용하여 함수를 정의한 다음 이름을 할당합니다. 함수에 일부 입력과 출력을 포함해야 할 것입니다. 입력은 괄호 안에 지정됩니다. 함수가 수행할 특정 작업은 중괄호 안에 들어갑니다.

print_names <- function(some_names) {
  print(some_names)
}

print_names(c("로한", "모니카"))
[1] "로한"   "모니카"

함수를 사용하는 사람이 입력을 제공하지 않는 경우를 대비하여 입력에 대한 기본값을 지정할 수 있습니다.

print_names <- function(some_names = c("에드워드", "휴고")) {
  print(some_names)
}

print_names()
[1] "에드워드" "휴고"    

일반적인 시나리오는 함수를 여러 번 적용하려는 경우입니다. 많은 프로그래밍 언어와 마찬가지로 for() 루프를 사용할 수 있습니다. R에서 for() 루프의 모양은 function()과 유사합니다. 즉, 괄호 안에 반복할 대상을 정의하고, 중괄호 안에 적용할 함수를 정의합니다.

R은 통계에 중점을 둔 프로그래밍 언어이므로, 우리는 종종 배열이나 행렬에 관심이 있습니다. apply()를 사용하여 행(“MARGIN = 1”) 또는 열(“MARGIN = 2”)에 함수를 적용합니다.

simulated_data
  favorite_color person std_normal_observations uniform_observations
1         파란색      1             -0.35980342            9.6219155
2         파란색      2             -0.04064753            7.2269016
3         파란색      3             -1.78216227            0.8252921
4           흰색      4             -1.12242282            1.0379810
5         파란색      5             -1.00278400            3.0942004
  poisson_observations binomial_observations
1                   81                     2
2                   91                     1
3                   84                     1
4                  100                     1
5                   97                     1
apply(X = simulated_data, MARGIN = 2, FUN = unique)
$favorite_color
[1] "파란색" "흰색"  

$person
[1] "1" "2" "3" "4" "5"

$std_normal_observations
[1] "-0.35980342" "-0.04064753" "-1.78216227" "-1.12242282" "-1.00278400"

$uniform_observations
[1] "9.6219155" "7.2269016" "0.8252921" "1.0379810" "3.0942004"

$poisson_observations
[1] " 81" " 91" " 84" "100" " 97"

$binomial_observations
[1] "2" "1"

A.6 ggplot2로 그래프 만들기

데이터 조작 측면에서 tidyverse의 핵심 패키지가 dplyr(Wickham et al. 2022)이라면, 그래프 생성 측면에서 tidyverse의 핵심 패키지는 ggplot2(Wickham 2016)입니다. Chapter 5에서 그래프에 대해 더 자세히 다룰 것이지만, 여기서는 몇 가지 필수 사항을 간략하게 소개합니다. ggplot2는 “그래픽 문법”(따라서 “gg”)을 기반으로 그래프를 형성하는 레이어를 정의하여 작동합니다. 파이프 연산자(|>) 대신 ggplot2는 더하기 연산자 +를 사용합니다. tidyverse 패키지 모음의 일부이므로 tidyverse가 로드되면 ggplot2는 명시적으로 설치하거나 로드할 필요가 없습니다.

ggplot2로 그래프를 만들려면 세 가지 핵심 측면을 지정해야 합니다.

  1. 데이터;
  2. 미학 / 매핑; 그리고
  3. 유형.

시작하려면 경제 협력 개발 기구(OECD) 국가의 GDP 데이터를 가져올 것입니다(OECD 2022).

library(tidyverse)

oecd_gdp <-
  read_csv("https://stats.oecd.org/sdmx-json/data/DP_LIVE/.QGDP.../OECD?contentType=csv&detail=code&separator=comma&csv-lang=en")

write_csv(oecd_gdp, "inputs/data/oecd_gdp.csv")
# A tibble: 6 × 8
  LOCATION INDICATOR SUBJECT MEASURE  FREQUENCY TIME  Value `Flag Codes`
  <chr>    <chr>     <chr>   <chr>    <chr>     <chr> <dbl> <chr>       
1 OECD     QGDP      TOT     PC_CHGPP A         1962   5.70 <NA>        
2 OECD     QGDP      TOT     PC_CHGPP A         1963   5.20 <NA>        
3 OECD     QGDP      TOT     PC_CHGPP A         1964   6.38 <NA>        
4 OECD     QGDP      TOT     PC_CHGPP A         1965   5.35 <NA>        
5 OECD     QGDP      TOT     PC_CHGPP A         1966   5.75 <NA>        
6 OECD     QGDP      TOT     PC_CHGPP A         1967   3.96 <NA>        

우리는 먼저 2021년 3분기 OECD 10개국(호주, 캐나다, 칠레, 인도네시아, 독일, 영국, 뉴질랜드, 남아프리카 공화국, 스페인, 미국)의 GDP 변화에 대한 막대 차트를 만들고자 합니다.

oecd_gdp_2021_q3 <-
  oecd_gdp |>
  filter(
    TIME == "2021-Q3",
    SUBJECT == "TOT",
    LOCATION %in% c(
      "AUS",
      "CAN",
      "CHL",
      "DEU",
      "GBR",
      "IDN",
      "ESP",
      "NZL",
      "USA",
      "ZAF"
    ),
    MEASURE == "PC_CHGPY"
  ) |>
  mutate(
    european = if_else(
      LOCATION %in% c("DEU", "GBR", "ESP"),
      "European",
      "Not european"
    ),
    hemisphere = if_else(
      LOCATION %in% c("CAN", "DEU", "GBR", "ESP", "USA"),
      "Northern Hemisphere",
      "Southern Hemisphere"
    ),
  )

ggplot()으로 시작하여 매핑/미학을 지정합니다. 이 경우 x축과 y축을 지정하는 것을 의미합니다. ggplot()의 첫 번째 인수는 시각화하려는 데이터이므로, 평소처럼 파이프 연산자를 사용할 수 있습니다.

oecd_gdp_2021_q3 |>
  ggplot(mapping = aes(x = LOCATION, y = Value))

이제 관심 있는 그래프 유형을 지정해야 합니다. 이 경우 막대 차트를 원하며, +를 사용하여 geom_bar()를 추가하여 이를 수행합니다.

oecd_gdp_2021_q3 |>
  ggplot(mapping = aes(x = LOCATION, y = Value)) +
  geom_bar(stat = "identity")

“fill”이라는 또 다른 미학을 추가하여 국가가 유럽 국가인지 여부에 따라 막대에 색상을 지정할 수 있습니다.

oecd_gdp_2021_q3 |>
  ggplot(mapping = aes(x = LOCATION, y = Value, fill = european)) +
  geom_bar(stat = "identity")

마지막으로, labs()로 레이블을 추가하고, scale_fill_brewer()로 색상을 변경하고, theme_classic()로 배경을 변경하여 더 멋지게 만들 수 있습니다.

oecd_gdp_2021_q3 |>
  ggplot(mapping = aes(x = LOCATION, y = Value, fill = european)) +
  geom_bar(stat = "identity") +
  labs(
    title = "2021년 3분기 OECD 10개국의 분기별 GDP 변화",
    x = "국가",
    y = "변화 (%)",
    fill = "유럽입니까?"
  ) +
  theme_classic() +
  scale_fill_brewer(palette = "Set1")

패싯을 사용하면 데이터의 특정 측면에 초점을 맞춘 하위 플롯을 만들 수 있습니다. 3D 그래프를 만들 필요 없이 그래프에 다른 변수를 추가할 수 있으므로 매우 유용합니다. facet_wrap()을 사용하여 패싯을 추가하고 패싯할 변수를 지정합니다. 이 경우 반구별로 패싯합니다.

oecd_gdp_2021_q3 |>
  ggplot(mapping = aes(x = LOCATION, y = Value, fill = european)) +
  geom_bar(stat = "identity") +
  labs(
    title = "2021년 3분기 OECD 10개국의 분기별 GDP 변화",
    x = "국가",
    y = "변화 (%)",
    fill = "유럽입니까?"
  ) +
  theme_classic() +
  scale_fill_brewer(palette = "Set1") +
  facet_wrap(
    ~hemisphere,
    scales = "free_x"
  )

A.7 tidyverse 탐색

tidyverse의 두 가지 측면인 dplyrggplot2에 초점을 맞췄습니다. 그러나 tidyverse는 다양한 패키지와 함수로 구성되어 있습니다. 이제 네 가지 일반적인 측면을 살펴보겠습니다.

  • 데이터 가져오기 및 tibble();
  • 데이터셋 결합 및 피벗;
  • 문자열 조작 및 stringr;
  • 요인 변수 및 forcats.

그러나 첫 번째 작업은 명명법을 다루는 것이며, 특히 “tidyverse”에서 “tidy”가 무엇을 의미하는지 명확히 하는 것입니다. 이름은 정돈된 데이터를 의미하며, 그 이점은 데이터가 지저분할 수 있는 다양한 방법이 있지만, 정돈된 데이터는 세 가지 규칙을 충족한다는 것입니다. 이는 데이터셋의 구조가 세부 사항에 관계없이 일관되며, 특정 유형의 입력을 예상하는 함수를 적용하기가 더 쉽다는 것을 의미합니다. 정돈된 데이터는 다음을 충족하는 데이터셋을 의미합니다(Wickham, Çetinkaya-Rundel, and Grolemund [2016] 2023; Wickham 2014, 4).

  • 모든 변수는 자체 열에 있습니다.
  • 모든 관측치는 자체 행에 있습니다.
  • 모든 값은 자체 셀에 있습니다.

Table A.1 는 연령과 머리카락이 열을 공유하므로 정돈되지 않았습니다. Table A.2 는 정돈된 데이터입니다.

Table A.1: 정돈되지 않은 데이터의 예시
사람 변수
로한 나이 35
로한 머리카락 검정
모니카 나이 35
모니카 머리카락 금발
에드워드 나이 3
에드워드 머리카락 갈색
휴고 나이 1
휴고 머리카락 금발
Table A.2: 정돈된 데이터의 예시
사람 나이 머리카락
로한 35 검정
모니카 35 금발
에드워드 3 갈색
휴고 1 금발

A.7.1 데이터 가져오기 및 tibble()

데이터를 R로 가져와 사용할 수 있는 다양한 방법이 있습니다. CSV 파일의 경우 readr(Wickham, Hester, and Bryan 2022)read_csv()가 있고, Stata 파일의 경우 haven(Wickham, Miller, and Smith 2023)read_dta()가 있습니다.

CSV는 일반적인 형식이며, 데이터를 수정하지 않는다는 점을 포함하여 많은 장점이 있습니다. 각 열은 쉼표로 구분되고, 각 행은 레코드입니다. read_csv()에 URL 또는 로컬 파일을 제공하여 읽을 수 있습니다. read_csv()에 전달할 수 있는 다양한 옵션이 있으며, 데이터셋에 열 이름이 있는지, 열의 유형, 건너뛸 줄 수를 지정할 수 있습니다. 열의 유형을 지정하지 않으면 read_csv()는 데이터셋을 보고 추측합니다.

우리는 read_dta()를 사용하여 .dta 파일을 읽습니다. 이 파일은 통계 프로그램 Stata에서 일반적으로 생성됩니다. 이는 사회학, 정치학, 경제학과 같은 분야에서 흔히 사용된다는 것을 의미합니다. 이 형식은 데이터를 레이블과 분리하므로, 일반적으로 labelled(Larmarange 2023)to_factor()를 사용하여 다시 결합합니다. haventidyverse의 일부이지만, ggplot2와 같은 패키지와 달리 기본적으로 자동으로 로드되지 않으므로 library(haven)을 실행해야 합니다.

일반적으로 데이터셋은 R에 “data.frame”으로 들어옵니다. 이것은 유용할 수 있지만, 데이터셋에 대한 또 다른 유용한 클래스는 “tibble”입니다. 이것은 tidyverse의 일부인 tibbletibble()을 사용하여 생성할 수 있습니다. 티블은 데이터 프레임이지만, 기본적으로 문자열을 요인으로 변환하지 않고, 열의 클래스를 표시하고, 깔끔하게 인쇄하는 등 작업하기 쉽게 만드는 몇 가지 특정 변경 사항이 있습니다.

필요한 경우 수동으로 티블을 만들 수 있습니다. 예를 들어, 데이터를 시뮬레이션할 때입니다. 그러나 일반적으로 read_csv()를 사용할 때와 같이 데이터를 티블로 직접 가져옵니다.

people_as_dataframe <-
  data.frame(
    names = c("로한", "모니카"),
    website = c("rohanalexander.com", "monicaalexander.com"),
    fav_color = c("파란색", "흰색")
  )
class(people_as_dataframe)
[1] "data.frame"
people_as_dataframe
   names             website fav_color
1   로한  rohanalexander.com    파란색
2 모니카 monicaalexander.com      흰색
people_as_tibble <-
  tibble(
    names = c("로한", "모니카"),
    website = c("rohanalexander.com", "monicaalexander.com"),
    fav_color = c("파란색", "흰색")
  )
people_as_tibble
# A tibble: 2 × 3
  names  website             fav_color
  <chr>  <chr>               <chr>    
1 로한   rohanalexander.com  파란색   
2 모니카 monicaalexander.com 흰색     
class(people_as_tibble)
[1] "tbl_df"     "tbl"        "data.frame"

A.7.2 결합 및 피벗을 사용한 데이터셋 조작

자주 필요한 데이터셋 조작은 결합과 피벗입니다.

두 개 이상의 데이터셋이 있고 그것들을 결합하는 데 관심이 있는 경우가 많습니다. 다양한 방법으로 데이터셋을 결합할 수 있습니다. 일반적인 방법은 dplyr(Wickham et al. 2022)left_join()을 사용하는 것입니다. 이것은 우리가 사용하는 하나의 주요 데이터셋이 있고, 거기에 추가하고 싶은 유용한 변수가 있는 다른 데이터셋이 있을 때 가장 유용합니다. 중요한 측면은 두 데이터셋을 연결하는 데 사용할 수 있는 열 또는 열이 있다는 것입니다. 여기서는 두 개의 티블을 만든 다음 이름을 기준으로 결합할 것입니다.

main_dataset <-
  tibble(
    names = c("로한", "모니카", "에드워드", "휴고"),
    status = c("성인", "성인", "어린이", "유아")
  )
main_dataset
# A tibble: 4 × 2
  names    status
  <chr>    <chr> 
1 로한     성인  
2 모니카   성인  
3 에드워드 어린이
4 휴고     유아  
supplementary_dataset <-
  tibble(
    names = c("로한", "모니카", "에드워드", "휴고"),
    favorite_food = c("파스타", "연어", "피자", "우유")
  )
supplementary_dataset
# A tibble: 4 × 2
  names    favorite_food
  <chr>    <chr>        
1 로한     파스타       
2 모니카   연어         
3 에드워드 피자         
4 휴고     우유         
main_dataset <-
  main_dataset |>
  left_join(supplementary_dataset, by = "names")

main_dataset
# A tibble: 4 × 3
  names    status favorite_food
  <chr>    <chr>  <chr>        
1 로한     성인   파스타       
2 모니카   성인   연어         
3 에드워드 어린이 피자         
4 휴고     유아   우유         

inner_join(), right_join(), full_join()을 포함하여 데이터셋을 결합하는 다양한 다른 옵션이 있습니다.

또 다른 일반적인 데이터셋 조작 작업은 피벗입니다. 데이터셋은 길거나 넓은 경향이 있습니다. 긴 데이터는 각 변수가 행에 있으므로 반복이 있을 수 있는 반면, 넓은 데이터는 각 변수가 열이므로 일반적으로 반복이 거의 없습니다(Wickham 2009). 예를 들어, “anscombe”는 넓고, “anscombe_long”은 깁니다.

anscombe
   x1 x2 x3 x4    y1   y2    y3    y4
1  10 10 10  8  8.04 9.14  7.46  6.58
2   8  8  8  8  6.95 8.14  6.77  5.76
3  13 13 13  8  7.58 8.74 12.74  7.71
4   9  9  9  8  8.81 8.77  7.11  8.84
5  11 11 11  8  8.33 9.26  7.81  8.47
6  14 14 14  8  9.96 8.10  8.84  7.04
7   6  6  6  8  7.24 6.13  6.08  5.25
8   4  4  4 19  4.26 3.10  5.39 12.50
9  12 12 12  8 10.84 9.13  8.15  5.56
10  7  7  7  8  4.82 7.26  6.42  7.91
11  5  5  5  8  5.68 4.74  5.73  6.89
anscombe_long
# A tibble: 44 × 3
   set       x     y
   <chr> <dbl> <dbl>
 1 1        10  8.04
 2 2        10  9.14
 3 3        10  7.46
 4 4         8  6.58
 5 1         8  6.95
 6 2         8  8.14
 7 3         8  6.77
 8 4         8  5.76
 9 1        13  7.58
10 2        13  8.74
# ℹ 34 more rows

일반적으로 tidyverse에서, 그리고 확실히 ggplot2에서는 긴 데이터가 필요합니다. 한 형식에서 다른 형식으로 이동하려면 tidyr(Wickham, Vaughan, and Girlich 2023)pivot_longer()pivot_wider()를 사용합니다.

세 년도 각각에서 “마크” 또는 “로렌”이 달리기 경주에서 우승했는지에 대한 넓은 데이터를 생성할 것입니다.

pivot_example_data <-
  tibble(
    year = c(2019, 2020, 2021),
    mark = c("1위", "2위", "1위"),
    lauren = c("2위", "1위", "2위")
  )

pivot_example_data
# A tibble: 3 × 3
   year mark  lauren
  <dbl> <chr> <chr> 
1  2019 1위   2위   
2  2020 2위   1위   
3  2021 1위   2위   

이 데이터셋은 현재 넓은 형식입니다. 긴 형식으로 만들려면 사람을 지정하는 열과 결과를 지정하는 열이 필요합니다. pivot_longer()를 사용하여 이를 달성합니다.

data_pivoted_longer <-
  pivot_example_data |>
  pivot_longer(
    cols = c("mark", "lauren"),
    names_to = "person",
    values_to = "position"
  )

head(data_pivoted_longer)
# A tibble: 6 × 3
   year person position
  <dbl> <chr>  <chr>   
1  2019 mark   1위     
2  2019 lauren 2위     
3  2020 mark   2위     
4  2020 lauren 1위     
5  2021 mark   1위     
6  2021 lauren 2위     

때때로 긴 데이터에서 넓은 데이터로 이동해야 합니다. pivot_wider()를 사용하여 이를 수행합니다.

data_pivoted_wider <-
  data_pivoted_longer |>
  pivot_wider(
    names_from = "person",
    values_from = "position"
  )

head(data_pivoted_wider)
# A tibble: 3 × 3
   year mark  lauren
  <dbl> <chr> <chr> 
1  2019 1위   2위   
2  2020 2위   1위   
3  2021 1위   2위   

A.7.3 문자열 조작 및 stringr

R에서는 종종 큰따옴표로 문자열을 생성하지만, 작은따옴표도 작동합니다. 예를 들어 c("a", "b")는 문자 벡터에 포함된 두 개의 문자열 “a”와 “b”로 구성됩니다. R에서 문자열을 조작하는 다양한 방법이 있으며, stringr(Wickham 2022)에 초점을 맞춥니다. 이것은 tidyverse를 로드할 때 자동으로 로드됩니다.

문자열에 특정 내용이 포함되어 있는지 확인하려면 str_detect()를 사용할 수 있습니다. 그리고 특정 내용을 제거하거나 변경하려면 str_remove() 또는 str_replace()를 사용할 수 있습니다.

dataset_of_strings <-
  tibble(
    names = c(
      "로한 알렉산더",
      "모니카 알렉산더",
      "에드워드 알렉산더",
      "휴고 알렉산더"
    )
  )

dataset_of_strings |>
  mutate(
    is_rohan = str_detect(names, "로한"),
    make_howlett = str_replace(names, "알렉산더", "하울렛"),
    remove_rohan = str_remove(names, "로한")
  )
# A tibble: 4 × 4
  names             is_rohan make_howlett    remove_rohan       
  <chr>             <lgl>    <chr>           <chr>              
1 로한 알렉산더     TRUE     로한 하울렛     " 알렉산더"        
2 모니카 알렉산더   FALSE    모니카 하울렛   "모니카 알렉산더"  
3 에드워드 알렉산더 FALSE    에드워드 하울렛 "에드워드 알렉산더"
4 휴고 알렉산더     FALSE    휴고 하울렛     "휴고 알렉산더"    

데이터 정리에서 특히 유용한 다양한 다른 함수가 있습니다. 예를 들어, str_length()를 사용하여 문자열의 길이를 찾고, str_c()를 사용하여 문자열을 결합할 수 있습니다.

dataset_of_strings |>
  mutate(
    length_is = str_length(string = names),
    name_and_length = str_c(names, length_is, sep = " - ")
  )
# A tibble: 4 × 3
  names             length_is name_and_length      
  <chr>                 <int> <chr>                
1 로한 알렉산더             7 로한 알렉산더 - 7    
2 모니카 알렉산더           8 모니카 알렉산더 - 8  
3 에드워드 알렉산더         9 에드워드 알렉산더 - 9
4 휴고 알렉산더             7 휴고 알렉산더 - 7    

마지막으로, tidyrseparate()stringr의 일부는 아니지만, 문자열 조작에 필수적입니다. 하나의 문자 열을 여러 개로 변환합니다.

dataset_of_strings |>
  separate(
    col = names,
    into = c("first", "last"),
    sep = " ",
    remove = FALSE
  )
# A tibble: 4 × 3
  names             first    last    
  <chr>             <chr>    <chr>   
1 로한 알렉산더     로한     알렉산더
2 모니카 알렉산더   모니카   알렉산더
3 에드워드 알렉산더 에드워드 알렉산더
4 휴고 알렉산더     휴고     알렉산더

A.7.4 요인 변수 및 forcats

요인은 범주인 문자열 모음입니다. 때로는 고유한 순서가 있을 것입니다. 예를 들어, 요일은 월요일, 화요일, 수요일…과 같은 순서를 가지며, 이는 알파벳순이 아닙니다. 그러나 항상 그럴 필요는 없습니다. 예를 들어 임신 상태: 임신 또는 비임신. 요인은 base R에서 두드러지게 나타납니다. 적절한 문자열만 허용되도록 보장하므로 유용할 수 있습니다. 예를 들어, “days_of_the_week”가 요인 변수라면 “January”는 허용되지 않을 것입니다. 그러나 많은 복잡성을 추가할 수 있으므로 tidyverse에서는 덜 중요한 역할을 합니다. 그럼에도 불구하고 특정 상황에서는 요인을 활용하는 것이 유용합니다. 예를 들어, 요일을 플로팅할 때 문자 변수로 가지고 있다면 알파벳순으로 정렬되는 것보다 일반적인 순서로 정렬되기를 원할 것입니다. 요인은 base R에 내장되어 있지만, 요인을 사용할 때 특히 유용한 tidyverse 패키지 중 하나는 forcats(Wickham 2023)입니다.

때로는 문자 벡터가 있고 특정 방식으로 정렬되기를 원할 것입니다. 기본값은 문자 벡터가 알파벳순으로 정렬되는 것이지만, 우리는 그것을 원하지 않을 수 있습니다. 예를 들어, 요일이 알파벳순으로 정렬되면 그래프에서 이상하게 보일 것입니다: 금요일, 월요일, 토요일, 일요일, 목요일, 화요일, 수요일!

정렬을 변경하는 방법은 변수를 문자에서 요인으로 변경하는 것입니다. forcats(Wickham 2023)fct_relevel()을 사용하여 정렬을 지정할 수 있습니다.

set.seed(853)

days_data <-
  tibble(
    days =
      c(
        "월요일",
        "화요일",
        "수요일",
        "목요일",
        "금요일",
        "토요일",
        "일요일"
      ),
    some_value = c(sample.int(100, 7))
  )

days_data <-
  days_data |>
  mutate(
    days_as_factor = factor(days),
    days_as_factor = fct_relevel(
      days,
      "월요일",
      "화요일",
      "수요일",
      "목요일",
      "금요일",
      "토요일",
      "일요일"
    )
  )

그리고 x축에 원본 문자 벡터를 사용하여 그래프를 그린 다음, x축에 요인 벡터를 사용하여 다른 그래프를 그려 결과를 비교할 수 있습니다.

days_data |>
  ggplot(aes(x = days, y = some_value)) +
  geom_point()

days_data |>
  ggplot(aes(x = days_as_factor, y = some_value)) +
  geom_point()

A.8 연습 문제

연습

  1. (계획) 다음 시나리오를 고려하십시오: 어떤 사람이 왕이나 왕비가 더 오래 사는지에 관심이 있으며, 모든 군주에 대해 그들이 얼마나 오래 살았는지에 대한 데이터를 수집합니다. 데이터셋이 어떻게 생겼을지 스케치한 다음, 모든 관측치를 보여주기 위해 만들 수 있는 그래프를 스케치하십시오.
  2. (시뮬레이션) 설명된 시나리오를 더 고려하고, 1,000명의 군주가 있다고 가정하고, 다음 중 어떤 것을 사용하여 상황을 시뮬레이션할 수 있는지 결정하십시오(모두 선택하십시오)?
    1. runif(n = 1000, min = 1, max = 110) |> floor()
    2. rpois(n = 1000, lambda = 65)
    3. rnorm(n = 1000) |> floor()
    4. sample(x = sunspot.month, size = 1000, replace = TRUE) |> floor()
  3. (수집) 군주가 얼마나 오래 살았는지에 대한 실제 데이터의 가능한 출처를 하나 식별하십시오.
  4. (탐색) tidyverse가 로드되어 있고, 데이터셋 “monarchs”에 “years” 열이 있다고 가정하십시오. 다음 중 어떤 것이 35년 이상 산 군주만 결과로 나타낼까요(하나 선택)?
    1. monarchs |> arrange(years > 35)
    2. monarchs |> select(years > 35)
    3. monarchs |> filter(years > 35)
    4. monarchs |> mutate(years > 35)
  5. (소통) 해당 출처에서 데이터를 수집하고 그래프를 만들었다고 가정하고 두 단락을 작성하십시오. 단락에 포함된 정확한 세부 정보는 사실일 필요는 없습니다(즉, 실제로 데이터를 얻거나 그래프를 만들 필요는 없습니다).

퀴즈

  1. R은 무엇입니까 (하나 선택)?
    1. 오픈 소스 통계 프로그래밍 언어
    2. 귀도 반 로섬이 만든 프로그래밍 언어
    3. 폐쇄 소스 통계 프로그래밍 언어
    4. 통합 개발 환경 (IDE)
  2. R의 세 가지 장점은 무엇입니까? 세 가지 단점은 무엇입니까?
  3. RStudio는 무엇입니까?
    1. 통합 개발 환경 (IDE).
    2. 폐쇄 소스 유료 프로그램.
    3. 귀도 반 로섬이 만든 프로그래밍 언어
    4. 통계 프로그래밍 언어.
  4. 2 + 2의 출력 클래스는 무엇입니까 (하나 선택)?
    1. character
    2. factor
    3. numeric
    4. date
  5. my_name <- "로한"을 실행했다고 가정해 봅시다. print(my_name)을 실행한 결과는 무엇입니까 (하나 선택)?
    1. “에드워드”
    2. “모니카”
    3. “휴고”
    4. “로한”
  6. “name”과 “age”라는 두 개의 열이 있는 데이터셋이 있다고 가정해 봅시다. “name”만 선택하려면 어떤 동사를 사용해야 합니까 (하나 선택)?
    1. select()
    2. mutate()
    3. filter()
    4. rename()
  7. AustralianPoliticianstidyverse를 로드한 다음 다음 코드를 실행했다고 가정해 봅시다: australian_politicians <- get_auspol("all"). “Name”으로 끝나는 모든 열을 어떻게 선택할 수 있습니까 (하나 선택)?
    1. australian_politicians |> select(contains("Name"))
    2. australian_politicians |> select(starts_with("Name"))
    3. australian_politicians |> select(matches("Name"))
    4. australian_politicians |> select(ends_with("Name"))
  8. 열 이름 측면에서, 위 질문에서 contains()를 사용하는 것이 ends_with()를 사용하는 것과 다른 결과를 줄 수 있는 상황은 무엇입니까?
  9. 다음 중 tidyverse 동사가 아닌 것은 무엇입니까 (하나 선택)?
    1. select()
    2. filter()
    3. arrange()
    4. mutate()
    5. visualize()
  10. 새 열을 만드는 함수는 무엇입니까 (하나 선택)?
    1. select()
    2. filter()
    3. arrange()
    4. mutate()
    5. visualize()
  11. 특정 행에 초점을 맞추는 함수는 무엇입니까 (하나 선택)?
    1. select()
    2. filter()
    3. arrange()
    4. mutate()
    5. summarise()
  12. 성별별 데이터셋의 평균을 제공할 수 있는 두 가지 조합은 무엇입니까 (두 가지 선택)?
    1. summarise()
    2. filter()
    3. arrange()
    4. mutate()
    5. .by
  13. “age”라는 변수가 정수라고 가정해 봅시다. 다음 코드 줄 중 어떤 것이 그 지수를 나타내는 열을 생성할까요 (하나 선택)?
    1. generate(exp_age = exp(age))
    2. change(exp_age = exp(age))
    3. make(exp_age = exp(age))
    4. mutate(exp_age = exp(age))
  14. “age”라는 열이 있다고 가정해 봅시다. 다음 코드 줄 중 어떤 것이 5행 위에서 값을 포함하는 열을 생성할 수 있을까요?
    1. mutate(five_before = lag(age))
    2. mutate(five_before = lead(age))
    3. mutate(five_before = lag(age, n = 5))
    4. mutate(five_before = lead(age, n = 5))
  15. class("edward")의 출력은 무엇입니까 (하나 선택)?
    1. “numeric”
    2. “character”
    3. “data.frame”
    4. “vector”
  16. “파란색, 흰색, 빨간색” 세 가지 옵션에서 한 번 추출하고, “파란색”과 “흰색”에 10% 확률, 나머지는 “빨간색”에 확률을 부여하는 함수는 무엇입니까?
    1. sample(c("파란색", "흰색", "빨간색"), prob = c(0.1, 0.1, 0.8))
    2. sample(c("파란색", "흰색", "빨간색"), size = 1)
    3. sample(c("파란색", "흰색", "빨간색"), size = 1, prob = c(0.8, 0.1, 0.1))
    4. sample(c("파란색", "흰색", "빨간색"), size = 1, prob = c(0.1, 0.1, 0.8))
  17. 평균 27, 표준 편차 3인 정규 분포에서 10,000개의 표본을 시뮬레이션하는 코드는 무엇입니까 (하나 선택)?
    1. rnorm(10000, mean = 27, sd = 3)
    2. rnorm(27, mean = 10000, sd = 3)
    3. rnorm(3, mean = 10000, sd = 27)
    4. rnorm(27, mean = 3, sd = 1000)
  18. 그래픽 문법의 세 가지 핵심 측면은 무엇입니까 (모두 선택하십시오)?
    1. 데이터
    2. 미학
    3. 유형
    4. geom_histogram()

활동

우리는 데이터에 끌릴 때 의심해야 한다. 즉, 매우, 매우 얇고 약한 데이터가 역사상 많은 사회에서 큰 통용력을 가졌던 신념을 정당화하는 것처럼 보일 때, 이는 인구의 많은 부분을 억압하는 데 도움이 되는 방식으로 이루어진다.

아미아 스리니바산 (Cowen 2021)

옥스포드 올 소울스 칼리지의 사회 및 정치 이론 치첼레 교수인 아미아 스리니바산의 인용문과 D’Ignazio and Klein (2020), 특히 6장을 되돌아보십시오.

의미 있는 이름과 적절한 구조를 가진 GitHub 리포지토리를 만들고, 재현 가능한 Quarto 파일을 사용하여 최소 두 페이지(참고 문헌 제외)의 PDF를 생성하여 익숙한 데이터셋과 관련하여 해당 인용문을 논의하십시오. PDF 파일 링크(예: https://github.com/RohanAlexander/starter_folder/blob/main/outputs/paper/paper.pdf)와 PDF 자체를 제출하십시오.