이번 장에서는
지난 두 장에서 여러분은 데이터 사이언스 프로젝트의 범위와 목표를 설정하는 방법과 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
특히 데이터의 양이 많을 때, 데이터셋을 먼저 깊이 살펴보지 않고 바로 모델링 단계로 가고 싶다는 생각이 클 것이다. 그 욕망을 뿌리쳐야한다. 완벽한 데이터는 없다. 일부 고객에 대한 정보가 없을 수도 있고, 잘못된 데이터를 갖고 있을 수도 있다. 어떤 데이터 필드는 지저분하고, 일관적이지 않을 수도 있다. 모델링을 하기 전에 데이터를 살펴보지 않으면, 모델링 이전 단계에 변환되어야할 데이터 필드나 변수를 발견할 때마다 같은 작업을 반복해야할 것이다. 최악의 경우에는 잘못된 예측 결과를 내는 모델을 만들 수도 있는데, 그 이유조차 모를 수도 있다. 데이터 문제를 초기에 발견함으로써 여러분은 불필요한 작업과 골치 아픈 일을 겪지 않아도 될 것이다.
이번 장에서는 여러분의 데이터를 더 잘 알아보기 위한 방법을 배울 것이며, 탐색을 하면서 발견할 수도 있는 잠재적인 문제에 대해서도 이야기할 것이다. 데이터 탐색은 평균, 중위수, 분산, 빈도 등의 요약 통계량과 그래프와 같은 시각화를 같이 사용해서 할 것이다.
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 로 불러 들여왔을 때). 위에서 알 수 있다시피, 데이터의 요약 통계량을 보면 결측값이나 이상한 값 같은 잠재적으로 문제가 될 수 있는 데이터를 빠르게 파악할 수 있다. 뿐만 아니라 범주형 자료의 분포도 파악이 가능하다.
이번 단계에서는 결측치, 나올 수 없는 값, 이상치, 그리고 너무 넓거나 좁은 데이터의 범위 등 몇 가지 일반적인 문제들에 대해 살펴볼 것이다.
많지 않은 결측치는 큰 문제는 아닐지 모르지만, 특정 필드에서 많은 데이터가 빠져있다면 이를 해결하기 전에는 모델링에는 사용해서는 안 될 것이다(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"
데이터의 요약 통계량으로 발견할 수 있는 문제들도 많지만, 데이터의 특성들 중에는 숫자보다 그림으로 보는 것이 더 나은 것도 있다.
겨우 몇 가지 숫자만으로 데이터에 존재하는 정보의 가치를 지속적으로 보여주기는 어렵다. 숫자로 축약된 방법에는 데이터에 있는 정보는 담겨있지 않다. - 윌리엄 클리블랜드
나이의 최빈값과 같은 정보나, 또 하위 분포의 존재 여부, 그리고 이상치의 존재 여부는 글로 쓰여진 것보다는 시각적으로 받아들이는 편이 훨씬 용이하다.
도표를 이용해서 데이터를 살펴보는 것을 시각화라고 부른다. 클리랜드의 철학의 중요한 점은 다음과 같다:
시각화 단계에서는 데이터를 그림으로 나타내고, 배울 수 있는 것을 배우고, 이전의 그래프에서 나온 질문들에 대답하기 위해 다시 그림을 그린다. 다른 질문에 대답하기 위해서는 다른 그래프를 이용하는 것이 최선이다.
이 절의 주제는 데이터를 탐구하기 위해 시각화를 사용하는 방법에 대한 것이지 ggplot2 를 사용하는 방법이 아니다. 예제 코드를 보면서 다음과 같은 것들을 이해하기 위한 중요 포인트들은 다음과 같다.
ggplot2 의 그래프는 데이터프레임에만 적용할 수 있다. 그래프에서의 변수들, x 변수, y 변수, 색을 지정하거나, 점의 크기를 정하는 변수 등은 asthetics 라고 불리며, aes 함수를 이용해서 선언한다.ggplot() 함수는 그래프 오브젝트를 선언한다. ggplot() 에서의 인자들은 사용하고자 하는 데이터프레임과 aesthetics 를 포함한다. ggplot() 함수는 자체만으로 그래프를 만들어내지 못하며, 그래프는 layers 에서 만들어진다.+ 연산자를 이용해서 주어진 그래프 오브젝트에 추가된다. 각 레이어 또한 도표에 특화된 파라미터뿐만 아니라 데이터프레임과 미적 요소를 인자로 받을 수 있다.이번 절에서 살펴볼 시각화는 다음과 같은 질문에 답을 할 수 있도록 도와준다:
시각적으로 파악하는 것이 더 쉬운 것 중 하나는 데이터 분포의 모양이다. 많은 요약 통계량은 데이터가 근사적으로 정규분포에 가깝다고(최소한 연속형 변수들에 대해서는) 가정을 하고 있기 때문에 실제로 그런지 확인하고 싶을 것이다.
그림 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)))
이 단계에서는 다음과 같은 질문들에 대한 해답을 알아보려고 한다.
모델링 단계에서 이를 정확하게 수량화할 수 있겠지만, 지금 이를 탐색함으로써 어떤 변수들을 모델에 포함하는 것이 가장 적절한지를 알 수도 있다.
우선, 두 연속형 변수들 간의 관계를 생각해보자. 가장 명백한(하지만 항상 최선이지만은 않은) 방법은 선도표이다.
선도표(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개 이상일 때 가장 유용함. |
이제 요약 통계량과 시각화에 대해 살펴보았다. 이제 데이터의 질과 변수들 간의 관계에 대해 어느 정도 감을 잡았을 것이다. 비록 작업을 진행하면서 더 많은 문제에 닥칠 가능성이 높긴 하지만, 어느 정도의 문제에 대해서는 해결 방법에 대해 배웠다.
이전 장에서도 언급했다시피, 데이터 사이언스 프로세스는 끊임없는 반복으로 이루어져있다. 데이터 탐색과 데이터 정제 단계(는 다음 장에서 다룰 예정이다)는 다른 단계에 비해 시간을 많이 잡아먹긴 하지만, 가장 중요한 단계이기도 하다. 좋은 데이터 없이는 좋은 모델을 만들 수 없다. 이 단계에서 보낸 시간만큼 다른 곳에서 낭비할 시간이 줄어들 것이다.
이번 장에서 얻어가야 할 것
- 모델링에 뛰어들기 전에 데이터를 살펴보는 시간을 갖자.
- `summary` 함수는 데이터 범위, 단위, 타입, 그리고 결측치나 유효하지 않은 값 등에 대한 문제를 찾을 수 있도록 도와준다.
- 시각화는 데이터의 분포와 변수들 간의 관계에 대한 추가적인 정보를 제공해준다.
- 시각화는 반복적인 과정이며, 데이터에 관련된 질문에 대한 답을 할 수 있도록 도와준다. 이 단계에서 보낸 시간만큼 모델링 단계에서 절약하게 될 것이다.