(공지) 본 자료는 유쾌한 R 통계학 Chapter 4장을 요약 정리한 내용입니다.


1 이번장에서 배우는 내용


2 자료 표현의 예술

2.1 그래프가 필요한 이유

  • 자료를 시각적으로 표현해서 어떤 모습인지 파악한 후 좀 더 중요한 통계량들을 해석해야 한다.
  • 비유: 온라인 데이트 (카메라속 이미지와 실제는 늘 다르다!)


2.2 좋은 그래프의 조건 (에드워드 터프티, 2001)

  • 자료를 보여주어야 한다.
  • 그래프가 제시하는 자료에 괜해 독자가 뭔가 생각하게 만들어야 한다.
  • 자료를 왜곡하지 않아야 한다.
  • 최소한의 잉크로 많은 수치를 제시해야 한다.
  • 큰 자료 집합들의 일관성을 보여주어야 한다.
  • 서로 다른 자료 조각들을 비교할 수 있게 해야 한다.
  • 자료의 숨겨진 본성을 드러내야 한다.


2.2.1 나쁜 그래프

bad_graph
  • 왜 나쁠까?


2.2.2 좋은 그래프

good_graph
  • 왜 좋은가?


2.2.3 거짓말, 새빨간 거짓말, 그리고, —음, —그래프

two_graphs
  • 두 그래프의 차이를 어떻게 다른가?


2.3 이번 장에서 사용하는 패키지

#If you don't have ggplot2 installed then use:
# install.packages(c("ggplot2", "plyr"))
library(ggplot2)
library(plyr)
library(dplyr)


2.3.1 그래프의 구성

  • 기하객체: geometric object - 줄여서 geom
  • 미적속성: aesthetics property - aes()
ggplot2_intro


2.3.2 기하 객체(geom)

기하객체에 관한 모든 함수를 ggplot2 웹싸이트 http://had.co.nz/ggplot2/를 보기 바란다.


2.3.3 미적 속성

aes_intro


2.3.4 ggplot() 함수 사용법

  • 해당 명령의 일반적인 형태는 아래와 같다.
myGraph <- ggplot(myData, aes(x축에 그릴 변수들, y축에 그릴 변수들))
  • 해석: myData라는 자료에 기초해서 myGraph라는 새 그래프 객체를 생성한다.
  • 계층들과 기하 객체들에서 남성의 자료와 여성의 자료를 다른 색으로 표시하려면 다음과 같이 하면 된다. (자료가 남성의 것인지, 여성의 것인지가 gender 변수에 정의되어 있다고 가정)
myGraph <- ggplot(myData, aes(x축에 그릴 변수들, y축에 그릴 변수들, colour = gender))


2.3.5 스탯함수와 기하객체

stat_function
  • 사용 예시는 아래와 같다.
myHistogram <- ggplot(myData, aes(variable))
myHistogram + geom_histogram(aes(y=..count..), binwidth = 0.4)


2.3.6 과도한 그래프 작도를 피하려면

그래프가 지저분하거나 불명확해지는 주된 이유는(1) 그래프 하나에 너무 많은 자료를 표시하거나 (2) 자료가 너무 겹쳐져 그려지는 것이다. ggplot2에는 이런 문제를 극복하는 데 도움이 되는 여러 위치 관련 기능이 있다. 첫번째로 살펴볼 것은 다음과 같은 형태로 사용하는 위치 조정 기능이다.

position = 'x'
  • 여기서 x에는 다음 다섯 단어 중 하나를 사용할 수 있다.
    • dodge: 가장자리가 겹치지 않도록 객체들의 위치를 조정한다.
    • stack & fill: 객체들이 쌓이도록 위치를 조정한다. stack은 가장 큰 객체가 제일 밑에 깔리고 가장 작은 객체가 제일 위에 놓이도록 객체들을 쌓는다. fill은 공간이 모두 채워지도록 객체들의 높이를 적절히 비례해서 쌓는다.
    • identity: 위치를 조정하지 않는다.
    • jitter: 객체들이 겹치지 않도록 무작위로 오프셋을 추가한다.

과도한 그래프 작도를 피하는 또 다른 방법은 면 분할(faceting)이다. 크게 두가지 방법이 있다.

faceting

2.3.6.1 facet_grid

