Tidying, Visualising and Summarising Data

FMB819: R을 이용한 데이터분석

고려대학교 경영대학 정지웅

Working With Data

  • 2014년 뉴욕타임즈 기사에 따르면, “데이터 과학자들은 데이터를 분석하기 전에 50%에서 80%의 시간을 데이터 수집 및 정리에 소비한다.”라고 함.

  • 다음 두 강의에서는 데이터 정리, 시각화, 요약의 기본을 배움.

Tidying Data

dplyr 소개

  • dplyrtidyverse 패키지군의 일부.
  • data.table도 대안으로 사용 가능하며, 대용량 데이터에 최적화되어 있음.
  • 여기서는 dplyr을 다룸.

dplyr 개요

  • Hadley Wickham의 “R for Data Science”, 링크 영문판, 국문판
  • dplyr은 여러 verbs 중심으로 구성되어 있음.
  • data.frame 또는 tibble 형식의 데이터를 다룰 것임.

\[\text{verb}(\underbrace{\text{data.frame}}_{\text{1st argument}}, \underbrace{\text{what to do}}_\text{2nd argument})\]

  • 또는 pipe 연산자 %>% 이용 (magrittr 패키지) 또는 |>도 가능:

\[\underbrace{\text{data.frame}}_{\text{1st argument}} \underbrace{\text{ %>% }}_{\text{"pipe" operator}} \text{verb}(\underbrace{\text{what to do}}_\text{2nd argument})\]

주요 dplyr verbs

  1. filter(): 특정 조건을 만족하는 행 선택
  2. arrange(): 행 정렬
  3. select(): 특정 열 선택
  4. mutate(): 기존 열을 이용하여 새 변수 생성
  5. summarise(): 요약 통계 계산
  6. group_by(): 그룹별 연산 수행 가능

예제 데이터: 2016년 미국 대선 여론조사 (dslabs 패키지)

  • 2016년 미국 대선과 관련된 여론조사 데이터를 포함
library(dslabs)
library(tidyverse)
data(polls_us_election_2016, package = "dslabs")
polls_us_election_2016 <- as_tibble(polls_us_election_2016) # 데이터를 'tibble' 형식으로 변환
head(polls_us_election_2016[,1:6]) # 데이터의 첫 6개의 행과 첫 6개의 열을 출력
## # A tibble: 6 × 6
##   state startdate  enddate    pollster                          grade samplesize
##   <fct> <date>     <date>     <fct>                             <fct>      <int>
## 1 U.S.  2016-11-03 2016-11-06 ABC News/Washington Post          A+          2220
## 2 U.S.  2016-11-01 2016-11-07 Google Consumer Surveys           B          26574
## 3 U.S.  2016-11-02 2016-11-06 Ipsos                             A-          2195
## 4 U.S.  2016-11-04 2016-11-07 YouGov                            B           3677
## 5 U.S.  2016-11-03 2016-11-06 Gravis Marketing                  B-         16639
## 6 U.S.  2016-11-03 2016-11-06 Fox News/Anderson Robbins Resear… A           1295

예제 데이터: 2016년 미국 대선 여론조사 (dslabs 패키지)

  • 이 데이터셋에 어떤 변수가 포함되어 있는지 확인
str(polls_us_election_2016) # 데이터의 구조를 요약하여 출력
## tibble [4,208 × 15] (S3: tbl_df/tbl/data.frame)
##  $ state           : Factor w/ 57 levels "Alabama","Alaska",..: 50 50 50 50 50 50 50 50 37 50 ...
##  $ startdate       : Date[1:4208], format: "2016-11-03" "2016-11-01" ...
##  $ enddate         : Date[1:4208], format: "2016-11-06" "2016-11-07" ...
##  $ pollster        : Factor w/ 196 levels "ABC News/Washington Post",..: 1 63 81 194 65 55 18 113 195 76 ...
##  $ grade           : Factor w/ 10 levels "D","C-","C","C+",..: 10 6 8 6 5 9 8 8 NA 8 ...
##  $ samplesize      : int [1:4208] 2220 26574 2195 3677 16639 1295 1426 1282 8439 1107 ...
##  $ population      : chr [1:4208] "lv" "lv" "lv" "lv" ...
##  $ rawpoll_clinton : num [1:4208] 47 38 42 45 47 ...
##  $ rawpoll_trump   : num [1:4208] 43 35.7 39 41 43 ...
##  $ rawpoll_johnson : num [1:4208] 4 5.46 6 5 3 3 5 6 6 7.1 ...
##  $ rawpoll_mcmullin: num [1:4208] NA NA NA NA NA NA NA NA NA NA ...
##  $ adjpoll_clinton : num [1:4208] 45.2 43.3 42 45.7 46.8 ...
##  $ adjpoll_trump   : num [1:4208] 41.7 41.2 38.8 40.9 42.3 ...
##  $ adjpoll_johnson : num [1:4208] 4.63 5.18 6.84 6.07 3.73 ...
##  $ adjpoll_mcmullin: num [1:4208] NA NA NA NA NA NA NA NA NA NA ...

