3장 데이터 탐색하기

이번 장에서는

지난 두 장에서 여러분은 데이터 사이언스 프로젝트의 범위와 목표를 설정하는 방법과 R 로 데이터를 불러오는 방법을 배웠다. 이번 장에서는 실제로 데이터를 활용하는 것에 대해 배울 것이다.

우리가 사용할 데이터는 ‘custdata.tsv’ 인데 두 가지 방법으로 불러올 수 있다.

# 데이터를 PDSwR Git 에서 바로 불러오기
custdata <- read.table("https://raw.githubusercontent.com/WinVector/zmPDSwR/master/Custdata/custdata.tsv", header = TRUE, sep = "\t")

# 첫 6줄을 불러와보자.
head(custdata)
##   custid sex is.employed income  marital.stat health.ins
## 1   2068   F          NA  11300       Married       TRUE
## 2   2073   F          NA      0       Married       TRUE
## 3   2848   M        TRUE   4500 Never Married      FALSE
## 4   5641   M        TRUE  20000 Never Married      FALSE
## 5   6369   F        TRUE  12000 Never Married       TRUE
## 6   8322   F        TRUE 180000 Never Married       TRUE
##                   housing.type recent.move num.vehicles age state.of.res
## 1     Homeowner free and clear       FALSE            2  49     Michigan
## 2                       Rented        TRUE            3  40      Florida
## 3                       Rented        TRUE            3  22      Georgia
## 4        Occupied with no rent       FALSE            0  22   New Mexico
## 5                       Rented        TRUE            1  31      Florida
## 6 Homeowner with mortgage/loan       FALSE            1  40     New York
# 다운 받은 GitHub 폴더에서 불러오기
custdata <- read.table("./Custdata/custdata.tsv", header = TRUE, sep = "\t")

# 첫 6줄을 불러와보자.
head(custdata)
##   custid sex is.employed income  marital.stat health.ins
## 1   2068   F          NA  11300       Married       TRUE
## 2   2073   F          NA      0       Married       TRUE
## 3   2848   M        TRUE   4500 Never Married      FALSE
## 4   5641   M        TRUE  20000 Never Married      FALSE
## 5   6369   F        TRUE  12000 Never Married       TRUE
## 6   8322   F        TRUE 180000 Never Married       TRUE
##                   housing.type recent.move num.vehicles age state.of.res
## 1     Homeowner free and clear       FALSE            2  49     Michigan
## 2                       Rented        TRUE            3  40      Florida
## 3                       Rented        TRUE            3  22      Georgia
## 4        Occupied with no rent       FALSE            0  22   New Mexico
## 5                       Rented        TRUE            1  31      Florida
## 6 Homeowner with mortgage/loan       FALSE            1  40     New York

특히 데이터의 양이 많을 때, 데이터셋을 먼저 깊이 살펴보지 않고 바로 모델링 단계로 가고 싶다는 생각이 클 것이다. 그 욕망을 뿌리쳐야한다. 완벽한 데이터는 없다. 일부 고객에 대한 정보가 없을 수도 있고, 잘못된 데이터를 갖고 있을 수도 있다. 어떤 데이터 필드는 지저분하고, 일관적이지 않을 수도 있다. 모델링을 하기 전에 데이터를 살펴보지 않으면, 모델링 이전 단계에 변환되어야할 데이터 필드나 변수를 발견할 때마다 같은 작업을 반복해야할 것이다. 최악의 경우에는 잘못된 예측 결과를 내는 모델을 만들 수도 있는데, 그 이유조차 모를 수도 있다. 데이터 문제를 초기에 발견함으로써 여러분은 불필요한 작업과 골치 아픈 일을 겪지 않아도 될 것이다.

이번 장에서는 여러분의 데이터를 더 잘 알아보기 위한 방법을 배울 것이며, 탐색을 하면서 발견할 수도 있는 잠재적인 문제에 대해서도 이야기할 것이다. 데이터 탐색은 평균, 중위수, 분산, 빈도 등의 요약 통계량과 그래프와 같은 시각화를 같이 사용해서 할 것이다.

3.1 요약 통계량을 사용해서 문제 찾아내기

R 에서는 주로 summary() 함수를 이용해서 데이터를 우선 살펴본다.