그래프가 표시하는 자료를 다른 변수들과의 조합에 기초해서 격자(grid) 형태로 분할할 때 쓰는 함수

+ facet_grid(gender ~ extroversion)


2.3.6.2 facet_wrap

그래프를 하나의 변수에 기초해서 여러 개별 그래프들로 분할하고 그것들을 긴 리본 형태로 표시하는 것인데, 필요하면 일정 개수의 그래프마다 줄을 바꾸어서 격자 형태를 만들 수도 있다.

3 변수들의 관계를 보여주는 산점도

산점도(scatterplot)는 자료에 관해 여러 가지 것을 말해주는데, 이를테면 변수들에 관계가 존재하는지, 그것이 어떤 관계인지, 그리고 다른 사례들과 눈에 띄게 다른 사례가 있는지 등을 산점도를 통해서 파악할 수 있다.

3.1 단순 산점도

  • 현재 모든 파일은 구글 드라이브에 저장되어 있습니다. 아래와 같이 실행하면 본인인증만 하면 관련 파일을 다운로드 받을 수 있습니다.
library(googledrive)
drive_download(file = "Exam Anxiety.dat", path = "../data/Exam Anxiety.dat", overwrite = TRUE)
examData <- read.delim("../data/Exam Anxiety.dat", header = TRUE)
dplyr::glimpse(examData)
## Observations: 103
## Variables: 5
## $ Code    <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1…
## $ Revise  <int> 4, 11, 27, 53, 4, 22, 16, 21, 25, 18, 18, 16, 13, 18, 98…
## $ Exam    <int> 40, 65, 80, 80, 40, 70, 20, 55, 50, 40, 45, 85, 70, 50, …
## $ Anxiety <dbl> 86.298, 88.716, 70.178, 61.312, 89.522, 60.506, 81.462, …
## $ Gender  <fct> Male, Female, Male, Male, Male, Female, Female, Female, …
  • Code: 점수가 속한 참가자를 식별하는 번호
  • Revise: 참가자가 복습(시험 준비)에 소비한 시간
  • Exam: 참가자의 시험 점수를 퍼센트로 환산한 값
  • Anxiety: EAQ 평가 점수
  • Gender: 참가자의 성별(“male” 또는 “female”이라는 문자열로 저장)

데이터셋은 아래와 같이 구성되어 있습니다.

DT::datatable(examData)

이제 산점도를 그리도록 합니다.

ggplot(examData, aes(x = Anxiety, Exam)) + 
  geom_point() + 
  labs(x = "Exam Anxiety", y = "Exam Performance %")

  • 위 그래프를 어떻게 해석할 것인가? 그대로 볼 것인가? 아니면 별도로 가공할 것인가?

3.2 멋진 선 추가

회귀선(regression line)을 추가할 수 있습니다. ggplot2의 어법에서는 이 회귀선을 ‘평활기(smoother)’라고 부르는데, 이는 회귀선이 원본 자료의 들쭉날쭉한 요철을 매끄럽게 펴서(’평활’) 자료 전체를 요약하는 선입니다. (p. 177)

library(gridExtra)
p <- ggplot(examData, aes(x = Anxiety, Exam)) + 
  geom_point() + 
  labs(x = "Exam Anxiety", y = "Exam Performance %") + 
  ggtitle("scatter_plot")

p1 <- p + geom_smooth() + ggtitle("geom_smooth")
  
p2 <- p + geom_smooth(method = "lm") + ggtitle("method = `lm`")

p3 <- p + geom_smooth(method = "lm", colour = "Red" ) + ggtitle("method = `lm` & colour = `Red`")

p4 <- p + geom_smooth(method = "lm", se = F ) + 
  ggtitle("method = `lm` & se = F")

p5 <- p + geom_smooth(method = "lm", alpha = 0.1, fill = "Blue") + ggtitle("method = `lm` & alpha = 0.1 & fill = 'Blue'")

grid.arrange(p, p1, p2, p3, p4, p5, ncol = 1)

3.3 그룹 산점도

그래프와 보고자 하는 것은 Exam Anxiety에 대해 성별간의 반응이 어떻게 다른지 보고 싶을 때는 어떻게 그래프를 작성해야 할까요?

코드는 아래와 같습니다.