dplyr: filter()

# 표본 크기(samplesize)가 2000보다 큰 행만 선택, 츨력
polls_us_election_2016 %>%
  filter(samplesize > 2000)
## # A tibble: 403 × 15
##    state      startdate  enddate    pollster         grade samplesize population
##    <fct>      <date>     <date>     <fct>            <fct>      <int> <chr>     
##  1 U.S.       2016-11-03 2016-11-06 ABC News/Washin… A+          2220 lv        
##  2 U.S.       2016-11-01 2016-11-07 Google Consumer… B          26574 lv        
##  3 U.S.       2016-11-02 2016-11-06 Ipsos            A-          2195 lv        
##  4 U.S.       2016-11-04 2016-11-07 YouGov           B           3677 lv        
##  5 U.S.       2016-11-03 2016-11-06 Gravis Marketing B-         16639 rv        
##  6 New Mexico 2016-11-06 2016-11-06 Zia Poll         <NA>        8439 lv        
##  7 U.S.       2016-11-05 2016-11-07 The Times-Picay… <NA>        2521 lv        
##  8 U.S.       2016-11-01 2016-11-07 USC Dornsife/LA… <NA>        2972 lv        
##  9 Georgia    2016-11-03 2016-11-06 Gravis Marketing B-          2002 rv        
## 10 Virginia   2016-11-01 2016-11-02 Remington        <NA>        3076 lv        
## # ℹ 393 more rows
## # ℹ 8 more variables: rawpoll_clinton <dbl>, rawpoll_trump <dbl>,
## #   rawpoll_johnson <dbl>, rawpoll_mcmullin <dbl>, adjpoll_clinton <dbl>,
## #   adjpoll_trump <dbl>, adjpoll_johnson <dbl>, adjpoll_mcmullin <dbl>

dplyr: filter()

기본적인 비교 연산자:

  • >: 크다 (greater than)

  • <: 작다 (smaller than)

  • >=: 크거나 같다 (greater than or equal to)

  • <=: 작거나 같다 (smaller than or equal to)

  • !=: 같지 않다 (not equal to)

  • ==: 같다 (equal to)

논리 연산자:

  1. x & y: x 그리고 y (둘 다 참일 때만 참)

  2. x | y: x 또는 y (둘 중 하나라도 참이면 참)

  3. !y: y가 아닐 때 (논리 반전)

dplyr: filter()

  • %in% 연산자의 이용

  • x %in% yxy의 요소인지 확인

  • !(x %in% y)를 사용하면 반대의 논리 적용

# 3이 1부터 3까지의 숫자 중 하나인지 확인 (TRUE)
3 %in% 1:3  
## [1] TRUE
# 벡터화된 연산: 2와 5가 2부터 10 사이의 숫자 중 하나인지 확인 (각각 TRUE와 TRUE)
c(2,5) %in% 2:10  
## [1] TRUE TRUE
# 문자열 비교: "S" 또는 "Po"가 벡터 `c("Sciences","Po")`의 요소인지 확인
c("K","Uni") %in% c("Korea","University")  
## [1] FALSE FALSE

dplyr: filter()

A 등급을 받은 여론조사 중 표본 크기가 2,000명 이상이고, 트럼프가 최소 45%의 지지를 받은 여론조사는?

# polls_us_election_2016 데이터에서 
# 1. 등급(grade)이 "A"이고
# 2. 표본 크기(samplesize)가 2000명보다 크며
# 3. 트럼프의 여론조사 지지율(rawpoll_trump)이 45% 이상인 행을 필터링합니다.
polls_us_election_2016 %>%
  filter(grade == "A" & samplesize > 2000 & rawpoll_trump > 45) 
## # A tibble: 1 × 15
##   state   startdate  enddate    pollster       grade samplesize population
##   <fct>   <date>     <date>     <fct>          <fct>      <int> <chr>     
## 1 Indiana 2016-04-26 2016-04-28 Marist College A           2149 rv        
## # ℹ 8 more variables: rawpoll_clinton <dbl>, rawpoll_trump <dbl>,
## #   rawpoll_johnson <dbl>, rawpoll_mcmullin <dbl>, adjpoll_clinton <dbl>,
## #   adjpoll_trump <dbl>, adjpoll_johnson <dbl>, adjpoll_mcmullin <dbl>

dplyr: mutate()

  1. 각 여론조사에서 트럼프와 클린턴의 지지율 합계
  2. 트럼프의 원래(raw) 지지율과 FiveThirtyEight의 조정(adjusted) 지지율 간의 차이