summary(custdata)
##      custid        sex     is.employed         income      
##  Min.   :   2068   F:440   Mode :logical   Min.   : -8700  
##  1st Qu.: 345667   M:560   FALSE:73        1st Qu.: 14600  
##  Median : 693403           TRUE :599       Median : 35000  
##  Mean   : 698500           NA's :328       Mean   : 53505  
##  3rd Qu.:1044606                           3rd Qu.: 67000  
##  Max.   :1414286                           Max.   :615000  
##                                                            
##              marital.stat health.ins     
##  Divorced/Separated:155   Mode :logical  
##  Married           :516   FALSE:159      
##  Never Married     :233   TRUE :841      
##  Widowed           : 96                  
##                                          
##                                          
##                                          
##                        housing.type recent.move      num.vehicles  
##  Homeowner free and clear    :157   Mode :logical   Min.   :0.000  
##  Homeowner with mortgage/loan:412   FALSE:820       1st Qu.:1.000  
##  Occupied with no rent       : 11   TRUE :124       Median :2.000  
##  Rented                      :364   NA's :56        Mean   :1.916  
##  NA's                        : 56                   3rd Qu.:2.000  
##                                                     Max.   :6.000  
##                                                     NA's   :56     
##       age              state.of.res
##  Min.   :  0.0   California  :100  
##  1st Qu.: 38.0   New York    : 71  
##  Median : 50.0   Pennsylvania: 70  
##  Mean   : 51.7   Texas       : 56  
##  3rd Qu.: 64.0   Michigan    : 52  
##  Max.   :146.7   Ohio        : 51  
##                  (Other)     :600

데이터 프레임에 summary() 함수를 사용하면 데이터 프레임 내의 수치형 자료에 대한 다양한 요약 통계량을 제공하며, 범주형 자료에 대해서는 빈도 통계량을 제공한다(범주형 자료가 미리 factor 로 불러 들여왔을 때). 위에서 알 수 있다시피, 데이터의 요약 통계량을 보면 결측값이나 이상한 값 같은 잠재적으로 문제가 될 수 있는 데이터를 빠르게 파악할 수 있다. 뿐만 아니라 범주형 자료의 분포도 파악이 가능하다.

3.1.1 데이터 요약으로 발견이 가능한 전형적인 문제점들

이번 단계에서는 결측치, 나올 수 없는 값, 이상치, 그리고 너무 넓거나 좁은 데이터의 범위 등 몇 가지 일반적인 문제들에 대해 살펴볼 것이다.

결측치

많지 않은 결측치는 큰 문제는 아닐지 모르지만, 특정 필드에서 많은 데이터가 빠져있다면 이를 해결하기 전에는 모델링에는 사용해서는 안 될 것이다(4장 4.1.1절에서도 다룰 예정이다).

특정 데이터 필드에서 많은 값이 빠져있다면, 그 이유를 알아내는 것도 의미 있을 것이다. 때로는 결측치가 있다는 것 자체만으로도 가치 있을 때도 있다. 예를 들어 is.employed 변수에 결측값이 많은 이유는 무엇일까?

그 이유가 무엇이건 간에 가장 적절한 조치가 어떤 것인지 결정을 해야한다. 여러분의 모형에 결측치가 있는 변수를 포함할 것인가, 말 것인가? 포함하는 것으로 결정했다면, 결측치를 포함한 행은 없앨 것인가, 아니면 이를 0이나 다른 범주로 바꿀 것인가? 결측치를 다루는 방법에 대해서는 4장에서 다룰 예정이다. 이 데이터에서는 주거 형태나 차량 변수에서는 결측치를 포함한 데이터가 많지는 않기 때문에 데이터를 삭제할 것이다. 하지만 고용 형태 변수에서는 1/3 의 데이터가 결측치이기 때문에 그럴 수는 없고, 이를 또 다른 카테고리로 만들 것이다. 모형 평가에서 결측치를 만날 가능성이 높기 때문에 모형 학습 단계에서 처리해주어야만 한다.

유효하지 않은 값과 이상치

비록 행이나 열에 결측치가 없더라도, 해당하는 값들이 유효한 것인지에 대해서는 살펴봐야 한다. 유효하지 않은 값이나 이상치는 없는가? 유효하지 않은 값이란 양수만 들어 있어야 하는 곳에 음수가 있거나, 숫자만 있어야 하는데 다른 것이 있다거나 하는 것을 의미한다. 이상치는 여러분이 생각하는 값의 범위를 크게 벗어난 값을 의미한다.