# 객체 생성
p <- ggplot(examData, 
            aes(x = Anxiety, 
                y = Exam, 
                colour = Gender))

# 그래프 생성
p + 
  geom_point() + 
  geom_smooth(method = "lm", 
              aes(fill = Gender), 
              alpha = 0.1) +
  labs(x = "Exam Anxiety", 
       y = "Exam Performance %", 
       colour = "Gender")

회귀선의 기울기를 보면 MaleFemale 그룹보다 선의 기울기가 더 급한 것을 볼 수가 있습니다. 다른 말로 하면, 시험 불안이 시험 성적에 미치는 악영향이 여학생들보다 남학생에게 더 큰 것을 확인할 수 있습니다.


4 명백한 문제점을 포착하기에 좋은 히스토그램

히스토그램이 보여주는 것은 무엇인가?

뮤직 페스티벌 참가한 사람들의 위생 상태조사한 데이터를 활용한다. DownloadFestival.dat - 데이터의 자세한 설명은 페이지 182 참조.

4.1 데이터 가져오기

library(googledrive)
drive_download(file = "DownloadFestival.dat", path = "../data/DownloadFestival.dat", overwrite = TRUE)
festivalData <- read.delim("../data/DownloadFestival.dat", header = TRUE)
dplyr::glimpse(festivalData)
## Observations: 810
## Variables: 5
## $ ticknumb <int> 2111, 2229, 2338, 2384, 2401, 2405, 2467, 2478, 2490, 2…
## $ gender   <fct> Male, Female, Male, Female, Female, Male, Female, Femal…
## $ day1     <dbl> 2.64, 0.97, 0.84, 3.03, 0.88, 0.85, 1.56, 3.02, 2.29, 1…
## $ day2     <dbl> 1.35, 1.41, NA, NA, 0.08, NA, NA, NA, NA, 0.44, NA, 0.2…
## $ day3     <dbl> 1.61, 0.29, NA, NA, NA, NA, NA, NA, NA, 0.55, NA, 0.47,…

4.2 히스토그램 생성

festivalHistogram <- ggplot(festivalData, aes(day1)) + 
  theme(legend.position = "none")

festivalHistogram + 
  geom_histogram(binwidth = 0.4) +
  labs(x = "Hygiene (Day 1 of Festival", y = "Frequency")

  • 히스토그램에서 무엇을 볼 것인가?
  • 이상치를 어떻게 볼 것인가?

5 상자그림(상자수염도)

5.1 BoxPlot 그래프

festivalBoxplot <- ggplot(festivalData, aes(x = gender, y = day1))
festivalBoxplot + 
  geom_boxplot() + 
  labs(x = "Gender", y = "Hygiene (Day 1 of Festival)")

  • 히스토그램과의 차이점은 무엇인가요?
  • 히스토그램에서도 이상치가 발견되었지만, 상자그림을 통해서는 여성그룹에서 이상치가 발견된 것을 확인할 수 있습니다.

5.2 이상치 검출방법 - 자료 정렬

festivalData2 <- festivalData[order(festivalData$day1), ]
tail(festivalData2)
##     ticknumb gender  day1 day2 day3
## 774     4564 Female  3.38 3.44 3.41
## 300     3371 Female  3.41   NA   NA
## 657     4264   Male  3.44   NA   NA
## 303     3374   Male  3.58 3.35   NA
## 574     4016 Female  3.69   NA   NA
## 611     4158 Female 20.02 2.44   NA
  • 맨 마지막에 있는 데이터에서 20.02이 확인 되었다.
  • 코딩이 잘못되었음을 확인함. (데이터 입력의 실수)
  • 데이터 입력의 실수를 어떻게 볼 것인가? 어떻게 줄일 것인가?

5.3 데이터 입력 수정

festivalData3 <- festivalData2 %>% 
  mutate(day1 = recode(day1, '20.02' = 2.02))

tail(festivalData3)
##     ticknumb gender day1 day2 day3
## 805     4564 Female 3.38 3.44 3.41
## 806     3371 Female 3.41   NA   NA
## 807     4264   Male 3.44   NA   NA
## 808     3374   Male 3.58 3.35   NA
## 809     4016 Female 3.69   NA   NA
## 810     4158 Female 2.02 2.44   NA
  • recode 함수를 사용하여 20.02의 값을 2.02로 바꿀 수 있습니다.