# 1. trump_clinton_tot: 트럼프와 클린턴의 지지율 합계
# 2. trump_raw_adj_diff: 트럼프의 원래 지지율과 538 조정 지지율 간의 차이
# 마지막으로 names() 함수를 사용하여 데이터의 변수명을 확인.
polls_us_election_2016 %>%
  mutate(trump_clinton_tot = rawpoll_trump + rawpoll_clinton, # 트럼프와 클린턴 지지율 합계
         trump_raw_adj_diff = rawpoll_trump - adjpoll_trump) %>% # 원래 지지율과 조정 지지율 차이
  names() # 변수명 출력
##  [1] "state"              "startdate"          "enddate"           
##  [4] "pollster"           "grade"              "samplesize"        
##  [7] "population"         "rawpoll_clinton"    "rawpoll_trump"     
## [10] "rawpoll_johnson"    "rawpoll_mcmullin"   "adjpoll_clinton"   
## [13] "adjpoll_trump"      "adjpoll_johnson"    "adjpoll_mcmullin"  
## [16] "trump_clinton_tot"  "trump_raw_adj_diff"

dplyr: select()

  • 다음 변수만 선택: state, startdate, enddate, pollster, rawpoll_clinton, rawpoll_trump
# select() 함수를 사용하여 특정 열만 선택.
# 1. state: 조사된 주(State)
# 2. startdate: 여론조사가 시작된 날짜
# 3. enddate: 여론조사가 종료된 날짜
# 4. pollster: 여론조사 기관
# 5. rawpoll_clinton: 힐러리 클린턴의 원래(raw) 지지율
# 6. rawpoll_trump: 도널드 트럼프의 원래(raw) 지지율

polls_us_election_2016 %>%
  select(state, startdate, enddate, pollster, rawpoll_clinton, rawpoll_trump) %>% 
  names() # 데이터 프레임의 변수명을 출력하여 올바르게 선택되었는지 확인
## [1] "state"           "startdate"       "enddate"         "pollster"       
## [5] "rawpoll_clinton" "rawpoll_trump"

dplyr: summarise()

  • 트럼프의 최대 지지율은 얼마인가?
# summarise() 함수를 사용하여 트럼프의 최대(raw) 지지율을 계산
# max() 함수는 주어진 열에서 가장 큰 값을 반환

polls_us_election_2016 %>%
  summarise(max_trump = max(rawpoll_trump)) # 트럼프의 최대 지지율 계산
## # A tibble: 1 × 1
##   max_trump
##       <dbl>
## 1        68

dplyr: group_by()

  • 여론조사 등급(grade)별 클린턴의 평균 지지율은 얼마인가?
# group_by()를 사용하여 여론조사 등급(grade)별로 그룹을 나눔.
# summarise()를 사용하여 각 그룹에서 rawpoll_clinton(클린턴의 원래 지지율)의 평균 계산

polls_us_election_2016 %>%
  group_by(grade) %>% # 여론조사 등급별 그룹화
  summarise(mean_vote_clinton = mean(rawpoll_clinton, na.rm = TRUE)) # 각 그룹에서 클린턴의 평균 지지율 계산
## # A tibble: 11 × 2
##    grade mean_vote_clinton
##    <fct>             <dbl>
##  1 D                  46.7
##  2 C-                 43.2
##  3 C                  41.8
##  4 C+                 44.2
##  5 B-                 43.9
##  6 B                  37.3
##  7 B+                 44.1
##  8 A-                 43.0
##  9 A                  45.3
## 10 A+                 45.8
## 11 <NA>               43.2

명령어 연결하기

polls_us_election_2016
## # A tibble: 4,208 × 15
##    state      startdate  enddate    pollster         grade samplesize population
##    <fct>      <date>     <date>     <fct>            <fct>      <int> <chr>     
##  1 U.S.       2016-11-03 2016-11-06 ABC News/Washin… A+          2220 lv        
##  2 U.S.       2016-11-01 2016-11-07 Google Consumer… B          26574 lv        
##  3 U.S.       2016-11-02 2016-11-06 Ipsos            A-          2195 lv        
##  4 U.S.       2016-11-04 2016-11-07 YouGov           B           3677 lv        
##  5 U.S.       2016-11-03 2016-11-06 Gravis Marketing B-         16639 rv        
##  6 U.S.       2016-11-03 2016-11-06 Fox News/Anders… A           1295 lv        
##  7 U.S.       2016-11-02 2016-11-06 CBS News/New Yo… A-          1426 lv        
##  8 U.S.       2016-11-03 2016-11-05 NBC News/Wall S… A-          1282 lv        
##  9 New Mexico 2016-11-06 2016-11-06 Zia Poll         <NA>        8439 lv        
## 10 U.S.       2016-11-04 2016-11-07 IBD/TIPP         A-          1107 lv        
## # ℹ 4,198 more rows
## # ℹ 8 more variables: rawpoll_clinton <dbl>, rawpoll_trump <dbl>,
## #   rawpoll_johnson <dbl>, rawpoll_mcmullin <dbl>, adjpoll_clinton <dbl>,
## #   adjpoll_trump <dbl>, adjpoll_johnson <dbl>, adjpoll_mcmullin <dbl>