종종 유요하지 않은 값들은 단순한 입력 오류일 때가 있다. 나이와 같은 필드에 음수가 들어있는 경우가 그것인데, 가끔은 “알 수 없음”을 나타내는 값으로 미리 정해놓은 sentinel value 일 수도 있다. 이상치 또한 데이터 오류나 sentinel value 일 수도 있다. 또는 유효하지만 일반적이지 않을 값일 수도 있다.

데이터의 범위

데이터의 값이 얼마나 다른 지에 대해서도 주의를 기울여야한다. 만약 나이나 수입이 건강 보험 가입 여부를 예측하는 데에 도움이 된다고 생각한다면, 그 관계를 파악하기 위해서 여러분이 가지고 있는 고객 데이터에서 나이와 수입이 충분히 변화가 있는지를 확인해야 한다.

# 수입의 범위 확인하기
summary(custdata$income)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   -8700   14600   35000   53505   67000  615000

-8700 을 빼더라도 0부터 615000 이라는 값은 꽤나 넓다고 할 수 있다. 이처럼 데이터의 범위가 여러 자릿수가 차이가 나는 경우에는 일부 모델링 방법에서는 문제를 일으킬 수 있다. 데이터 범위 문제를 해결하는 방법에 대해서는 4장에서 로그 변환에 대해 이야기하면서 다루기로 하자.

또한 데이터의 범위는 굉장히 좁을 수도 있다. 그렇다면 얼마나 좁은 것이 “너무 좁은” 것일까? 이를 판단하기 위해서는 문제의 전문 영역에 대한 정보에 의존해야 하지만, 간단한 방법으로는 산술 평균에 대한 표준 편차의 비율이 있다. 그 값이 매우 작으면 데이터가 적게 퍼져있다는 뜻이다. 데이터의 범위에 대해서는 3.2절에서 그래프를 통해 데이터를 살펴보면서 다시 다루도록 하자.

단위

# $1,000 단위로 수입 변환하기
Income <- custdata$income / 1000

summary(Income)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    -8.7    14.6    35.0    53.5    67.0   615.0

위의 수입 자료는 시급일까 아니면 $1,000 단위로 표시된 연봉일까? 사실 후자이지만, 만약에 전자로 생각했다면 어떻게 되었을까? 모델링 단계에서는 큰 문제가 발생하지 않겠지만, 이후에 누군가가 시급을 입력한다면 정확하지 않은 예측값을 반환할 것이다. 특히 단위에 대한 것은 자료 자체보다는 데이터 사전이나 문서에서 데이터의 정의를 살펴봐야 알 수 있는 것이다. 크게 중요하지 않다고 생각할 수도 있지만, 가끔 가다가 잘 사용하지 않는 단위를 마주치는 경우도 있으니 유의하도록 하자.

주로 사용하는 요약 통계량에 대한 함수

# 합계
sum(Income, na.rm = TRUE)
## [1] 53504.77
# 평균
# 산술평균
mean(Income, na.rm = TRUE) # na.rm 은 NA 값을 계산에 포함하지 않겠다는 argument
## [1] 53.50477
# 중앙값
median(Income)
## [1] 35
# 산포
# IQR(Inter Quantile Range)
IQR(Income)
## [1] 52.4
# 분산(Variance)
var(Income)
## [1] 4287.377
# 표준편차(Standard Deviation)
sd(Income)
## [1] 65.47807

자료 구조에 대한 함수

# 자료의 차원(dimension)
dim(custdata)
## [1] 1000   11
# 자료의 길이
length(Income)
## [1] 1000
# 클래스(Class)
class(custdata)
## [1] "data.frame"
class(Income)
## [1] "numeric"
# 타입(Type)
typeof(custdata)
## [1] "list"
typeof(Income)
## [1] "double"
# 저장 모드(Storage Mode)
mode(custdata)
## [1] "list"
mode(Income)
## [1] "numeric"

3.2 도표와 시각화를 이용해서 문제 발견하기

데이터의 요약 통계량으로 발견할 수 있는 문제들도 많지만, 데이터의 특성들 중에는 숫자보다 그림으로 보는 것이 더 나은 것도 있다.

겨우 몇 가지 숫자만으로 데이터에 존재하는 정보의 가치를 지속적으로 보여주기는 어렵다. 숫자로 축약된 방법에는 데이터에 있는 정보는 담겨있지 않다. - 윌리엄 클리블랜드