5.4 이상치 제거한 후의 상자그림

어떻게 해석할 것인가? 책의 내용을 요약하면 아래와 같이 해석할 수 있다.

흰 상자의 하단은 하위 사분위수를 나타낸다….여성이 남성보다 이 범위가 더 넓다….이는 여성 하위 25%가 남성 하위 25%보다 위생 점수들보다 더 다양하다(즉, 변동이 크다)는 뜻이다…여성의 중앙값이 남성의 중앙값보다 큰데, 이는 가운데에 해당하는 남성의 점수보다 높다는(더 위생적이라는) 뜻이다…마지막으로 남성의 상자그림을 보면 상자 위쪽에 자료점이 몇 개 있다. 이들은 이상치에 해당하는 사례들이다. 제5장에서는 이런 이상치들을 처리하는 방법을 살펴본다…(???)









6 밀도 그림

밀도 그림(density plot)은 히스토그램과 비슷하지만, 분포를 막대들이 아니라 매끄러운 선으로 표시한다. 이상치를 제거하고, 밀도 그래프를 생성한다. 우선 구글 드라이브에서 이상치가 제거된 파일을 다운로드 받습니다. 구글 드라이브에서 파일을 다운로드 받는 자세한 내용은 구글드라이브 패키지에서 확인하시기를 바랍니다.

library(googledrive)
x <- drive_find(pattern = ".dat")
drive_download(file = as_id(x$id[71]), path = "../data/DownloadFestival(No Outlier).dat", overwrite = TRUE)
festivalData <- read.delim("../data/DownloadFestival(No Outlier).dat", header = TRUE)

library(ggplot2) 
ggplot(festivalData, aes(day1)) +
  geom_density() + 
  labs(x = "Hygiene (Day 1 of Festival)", y = "Density Estimate")

7 평균을 그래프로 그리기

7.1 막대그림표와 오차 막대그림표

# library(googledrive)
# drive_download(file = "ChickFlick.dat", path = "../data/ChickFlick.dat", overwrite = TRUE)

chickFlick <- read.delim("../data/ChickFlick.dat", header = TRUE)

glimpse(chickFlick)
## Observations: 40
## Variables: 3
## $ gender  <fct> Male, Male, Male, Male, Male, Male, Male, Male, Male, Ma…
## $ film    <fct> Bridget Jones' Diary, Bridget Jones' Diary, Bridget Jone…
## $ arousal <int> 22, 13, 16, 10, 18, 24, 13, 14, 19, 23, 37, 20, 16, 28, …
  • gender: 참가자의 성별(문자열)
  • film: 관람한 영화 제목(문자열)
  • arousal: 각성 점수

7.1.1 독립변수 하나에 대한 막대그래프

ggplot(chickFlick, aes(film, arousal)) + 
  stat_summary(fun.y = mean, geom = "bar", fill = "White", colour = "Black") + 
  stat_summary(fun.data = mean_cl_normal, geom = "pointrange") + 
  labs(x = "Film", y = "Mean Arousal")

  • stat_summary() 활용 방법에 대해서는 p.192 페이지를 참고하기를 바랍니다.

7.1.2 여러 독립변수에 대한 막대그림표

ggplot(chickFlick, aes(film, arousal, fill = gender)) + 
  stat_summary(fun.y = mean, geom = "bar", position = "dodge") + 
  stat_summary(fun.data = mean_cl_normal, geom = "errorbar", position = position_dodge(width = 0.90), width = 0.2) + 
  labs(x = "Film", y = "Mean Arousal", fill = "Gender")

  • <Bridget Jones’ Diary>의 평균 각성 정도를 보면 남성이 더 높다. 즉, 실제로는 여성보다 남성이 이 영화를 즐겼음을 알 수 있다.
  • 에서는 여성과 남성의 차이가 크지 않다.
ggplot(chickFlick, aes(film, arousal, fill = gender)) +
  stat_summary(fun.y = mean, geom = "bar", position="dodge") + 
  stat_summary(fun.data = mean_cl_normal, 
               geom = "errorbar",
               position=position_dodge(width=0.90), 
               width = 0.2) + 
  labs(x = "Film", y = "Mean Arousal", fill = "Gender") + 
  scale_fill_manual("Gender", values = c("Female" = "pink", "Male" = "blue"))