명령어 연결하기

polls_us_election_2016 %>%
    mutate(trump_clinton_diff = 
             rawpoll_trump - 
             rawpoll_clinton) 
## # A tibble: 4,208 × 16
##    state      startdate  enddate    pollster         grade samplesize population
##    <fct>      <date>     <date>     <fct>            <fct>      <int> <chr>     
##  1 U.S.       2016-11-03 2016-11-06 ABC News/Washin… A+          2220 lv        
##  2 U.S.       2016-11-01 2016-11-07 Google Consumer… B          26574 lv        
##  3 U.S.       2016-11-02 2016-11-06 Ipsos            A-          2195 lv        
##  4 U.S.       2016-11-04 2016-11-07 YouGov           B           3677 lv        
##  5 U.S.       2016-11-03 2016-11-06 Gravis Marketing B-         16639 rv        
##  6 U.S.       2016-11-03 2016-11-06 Fox News/Anders… A           1295 lv        
##  7 U.S.       2016-11-02 2016-11-06 CBS News/New Yo… A-          1426 lv        
##  8 U.S.       2016-11-03 2016-11-05 NBC News/Wall S… A-          1282 lv        
##  9 New Mexico 2016-11-06 2016-11-06 Zia Poll         <NA>        8439 lv        
## 10 U.S.       2016-11-04 2016-11-07 IBD/TIPP         A-          1107 lv        
## # ℹ 4,198 more rows
## # ℹ 9 more variables: rawpoll_clinton <dbl>, rawpoll_trump <dbl>,
## #   rawpoll_johnson <dbl>, rawpoll_mcmullin <dbl>, adjpoll_clinton <dbl>,
## #   adjpoll_trump <dbl>, adjpoll_johnson <dbl>, adjpoll_mcmullin <dbl>,
## #   trump_clinton_diff <dbl>

명령어 연결하기

polls_us_election_2016 %>%
    mutate(trump_clinton_diff = 
             rawpoll_trump - 
             rawpoll_clinton) %>%
    filter(trump_clinton_diff>5 &
           state == "Iowa" &
           is.na(rawpoll_johnson))
## # A tibble: 3 × 16
##   state startdate  enddate    pollster grade samplesize population
##   <fct> <date>     <date>     <fct>    <fct>      <int> <chr>     
## 1 Iowa  2016-09-09 2016-09-29 Ipsos    A-           343 lv        
## 2 Iowa  2016-09-02 2016-09-22 Ipsos    A-           344 lv        
## 3 Iowa  2016-08-26 2016-09-15 Ipsos    A-           347 lv        
## # ℹ 9 more variables: rawpoll_clinton <dbl>, rawpoll_trump <dbl>,
## #   rawpoll_johnson <dbl>, rawpoll_mcmullin <dbl>, adjpoll_clinton <dbl>,
## #   adjpoll_trump <dbl>, adjpoll_johnson <dbl>, adjpoll_mcmullin <dbl>,
## #   trump_clinton_diff <dbl>

명령어 연결하기

polls_us_election_2016 %>%
    mutate(trump_clinton_diff = 
             rawpoll_trump - 
             rawpoll_clinton) %>%
    filter(trump_clinton_diff>5 &
           state == "Iowa" &
           is.na(rawpoll_johnson)) %>%
    select(pollster) # pollster(여론조사 기관) 열만 선택
## # A tibble: 3 × 1
##   pollster
##   <fct>   
## 1 Ipsos   
## 2 Ipsos   
## 3 Ipsos

명령어 연결하기

polls_us_election_2016 %>%
    mutate(trump_clinton_diff = 
             rawpoll_trump - 
             rawpoll_clinton) %>%
    filter(trump_clinton_diff>5 &
           state == "Iowa" &
           is.na(rawpoll_johnson)) %>%
    pull(pollster) # pollster(여론조사 기관) 열의 값을 추출하여 벡터로 반환
## [1] Ipsos Ipsos Ipsos
## 196 Levels: ABC News/Washington Post ... Zogby Interactive/JZ Analytics

다른 R 명령어에서도 사용 가능

polls_us_election_2016$samplesize %>% 
    mean(na.rm = TRUE) #samplesize 값들의 평균을 계산하되, NA(결측값)는 제거 
## [1] 1148.216
polls_us_election_2016 %>% 
    count() # 총 행 개수를 계산 (즉, 수행된 여론조사의 총 개수) 
## # A tibble: 1 × 1
##       n
##   <int>
## 1  4208
  • %>% 연산자는 magrittr 패키지에서 제공.
  • R v4.1.0부터 기본 제공(base) 파이프 연산자인 |> 추가
polls_us_election_2016$samplesize |> mean(na.rm = TRUE)
## [1] 1148.216

결측값(NA) 처리

  • 값이 누락(missing) 되었을 경우 NA로 표시됨.