나이의 최빈값과 같은 정보나, 또 하위 분포의 존재 여부, 그리고 이상치의 존재 여부는 글로 쓰여진 것보다는 시각적으로 받아들이는 편이 훨씬 용이하다.

도표를 이용해서 데이터를 살펴보는 것을 시각화라고 부른다. 클리랜드의 철학의 중요한 점은 다음과 같다:

  • 도표는 보는 사람이 높은 인지력이 없더라도 알 수 있도록 최대한 많은 정보를 보여주어야 한다.
  • 명확성을 위해 항상 노력하라. 데이터가 돋보이게 만들어라. 이를 위한 팁을 주자면,
    • 너무 많은 요소들을 겹쳐서 나타내는 것을 피하라.
    • 데이터의 세부 정보를 제대로 보여줄 수 있는 화면비와 비율을 찾아라.
    • 데이터가 그래프의 한 쪽으로 치우치게 만드는 것을 피하라.
  • 시각화는 반복적인 작업이다. 그 목적은 데이터에 관련된 질문에 답하는 것이다.

시각화 단계에서는 데이터를 그림으로 나타내고, 배울 수 있는 것을 배우고, 이전의 그래프에서 나온 질문들에 대답하기 위해 다시 그림을 그린다. 다른 질문에 대답하기 위해서는 다른 그래프를 이용하는 것이 최선이다.

ggplot2 의 특징

이 절의 주제는 데이터를 탐구하기 위해 시각화를 사용하는 방법에 대한 것이지 ggplot2 를 사용하는 방법이 아니다. 예제 코드를 보면서 다음과 같은 것들을 이해하기 위한 중요 포인트들은 다음과 같다.

  • ggplot2 의 그래프는 데이터프레임에만 적용할 수 있다. 그래프에서의 변수들, x 변수, y 변수, 색을 지정하거나, 점의 크기를 정하는 변수 등은 asthetics 라고 불리며, aes 함수를 이용해서 선언한다.
  • ggplot() 함수는 그래프 오브젝트를 선언한다. ggplot() 에서의 인자들은 사용하고자 하는 데이터프레임과 aesthetics 를 포함한다. ggplot() 함수는 자체만으로 그래프를 만들어내지 못하며, 그래프는 layers 에서 만들어진다.
  • 레이어들은 도표와, 도표를 바꾸는 것을 만들어 내고, + 연산자를 이용해서 주어진 그래프 오브젝트에 추가된다. 각 레이어 또한 도표에 특화된 파라미터뿐만 아니라 데이터프레임과 미적 요소를 인자로 받을 수 있다.

3.2.1 한 변수에 대한 분포를 시각적으로 확인하기

이번 절에서 살펴볼 시각화는 다음과 같은 질문에 답을 할 수 있도록 도와준다:

  • 분포에서의 최빈값은 무엇인가?
  • 분포에 최빈값은 몇 개인가(unimodal 인가 bimodal 인가)?
  • 데이터가 얼마나 정규분포(로그 변환한 정규분포)와 비슷한가? 정규분포와 로그 변환 한 정규분포에 대해서는 부록 B에서 다루도록 하자.
  • 데이터가 얼마나 많이 퍼져있는가? 특정 구간이나 집단에 집증되어 있는가?

시각적으로 파악하는 것이 더 쉬운 것 중 하나는 데이터 분포의 모양이다. 많은 요약 통계량은 데이터가 근사적으로 정규분포에 가깝다고(최소한 연속형 변수들에 대해서는) 가정을 하고 있기 때문에 실제로 그런지 확인하고 싶을 것이다.

그림 3.2에서 살펴보면, 회색 곡선은 봉우리가 하나 혹은 단봉형인 것을 확인 할 수 있다. 이는 데이터에서 확인하고자 하는 특성 중의 하나이다. (간단히 말해서) 단봉평 분포는 대상의 한 모집단에 대응하기 때문이다. 그림 3.2에서 고객의 평균 연령은 52세 정도이며, 50%의 고객은 38세와 64세 사이에 있다. 그림 3.2에서 검은 곡선은 봉우리가 두 개, 또는 양봉형 분포라고 부른다. 이 고객 집단 또한 회색 집단의 고객과 비슷한 평균 연령을 가지고는 있지만, 분포 자체는 전혀 다르다. 검은색 곡선의 집단은 (과장을 하자면) 대부분 2-30대인 조금 젊은 모집단과, 대부분은 70대인 모집단에 대응한다. 이 두 집단은 서로 다른 행동 패턴을 가지고 있을 가능성이 크고, 모델링을 할 때에도 다른 모델을 사용하는 것이 훨씬 더 나을 것이다.