7.2 선 그래프

7.2.1 독립변수 하나에 대한 선 그래프

library(googledrive)
drive_download(file = "Hiccups.dat", path = "../data/Hiccups.dat", overwrite = TRUE)
hiccupsData <- read.delim("../data/Hiccups.dat", header = TRUE)
hiccups <- stack(hiccupsData)
names(hiccups) <- c("Hiccups", "Intervention")
hiccups$Intervention_Factor <- factor(hiccups$Intervention, levels(hiccups$Intervention)[c(1, 2, 3, 4)])
levels(hiccups$Intervention_Factor)
## [1] "Baseline" "Tongue"   "Carotid"  "Rectum"
line <- ggplot(hiccups, aes(x = Intervention_Factor, y = Hiccups))
line + 
  stat_summary(fun.y = mean, geom = "line", aes(group = 1), colour = "Blue", linetype = "dashed") + 
  stat_summary(fun.data = mean_cl_boot, geom = "errorbar", width = 0.2) + 
  labs(x = "Intervention", y = "Mean Number of Hiccups")

  • Baseline: 기저에 해당하는 딸꾹질 횟수
  • Tongue: 혀를 잡아당긴 후의 딸꾹질 횟수
  • Carotid: 경동맥 마사지 이후의 딸꾹질 횟수
  • Rectum: 직장 수지 마사지 이후의 딸꾹질 횟수

위 그래프에는 기저와 여러 처치 이후의 평균 딸꾹질 횟수가 표시되어 있음. Old fashioned digital rectal massage. The moral here is: if you have hiccups, find something digital and go amuse yourself for a few minutes.

7.3 여러 독립변수에 대한 선 그래프

# library(googledrive)
# x <- drive_find(pattern = "TextMessages.dat")
# drive_download(file = as_id(x$id[1]), path = "../data/TextMessages.dat", overwrite = TRUE)
textData <- read.delim("../data/TextMessages.dat", header = TRUE)
glimpse(textData)
## Observations: 50
## Variables: 3
## $ Group      <fct> Text Messagers, Text Messagers, Text Messagers, Text …
## $ Baseline   <int> 52, 68, 85, 47, 73, 57, 63, 50, 66, 60, 51, 72, 77, 5…
## $ Six_months <int> 32, 48, 62, 16, 63, 53, 59, 58, 59, 57, 60, 56, 61, 5…
  • Group: 참가자가 문자 메시지를 허용한 실험군(“Text Messages”)에 속하는지 대조군(‘Controls’)에 속하는지를 나타낸다.
  • Baseline: 기저 조건(조작을 가하기 전)의 문법 시험 점수
  • Six_months: 6개월 이후의 문법 시험 점수

자료를 긴 형식으로 변경해서 textMessages라는 데이터프레임을 생성한다.

library(reshape2)
textData$id <- row(textData[1])
textMessages <- melt(textData, id = c("id", "Group"), measured = c("Baseline", "Six_months"))
names(textMessages)<-c("id", "Group", "Time", "Grammar_Score")
textMessages$Time<-factor(textMessages$Time, labels = c("Baseline", "6 Months"))

head(textMessages)
##   id          Group     Time Grammar_Score
## 1  1 Text Messagers Baseline            52
## 2  2 Text Messagers Baseline            68
## 3  3 Text Messagers Baseline            85
## 4  4 Text Messagers Baseline            47
## 5  5 Text Messagers Baseline            73
## 6  6 Text Messagers Baseline            57

가공된 데이터를 변환하여 그래프를 생성한다.

library(ggplot2)
line <- ggplot(textMessages, aes(x = Time, y = Grammar_Score, colour = Group))
line + 
  stat_summary(fun.y = mean, geom = "line", aes(group = Group)) + 
  stat_summary(fun.data = mean_cl_boot, geom = "errorbar", width = 0.2) + 
  labs(x = "Time", y = "Mean Grammar Score", colour = "Group") + 
  ylim(c(0, 80)) + 
  theme_bw()

  • 어떻게 해석할 것인가? 일단, 문자 메시지가 아동의 문법 이해도에 악영향을 미친다는 결론을 내릴 수 있음.

8 더 읽을거리

9 Web Resources

10 Interesting Real Research