x <- NA  # x에 결측값(NA) 할당
  • NA가 포함된 연산을 수행하면, 결과도 NA가 됨.
NA > 5    # NA는 숫자가 아니므로 비교 불가능 -> NA 반환
## [1] NA
NA + 10   # NA와 연산하면 결과도 NA
## [1] NA
  • is.na(x) 함수를 사용하면 값이 NA인지 확인 가능.
is.na(x)  # x가 NA인지 확인 -> TRUE 반환
## [1] TRUE
  • NA 값은 서로 비교할 수 없음.
NA == NA  # NA끼리 비교하면 결과도 NA
## [1] NA
  • 예제
# x는 Mary의 나이, 정확한 나이를 모름.
x <- NA

# y는 John의 나이, 정확한 나이를 모름.
y <- NA

# John과 Mary의 나이가 같은가?
x == y
## [1] NA
  • NA == NATRUE가 아니라 NA를 반환하는데, 이는 두 값이 같은지 여부를 판단할 수 없기 때문임.

Task 1

10:00

다음 코드를 실행하여 데이터를 로드합니다.

library(dslabs)
data(polls_us_election_2016)
  1. grade 값이 결측치(NA)인 여론조사는?

  2. 다음 조건을 모두 만족하는 여론조사는? (i) American Strategies, GfK Group, Merrill Poll에서 조사한 경우, (ii) 표본 크기가 1,000명 이상인 경우, (iii) 2016년 10월 20일에 시작된 경우. 힌트: (i) 조건에서는 %in% 연산자가 유용, 벡터는 c()함수로 만들 수 있음. (iii)에서는 날짜 변수의 형식을 확인 “yyyy-mm-dd”

  3. 다음 조건을 모두 만족하는 여론조사는? (i) Johnson 후보의 여론조사 데이터가 누락되지 않은 경우, (ii) 트럼프와 클린턴의 원본 여론조사 지지율 합이 95%를 초과하는 경우, (iii) 오하이오(OH) 주에서 실시된 경우 힌트: 트럼프와 클린턴의 지지율 합계를 계산하는 새로운 변수를 생성한 후 filter() 를 적용

  4. 표본 크기가 2,000명 이상인 여론조사에서 트럼프의 평균 지지율이 가장 높은 주는? 힌트: filter(), group_by(), summarise(), arrange() 사용. 내림차순 정렬하려면 arrange() 함수 사용.

금융 자료 다루기

if (!require("tidyquant")) install.packages("tidyquant")
if (!require("DT")) install.packages("DT")
if (!require("ggthems")) install.packages("ggthemes")
if (!require("highcharter")) install.packages("highcharter")

library(tidyquant)
library(DT)

apple_stock <- tq_get("AAPL", from="2010-01-01", to="2024-12-31")

# 일별 수익률 계산
apple_stock <- apple_stock %>% 
  arrange(date) %>%
  mutate(daily_return = adjusted / lag(adjusted) - 1)
head(apple_stock)

Visualising Data

기본 R 그래프와 ggplot2

  • ggplot2 (이 패키지는 tidyverse의 일부) 기본 R의 그래프 기능은 보다 훨씬 강력함

  • 예제를 실행하기 위해 gapminder 데이터셋 사용.

gapminder 개요

  • 먼저 gapminder 데이터를 로드:
library(dslabs) # dslabs 패키지 로드
data(gapminder, package = "dslabs") # gapminder 데이터셋 불러오기
  • 데이터의 처음 3개 행과 마지막 2개 행을 확인.
head(gapminder, n = 3) # 데이터의 처음 3행 출력
##   country year infant_mortality life_expectancy fertility population
## 1 Albania 1960            115.4           62.87      6.19    1636054
## 2 Algeria 1960            148.2           47.50      7.65   11124892
## 3  Angola 1960            208.0           35.98      7.32    5270844
##           gdp continent          region
## 1          NA    Europe Southern Europe
## 2 13828152297    Africa Northern Africa
## 3          NA    Africa   Middle Africa
tail(gapminder, n = 2) # 데이터의 마지막 2행 출력
##        country year infant_mortality life_expectancy fertility population gdp
## 10544   Zambia 2016               NA           57.10        NA         NA  NA
## 10545 Zimbabwe 2016               NA           61.69        NA         NA  NA
##       continent         region
## 10544    Africa Eastern Africa
## 10545    Africa Eastern Africa

Task 2

05:00

다음 코드를 실행하여 데이터를 로드합니다.

  1. 대륙/연도별 평균 인구(변수명: mean_pop)를 계산하고, 결과를 새로운 객체 gapminder_mean에 저장하시오. 힌트: 각 연도별 대륙당 하나의 관측치(행)만 있어야 함. group_bysummarise 사용

gg = Grammar of Graphics

Data

data %>%
  ggplot()

or