히스토그램과 확률밀도도표는 수치형 변수의 분포를 빠르게 살펴볼 수 있도록 도와주는 시각화 방법이다.

히스토그램(Histogram)

  • 기본적인 히스토그램은 정해진 너비의 구간에 변수들을 묶고, 이 구간에 포함되는 변수의 갯수를 반환한다. 히스토그램의 가장 큰 단점 중 하나는 구간의 크기를 미리 결정해야한다는 것이다. 구간의 크기가 너무 작으면 데이터의 분포를 제대로 알 수 없고, 너무 작으면 정보의 수준이 너무 낮아서 오히려 가독성이 떨어질 것이다. 또 다른 시각화 방법은 확률밀도도표가 있다.
library(ggplot2)

ggplot(custdata) +
    geom_histogram(aes(x = age), binwidth = 5, fill = "gray")

확률밀도도표

확률밀도도표는 한 변수에 대한 “연속형 히스토그램”이라고 여길 수 있는데, 다만 확률밀도도표의 곡선 아래 면적의 합은 1이다. 확률밀도도표의 한 점은 데이터의 비율과 같다. 데이터의 범위가 굉장히 넓고, 대부분의 데이터가 한쪽으로 치우쳐져있다면 모양에 대한 자세한 정보를 얻기가 힘들어진다. 데이터가 양수값을 가진다면 그림을 로그 스케일로 그리는 것도 하나의 좋은 방법이다. 두 번째 도표에서 ggplot2 가 알아서 음수값과 0 값을 제외하고 도표를 그려줬으니 이를 염두에 두고 그래프를 해석하자.

로그 스케일은 언제 사용해야할까?

절대적인 단위에서의 변화보다 비율 변화, 또는 자릿수의 변화가 더 중요할 때 로그 스케일을 사용해야 한다. 그리고 한쪽으로 크게 치우진 데이터를 더 보기 좋기 만들 때에도 로그 스케일을 사용하는 것이 좋다.

library(scales) # the scales package brings in the dollar scale notation

# Density plot of income
ggplot(custdata) +
    geom_density(aes(x = income)) +
    scale_x_continuous(labels = dollar)

# Density plot of income in logarithm scale
ggplot(custdata) +
    geom_density(aes(x = log10(income))) +
    scale_x_continuous(breaks = c(100, 1000, 10000, 100000), labels = dollar) +
    annotation_logticks(sides = "bt")
## Warning in FUN(X[[i]], ...): NaNs produced
## Warning: Removed 79 rows containing non-finite values (stat_density).

막대 그래프

막대 그래프는 이산형 데이터를 위한 히스토그램이다. 이는 범주형 변수의 각 값에 대한 빈도를 기록한다. 아래 그림은 고객 데이터(custdata)에서 결혼 상태 변수의 분포를 보여준다.

# Plot the marital status
ggplot(custdata) +
    geom_bar(aes(x = marital.stat), fill = "gray")

# Plot the state of residence horizontally
ggplot(custdata) +
    geom_bar(aes(x = state.of.res), fill = "gray") +
    coord_flip() +
    theme(axis.text.y = element_text(size = rel(0.8)))

3.2.2 두 변수의 관계를 시각적으로 확인하기

이 단계에서는 다음과 같은 질문들에 대한 해답을 알아보려고 한다.

  • 데이터에 있는 두 변수들 사이에 관계가 있는가?
  • 어떤 종류의 관계이고 그 크기는 어느 정도인가?

모델링 단계에서 이를 정확하게 수량화할 수 있겠지만, 지금 이를 탐색함으로써 어떤 변수들을 모델에 포함하는 것이 가장 적절한지를 알 수도 있다.

우선, 두 연속형 변수들 간의 관계를 생각해보자. 가장 명백한(하지만 항상 최선이지만은 않은) 방법은 선도표이다.

선도표(line plot)

선도표는 두 변수들 사이의 관계가 각 x 값이 고유한(또는 거의 고유한) y 값을 가지고 있을 때와 같이 상대적으로 깔끔할 때 가장 유용하다. 그렇지 않을 때는 상대적으로 유용성이 떨어진다.

x <- runif(100)
y <- x ^ 2 + 0.2 * x 

ggplot(data = data.frame(x = x, y = y), aes(x = x, y = y)) +
    geom_line()

산포도와 평활화 곡선

고객 데이터에서 나이와 건강보험 가입 여부, 그리고 수입과 건강 보험 가입 여부에 관계가 있다고 생각할 수 있다. 그렇다면 나이와 수입의 관계는 어떨까? 둘이 완벽히 같다는 관계가 있다면, 모델링에 두 변수를 모두 사용하지 않는게 보다 적절할 것이다. 이를 알아볼 수 있는 알맞은 요약 통계량은 상관관계이다.

산점도를 그려보고, 직선의 평활화 곡선을 그려보았지만 데이터에 잘 맞는다고는 볼 수 없다. 그래서 loess(lowess; Locally Weighted Scatterplot Smoothing) 을 사용해서 적합을 해보자.

# Calculate correlation between age and income
custdata2 <- subset(custdata,
                    (custdata$age > 0 & custdata$age < 100
                     & custdata$income > 0))

cor(custdata2$age, custdata2$income)
## [1] -0.02240845
# Draw a scatter plot on age and income
ggplot(custdata2, aes(x = age, y = income)) +
    geom_point() +
    ylim(0, 200000)
## Warning: Removed 32 rows containing missing values (geom_point).

# Add a linear smoothing curve
ggplot(custdata2, aes(x = age, y = income)) +
    geom_point() +
    stat_smooth(method = "lm") +
    ylim(0, 200000)
## Warning: Removed 32 rows containing non-finite values (stat_smooth).

## Warning: Removed 32 rows containing missing values (geom_point).

# Add a loess(lowess) smoothing curve
ggplot(custdata2, aes(x = age, y = income)) +
    geom_point() +
    stat_smooth() +
    ylim(0, 200000)
## `geom_smooth()` using method = 'loess'
## Warning: Removed 32 rows containing non-finite values (stat_smooth).

## Warning: Removed 32 rows containing missing values (geom_point).

# Plot health.ins and age
ggplot(custdata2, aes(x = age, y = as.numeric(health.ins))) +
    geom_point(position = position_jitter(w = 0.05, h = 0.05)) +
    stat_smooth()
## `geom_smooth()` using method = 'loess'

우리가 가지고 있는 건강 보험 데이터는 레코드가 많지 않아서 산점도를 읽기가 어렵지 않지만, 데이터의 갯수가 엄청나게 많아지면 이를 파악하는 것이 훨씬 더 어려워질 것이다. 그런 경우에 hexbin 도표와 같은 것들을 사용할 수 있다.

Hexbin 도표

Hexbin 도표는 2차원 히스토그램과 같다고 할 수 있다. 데이터는 구간별로 나눠지고, 각 구간에 있는 데이터의 갯수는 색깔이나 음영으로 나타낸다.

library(hexbin)
## Warning: package 'hexbin' was built under R version 3.4.4
ggplot(custdata2, aes(x = age, y = income)) +
    geom_hex(binwidth = c(5, 10000)) +
    geom_smooth(color = "white", se = FALSE) +
    ylim(0, 200000)
## Warning: Removed 32 rows containing non-finite values (stat_binhex).
## `geom_smooth()` using method = 'loess'
## Warning: Removed 32 rows containing non-finite values (stat_smooth).
## Warning: Removed 13 rows containing missing values (geom_hex).

두 범주형 변수들을 위한 막대 도표

가장 기본적인 형태는 범주들을 쌓아 놓은 stacked bar chart 이고, 선호에 따라 범주들을 옆에다가 배치한 side-by-side bar chart 로 만들 수도 있다. 하지만 이 두 도표의 큰 단점은 한 범주별 다른 범주에 대한 비율을 비교하기가 쉽지 않다는 것이다. 그래서 filled bar chart 를 사용하면 이를 극복할 수 있지만, 전체에서 한 범주가 차지하는 비율에 대한 정보는 잃게 된다. 이에 대한 추가 정보는 rug 라는 것을 이용해 x 축에 온 변수의 분포를 그래프 아래에 표현함으로써 극복할 수 있다.

# Stacked bar chart
ggplot(custdata, aes(x = marital.stat, fill = health.ins)) +
    geom_bar()