ggplot(data)
  • Tidy Data

    • 각 변수는 열(column)을 형성

    • 각 관측치는 행(row)을 형성

  • 시각화를 시작할 때 고려 사항

    • 시각화에서 어떤 정보를 사용할 것인가?

    • 해당 데이터가 하나의 열 또는 행에 포함되어 있는가?

gg = Grammar of Graphics

Data

Aesthetics

+ aes()

데이터를 시각적 요소 또는 매개변수에 매핑

  • year (연도)

  • population (인구)

  • country (국가)

gg = Grammar of Graphics

Data

Aesthetics

+ aes()

데이터를 시각적 요소 또는 매개변수에 매핑

  • year (연도) → x

  • population (인구) → y

  • country (국가) → shape, color, etc.

gg = Grammar of Graphics

Data

Aesthetics

+ aes()
aes(
  x = year,
  y = population,
  color = country
)

gg = Grammar of Graphics

Data

Aesthetics

Geoms

+ geom_*()

Geometric objects:

gg = Grammar of Graphics

Data

Aesthetics

Geoms

+ geom_*()

링크: 많이 사용되는 geoms

유형 함수
포인트 geom_point()
geom_line()
막대 그래프 geom_bar(), geom_col()
히스토그램 geom_histogram()
회귀선 geom_smooth()
박스플롯 geom_boxplot()
텍스트 geom_text()
수직/수평선 geom_{vh}line()
개수 세기 geom_count()
밀도 그래프 geom_density()

gg = Grammar of Graphics

Data

Aesthetics

Geoms

+ geom_*()

RStudio에서 geom_을 입력하면 자동 완성 기능을 통해 사용할 수 있는 모든 옵션 확인 가능

(Y)Our first plot!

gapminder_mean
## # A tibble: 285 × 3
## # Groups:   continent [5]
##    continent  year mean_pop
##    <fct>     <int>    <dbl>
##  1 Africa     1960 5464985.
##  2 Africa     1961 5598112.
##  3 Africa     1962 5736073.
##  4 Africa     1963 5878867.
##  5 Africa     1964 6026474.
##  6 Africa     1965 6178906.
##  7 Africa     1966 6336258.
##  8 Africa     1967 6498656.
##  9 Africa     1968 6666202.
## 10 Africa     1969 6839011.
## # ℹ 275 more rows

(Y)Our first plot!

gapminder_mean %>%
  ggplot() 

(Y)Our first plot!

gapminder_mean %>%
  ggplot() +
  aes(x = year, #<<
      y = mean_pop) #<<

(Y)Our first plot!

gapminder_mean %>%
  ggplot() +
  aes(x = year,
      y = mean_pop) +
  geom_point() #<<

(Y)Our first plot!

gapminder_mean %>%
  ggplot() +
  aes(x = year,
      y = mean_pop,
      color = continent) + #<<
  geom_point()

(Y)Our first plot!

gapminder_mean %>%
  ggplot() +
  aes(x = year,
      y = mean_pop,
      color = continent) +
  geom_point() +
  geom_line() #<<

(Y)Our first plot!

gapminder_mean %>%
  ggplot() +
  aes(x = year,
      y = mean_pop,
      color = continent) +
  # geom_point() + #<<
  geom_line()

(Y)Our first plot!

g = gapminder_mean %>% #<<
  ggplot() +
  aes(x = year,
      y = mean_pop,
      color = continent) +
  # geom_point() + 
  geom_line()
g   #<<
# graphs can be saved as
# objects!

gg = Grammar of Graphics

Data

Aesthetics

Geoms

Facet

+ facet_wrap() 
+ facet_grid()

gg = Grammar of Graphics

Data

Aesthetics

Geoms

Facet

+ facet_wrap() 
+ facet_grid()
g + facet_wrap(~ continent)

gg = Grammar of Graphics

Data

Aesthetics

Geoms

Facet

+ facet_wrap() 
+ facet_grid()
g + facet_grid(~ continent)

gg = Grammar of Graphics

Data

Aesthetics

Geoms

Facet

Labels

+ labs()
g + labs(x = "Year", y = "Average Population", color = "Continent")

gg = Grammar of Graphics

Data

Aesthetics

Geoms

Facet

Labels

Scales

+ scale_*_*()

scale + _ + <aes> + _ + <type> + ()

어떤 매개변수를 조정하고 싶은가? → <aes>

그 매개변수의 유형은 무엇인가? → <type>

  • 이산형(x축) 조정
    scale_x_discrete()
  • 연속형 변수에서 포인트 크기 조정
    scale_size_continuous()
  • y축을 로그 스케일로 변환
    scale_y_log10()
  • 색상 세팅 변환
    scale_fill_discrete()
    scale_color_manual()

gg = Grammar of Graphics

Data

Aesthetics

Geoms

Facet

Labels

Scales

+ scale_*_*()
g + scale_color_viridis_d()

gg = Grammar of Graphics

Data

Aesthetics

Geoms

Facet