# Side-by-side bar chart
ggplot(custdata, aes(x = marital.stat, fill = health.ins)) +
    geom_bar(position = "dodge")

# Filled bar chart
ggplot(custdata, aes(x = marital.stat, fill = health.ins)) +
    geom_bar(position = "fill")

# Add a rug
ggplot(custdata, aes(x = marital.stat, fill = health.ins)) +
    geom_bar(position = "fill") +
    geom_point(aes(y = -0.05), size = 0.75, alpha = 0.3,
               position = position_jitter(h = 0.01))

ggplot 에서 자주 사용하는 기능 중 하나는 facet 이라는 것이 있는데, 범주형 변수의 값별로 그래프를 따로 만드는 기능이다. 이를 이용하기 위해 주거 상태(housing.type)에 대한 결혼 상태(marital.stat) 를 나타내는 막대 도표를 그려보자.

# A bar chart without facets
ggplot(custdata2, aes(x = housing.type, fill = marital.stat)) +
    geom_bar(position = "dodge") +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

# A barchart with facets
ggplot(custdata2, aes(x = marital.stat)) +
    geom_bar(position = "dodge") +
    facet_wrap(~ housing.type, scales = "free_y") +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

두 변수를 나타내는 시각화 방법

그래프 형태 사용법
선 도표 두 연속형 변수들 사이의 관계를 보여줌. 함수형태로 나타낼 수 있을 떄 가장 좋음.
산점도 두 연속형 변수들 사이의 관계를 보여줌. 선 도표로 쉽게 확인하기 위해서는 관계가 느슨하거나 구름처럼 보일 때 가장 좋음.
평활화 곡선 두 연속형 변수들 사이에 숨겨져있는 “평균”적인 관계나 경향을 보여줌. 연속형 변수와 이항변수 사이의 관계를 보여주는 데에도 사용 가능
Hexbin 도표 데이터의 밀집도가 높을 때 두 연속형 변수의 관계를 보여줄 때 사용 가능.
쌓은 막대 도표 두 범주형 변수들 사이의 관계를 보여줌. 한 변수의 빈도에 집중함.
나열한 막대 도표 두 범주형 변수들 사이의 관계를 보여줌. 변수2의 빈도를 변수1의 값에 따라 비교하기에 좋음. 변수2가 이항형일 때 가장 유용함.
채운 막대 도표 두 범주형 변수들 사이의 관계를 보여줌. 변수2의 상대 비율를 변수1의 값에 따라 비교하기에 좋음. 변수2가 이항형일 때 가장 유용함.
펼쳐놓은 막대 도표 두 범주형 변수들 사이의 관계를 보여줌. 변수2의 빈도를 변수1의 값에 따라 비교하기에 좋음. 변수2의 값이 3개 이상일 때 가장 유용함.

3.3 요약

이제 요약 통계량과 시각화에 대해 살펴보았다. 이제 데이터의 질과 변수들 간의 관계에 대해 어느 정도 감을 잡았을 것이다. 비록 작업을 진행하면서 더 많은 문제에 닥칠 가능성이 높긴 하지만, 어느 정도의 문제에 대해서는 해결 방법에 대해 배웠다.

이전 장에서도 언급했다시피, 데이터 사이언스 프로세스는 끊임없는 반복으로 이루어져있다. 데이터 탐색과 데이터 정제 단계(는 다음 장에서 다룰 예정이다)는 다른 단계에 비해 시간을 많이 잡아먹긴 하지만, 가장 중요한 단계이기도 하다. 좋은 데이터 없이는 좋은 모델을 만들 수 없다. 이 단계에서 보낸 시간만큼 다른 곳에서 낭비할 시간이 줄어들 것이다.

이번 장에서 얻어가야 할 것

- 모델링에 뛰어들기 전에 데이터를 살펴보는 시간을 갖자.
- `summary` 함수는 데이터 범위, 단위, 타입, 그리고 결측치나 유효하지 않은 값 등에 대한 문제를 찾을 수 있도록 도와준다.
- 시각화는 데이터의 분포와 변수들 간의 관계에 대한 추가적인 정보를 제공해준다.
- 시각화는 반복적인 과정이며, 데이터에 관련된 질문에 대한 답을 할 수 있도록 도와준다. 이 단계에서 보낸 시간만큼 모델링 단계에서 절약하게 될 것이다.