Labels

Scales

+ scale_*_*()
g + scale_y_log10()

gg = Grammar of Graphics

Data

Aesthetics

Geoms

Facet

Labels

Scales

+ scale_*_*()
g + scale_x_continuous(breaks = seq(1950, 2020, 10))

ggplot 심화 탐구

Task 3

10:00

gapminder 데이터를 사용하여 다음의 그래프를 ggplot2로 생성하시오

  1. 2015년 기대수명(Life Expectancy)의 히스토그램을 작성하시오.
    힌트: 히스토그램을 만들 때 aes()에 y 값을 지정해야 할까? geom_* 내에서 다음 옵션을 설정하시오: binwidth = 5, boundary = 45, colour = “white”, fill = “#d90502”. x축은 “기대 수명”, y축은 “빈도”로 레이블 하시오.

    Optional: 생성한 히스토그램을 대륙(Continent)별로 나누어 (facet_grid()) 각 대륙이 새로운 행(row)에 표시되도록 만드시오. 힌트: facet_grid(rows = vars(continent))

  2. 연도/대륙별 평균 기대수명을 구하고 대륙별로 평균 기대수명에 대한 Boxplot 으로 그리시오. geom_* 옵션: colour = “black”, fill = “#d90502”.
    힌트: continent 및 year 두 개의 변수로 그룹화해야함.

  3. 2015년 출산율(Fertility Rate, y축)과 영아 사망률(Infant Mortality, x축) 간의 관계를 나타내는 산점도 (Scatter Plot)를 작성하시오. geom_* 옵션: size = 3, alpha = 0.5, colour = “#d90502”. labs()를 사용하여 레이블을 추가 (x = “영아 사망률”, y = “출산율”)

금융 자료 다루기

library(ggplot2)
library(ggthemes)

apple_stock %>% ggplot() + aes(x=date, y=adjusted) +
  geom_line(color="blue", linewidth=1) +
  labs(title="Apple Stock Prices", x="Date", y="Adjusted Close") +
  theme_economist()
library(highcharter)

highchart(type = "stock") |> 
  hc_add_series(apple_stock, type = "line", hcaes(x = date, y = adjusted), name = "Apple Price") |> 
  hc_add_series(apple_stock, type = "column", hcaes(x = date, y = volume), name = "Trading Volume", yAxis = 1) |> 
  hc_yAxis_multiples(
    list(title = list(text = "Stock Price")),
    list(title = list(text = "Trading Volume"), opposite = TRUE)
  ) |> 
  hc_title(text = "AAPL Stock Price and Trading Volume") |>
  hc_add_theme(hc_theme_ft())

Summarising

Summarising Data

  • 일반적으로 데이터를 시각화하거나 요약 통계를 통해 데이터를 분석을 시작.

  • 이제 요약 통계(summary statistics)를 살펴보겠음.

  • 특히, 중심 경향(central tendency)산포도(spread)를 중점적으로 다룰 것임.

Central Tendency

  • 평균 (Mean)

mean(x): x의 모든 값의 평균을 계산. \[\bar{x} = \frac{1}{N}\sum_{i=1}^N x_i\]

x <- c(1,2,2,2,2,100)  # 데이터 샘플
mean(x)  # 평균 계산
## [1] 18.16667
mean(x) == sum(x) / length(x)  # 평균 공식 확인
## [1] TRUE
  • 중앙값 (Median)

median(x): x의 값들 중 50%가 해당 값보다 작거나 같고, 50%가 크거나 같은 값을 찾음. \(m\)이 중앙값이라면: \[\Pr(X \leq m) \geq 0.5 \text{ 그리고 } \Pr(X \geq m) \geq 0.5\]

중앙값은 이상치(outliers)에 강건(robust).

median(x, echo=T)  # 중앙값 계산
## [1] 2

Spread

중심(평균)에서 얼마나 퍼져 있는지를 측정

분산(Variance)은 이러한 분포의 척도 중 하나

\[Var(X) = \frac{1}{N} \sum_{i=1}^N(x_i-\bar{x})^2\]

평균이 0인 두 개의 정규 분포를 비교해 보자.

분산 계산:

var(x)

Tabulating Data

  • table(x) 함수는 x 내 각 고유 값의 발생 횟수를 계산하는 데 유용.
table(gapminder$continent)
## 
##   Africa Americas     Asia   Europe  Oceania 
##     2907     2052     2679     2223      684
  • 동일한 작업을 dplyr의 count 함수를 사용하여 수행할 수도 있음.
gapminder %>% count(continent)
##   continent    n
## 1    Africa 2907
## 2  Americas 2052
## 3      Asia 2679
## 4    Europe 2223
## 5   Oceania  684

Tabulating Data

  • Contingency Table 생성
gapminder_new <- gapminder %>%
  filter(year == 2015) %>%
  mutate(fertility_above_2 = (fertility > 2)) # dummy variable for fertility rate above replacement rate
table(gapminder_new$fertility_above_2)
## 
## FALSE  TRUE 
##    73   111
table(gapminder_new$fertility_above_2,gapminder_new$continent)
##        
##         Africa Americas Asia Europe Oceania
##   FALSE      2       13   19     38       1
##   TRUE      49       22   28      1      11
  • prop.table을 사용하여 비율을 계산 가능:
# proportions by row
prop.table(table(gapminder_new$fertility_above_2,gapminder_new$continent), margin = 1)
##        
##              Africa    Americas        Asia      Europe     Oceania
##   FALSE 0.027397260 0.178082192 0.260273973 0.520547945 0.013698630
##   TRUE  0.441441441 0.198198198 0.252252252 0.009009009 0.099099099
# proportions by column
prop.table(table(gapminder_new$fertility_above_2,gapminder_new$continent), margin = 2) 
##        
##             Africa   Americas       Asia     Europe    Oceania
##   FALSE 0.03921569 0.37142857 0.40425532 0.97435897 0.08333333
##   TRUE  0.96078431 0.62857143 0.59574468 0.02564103 0.91666667
  • NA 값을 포함한 table 또는 crosstable을 얻으려면 useNA = "always" 또는 useNA = "ifany" 옵션을 사용

Tabulating Data

  • count 함수를 사용한 데이터 요약
gapminder_new %>%
  count(continent, fertility_above_2)
##    continent fertility_above_2  n
## 1     Africa             FALSE  2
## 2     Africa              TRUE 49
## 3   Americas             FALSE 13
## 4   Americas              TRUE 22
## 5   Americas                NA  1
## 6       Asia             FALSE 19
## 7       Asia              TRUE 28
## 8     Europe             FALSE 38
## 9     Europe              TRUE  1
## 10   Oceania             FALSE  1
## 11   Oceania              TRUE 11
  • count 함수는 NA 값이 포함된 경우에만 이를 표시.

공분산 (Covariance)과 상관계수 (Correlation)

ggplot(gapminder_new, aes(x=infant_mortality, y=fertility)) +
  geom_point(color="#d90502") +
  labs(
    title = "Relationship between fertility and infant mortality in 2015",
    x = "Infant mortality",
    y = "Fertility rate"
  ) +  theme_minimal()

Covariance

  • 공분산은 두 변수의 공동 변동성(joint variability) 을 측정하는 지표

    \[Cov(x,y) = \frac{1}{N} \sum_{i=1}^N(x_i-\bar{x})(y_i-\bar{y})\]

cov(gapminder_new$fertility,gapminder_new$infant_mortality, use = "complete.obs")
## [1] 24.21146

Correlation

  • 상관관계는 두 변수 간의 선형 관계(linear association) 의 강도를 측정하는 지표 \[Cor(x,y) = \frac{Cov(x,y)}{\sqrt{Var(x)}\sqrt{Var(y)}}\]
cor(gapminder_new$fertility,gapminder_new$infant_mortality, use = "complete.obs")
## [1] 0.8286402

Correlation

  • 상관계수는 항상 -1과 1 사이의 값을 가짐

[ Source: mathisfun]

Correlation

Task 4

10:00

  1. 2011년 GDP의 평균을 계산하고 mean이라는 객체에 할당하시오. 결측값은 제외. 힌트: mean 함수의 도움말을 읽고 NA를 제거하는 방법을 확인

  2. 2011년 GDP의 중앙값을 계산하고 median이라는 객체에 할당하시오. 마찬가지로 결측값을 제외. 중앙값이 평균보다 큰가, 작은가?

  3. geom_density를 사용하여 2011년 GDP의 밀도 그래프(density plot)를 생성하시오. 밀도 그래프는 숫자형 변수의 분포를 나타내는 방법임. 또한 다음 코드를 추가하여 평균과 중앙값을 수직선으로 표시하시오.

    geom_vline(xintercept = as.numeric(mean), colour = "red") +
    geom_vline(xintercept = as.numeric(median), colour = "orange")
  4. 2015년 출산율(fertility)과 유아 사망률(infant mortality)의 상관관계를 계산하시오. NA 값을 제외하려면 cor() 함수의 use 인수를 “pairwise.complete.obs”로 설정. 이 상관관계 값이 Task 3에서 생성한 그래프와 일치하는가?

🔍 인과 관계를 찾아가는 길

데이터를 어떻게 다룰까? : 읽기(Read), 정리(Tidy), 시각화(Visualize)…

❌ 변수 간 관계를 어떻게 요약할까? 단순 선형 회귀(Simple Linear Regression)

❌ 인과 관계(Causality)란 무엇인가?

❌ 전체 모집단을 관측하지 못하면 어떻게 할까?

❌ 우리의 연구 결과가 단순한 무작위(Randomness) 때문일 수도 있을까?

❌ 실제로 외생성을 어떻게 찾아낼 수 있을까?

THE END!