-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy path04-visualization.Rmd
308 lines (233 loc) · 18.3 KB
/
04-visualization.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
```{r echo=FALSE}
library(ggplot2)
library(ggpubr)
theme_set(theme_grey(base_family="NanumGothic")) #한글깨짐 문제 해결
```
# 시각화 기초
데이터 시각화는 데이터를 시각적으로 표현하여 이를 이해하고 전달하는 데에 사용된다. 숫자로만 이뤄진 복잡한 데이터를 직관적이고 효과적으로 분석할 수 있으며, 트렌드, 패턴, 상관 관계 등을 시각적으로 파악할 수 있다. 이런 시각화는 데이터를 보다 직관적으로 이해할 수 있도록 하여 데이터를 통한 의사소통을 원활하게 할 수 있다. 시각화는 결국 **'효과적인 정보 전달'**이 목적인데 그러기 위해서는 사람의 인지방식에 대한 이해 또한 필요하다. 한마디로 데이터 시각화란 데이터에서 찾은 인사이트를 사람이 쉽게 인지할 수 있게 표현하는 방법이다.
여기 앤스컴 콰르탯이라는 데이터가 존재한다(`datasets` 패키지에 내장되어 있다). 영국의 통계학자인 Frank Anscombe이 만든 데이터셋들로 X1~X4, Y1~Y4까지 데이터가 존재하며 각각 숫자에 맞는 X와 Y값은 매칭되는 총 4개의 그룹에 각각 11개의 관측값이 존재하는 데이터다.
```{r}
knitr::kable(anscombe)
```
나열된 숫자만을 읽는 것은 매우 피곤한일인지라, 먼저 데이터의 평균과 분산을 한번 계산해보자(코드의 해석은 생각하지 말고 결과값에 집중해보자).
```{r}
# 평균 계산
lapply(anscombe, mean)
# 분산 계산
lapply(anscombe, var)
```
X1~X4 모두 평균 9, 분산 11로 동일했으며, Y1~Y4 에서도 평균 7.5 분산 4.12로 동일했다.
```{r}
cor(anscombe)
```
X와 매칭되는 Y의 상관계수는 각각 0.816으로 동일했으며 1차 회귀식은 모두 y = 3 + 0.5x로 동일했다. **즉 4개 그룹의 평균, 분산, 상관계수 및 회귀식이 모두 같다.** 이것만 보면 같은 경향을 가진 데이터로 볼 수 있을 것이다. 하지만 이 데이터들을 산포도 표시하면 어떤 결과가 나타날까? 역시 코드의 해석은 생각하지 말고 결과값에 집중해보자.
```{r}
par(mfrow = c(2, 2)) # 그래프를 2x2 그리드로 배치
# 첫 번째 그래프
plot(anscombe$x1, anscombe$y1, main = "Group I",
xlab = "x", ylab = "y")
# 두 번째 그래프
plot(anscombe$x2, anscombe$y2, main = "Group II",
xlab = "x", ylab = "y")
# 세 번째 그래프
plot(anscombe$x3, anscombe$y3, main = "Group III",
xlab = "x", ylab = "y")
# 네 번째 그래프
plot(anscombe$x4, anscombe$y4, main = "Group IV",
xlab = "x", ylab = "y")
```
각 그룹은 평균, 분산, 상관관계, 회귀선 등의 통계적 속성이 거의 동일하지만 시각화해보면 각 그룹이 실제로 매우 다른 패턴을 갖고 있음을 알 수 있다. 시각적인 표현은 복잡한 데이터를 이해하기 쉽고 직관적으로 만들어준다. 앤스컴 콰르탯 데이터셋을 예시로 들어 설명했지만, 실제 데이터에서도 시각화를 통해 통찰력을 얻고 결정을 내릴 수 있을 것이다. 다음은 데이터 시각화를 하는 대표적인 이유들이다.
1. **패턴 식별**: 데이터 시각화는 데이터의 패턴을 식별하는 데 도움이 된다. 이렇게 패턴을 인식하는 것은 데이터를 이해하고 향후 분석에 활용하는 데 중요하다.
2. **이상치 탐지**: 데이터 시각화는 이상치를 탐지하는 데 유용하다. 이상치는 데이터셋에서 일반적인 패턴과 다른 값을 가진 데이터 포인트를 의미하는데, 앤스컴 콰르탯 데이터셋의 경우, 그룹 3의 x = 13, y = 12.74와 같은 값이나 그룹 4에서 x = 19, y = 12.50과 같은 이상치를 쉽게 식별할 수 있다. 이렇게 이상치를 시각적으로 확인하면 데이터의 신뢰성과 정확성을 평가할 수 있다.
3. **상관관계 이해**: 데이터 시각화는 변수 간의 상관관계를 시각적으로 이해하는 데 도움이 된다. 앤스컴 콰르탯 데이터셋의 그룹 1의 경우 x와 y의 관계가 비선형적이고 종 모양의 패턴을 보여주고, 그룹 2를 보면 선형적인 상관관계가 있음을 쉽게 알 수 있다. 이러한 상관관계를 시각화하여 변수 간의 관계를 파악하면 추세를 예측하고 의사 결정을 내릴 수 있다.
## 이왕이면 예쁜 그래프
> 같은 값이면 다홍치마 -- 우리속담
[심미적 사용성 효과](https://www.nngroup.com/articles/aesthetic-usability-effect/)(Aesthetic-Usability Effect)에 따르면, 심미적인 디자인은 사람들의 두뇌에 긍정적인 반응을 불러일으키고 디자인이 실제로 더 잘 작동한다고 믿게 만든다고 한다. 심미적인 디자인은 데이터의 패턴과 관계를 뚜렷하게 시각화하여 전달력을 강화한다. 그래프의 색상, 레이아웃, 텍스트의 크기와 스타일 등을 조절하여 데이터의 중요한 부분을 강조하거나, 시각적인 잡음을 최소화 함으로 보는이가 데이터의 핵심 메시지를 빠르게 파악하고 이해하는 데 도움을 줄 수 있다. 심미적인 데이터 시각화는 창의성과 상상력을 자극하기도 한다. 예술적인 요소를 활용한 시각화는 데이터에 새로운 시각을 부여함으로 새로운 통찰력을 발견할 수 있게 한다. 무엇보다 예쁜 디자인은 사람들의 관심을 끌어 더 많은 사람들에게 도달하고 공유될 수 있다. 어색하게 느껴질 수 도 있지만 데이터 시각화를 위해서는 심리학과 인문학이 중요하다. 바로 **사람이 어떻게 세상을 보고 해석하는지에 대한 깊은 이해를 기반**으로 한다는 공통점이 있기 때문이다. UX 디자인 분야로 생각할 수도 있겠지만 [Jon Yablonski](https://jonyablonski.com/)가 제작한 [Law of UX](https://lawsofux.com/) 웹페이지에는 사용자 경험 디자인과 관련된 심리학적 이론을 수집하여 매력적인 디자인 방법을 소개한다.
## 시각화 요소
```{r}
library(datatoys)
library(tidyverse)
```
### 색상(Color)
적절한 색상 선택은 데이터의 구분과 패턴을 강조할 수 있다. 하지만 종종 시각화를 단순히 멋지게 보이게 하려는 목적으로 여러가지 색상을 사용하는 경우가 있는데, 분명한 목적이나 의도가 없이 색을 사용하지 않으면 오히려 혼란만 불러일으킬 수 있다. 마포구 반려동물 이름 순위를 시각화한 아래 두 그래프를 비교해보자.
```{r echo=FALSE, message=FALSE, warning=FALSE}
p1 <- petNames %>%
head(5) %>%
ggplot(aes(동물이름, 건수, fill = 동물이름)) +
geom_col() +
theme(legend.position = "none") +
labs(title = "마포구 반려동물 이름 순위 (상위 5개)")
p2 <- petNames %>%
head(5) %>%
ggplot(aes(동물이름, 건수)) +
geom_col(fill = "grey") +
labs(title = "마포구 반려동물 이름 순위 (상위 5개)")
ggarrange(p1, p2, labels = c("A", "B"), ncol = 2)
```
A의 경우 알록달록하니 예쁘긴 하지만 색이 무엇을 의미하는지 한번 더 들여보게 된다. 반면에 B는 조금 투박해 보일수도 있지만 전달하고자 하는 정보가 정확히 전달되는 데 아무 문제가 없다. **특별한 이유가 없다면 최대한 적은 색상을 사용해 안그래도 복잡한 이 세상에서 보는이의 피로감을 조금이나마 감소**시켜 주자.
카테고리 별로 다른 색을 사용하면 보는이가 직관적으로 차이를 감지하게 된다.
```{r echo=FALSE, message=FALSE, warning=FALSE}
datatoys::tuition %>% group_by(학제별) %>% arrange(desc(평균등록금.원.)) %>% slice(1:5) %>% ungroup() %>%
ggplot(aes(reorder(대학명, 평균등록금.원.), 평균등록금.원.)) +
geom_col(aes(fill = 학제별)) +
scale_fill_manual(values = c("#0079FF", "#00DFA2")) +
coord_flip() +
theme(
legend.position = "bottom"
) +
labs(
title = "학제별 대학별 평균 등록금 상위 5개 학교",
x = "학교명", y = "평균 등록금(원)"
)
```
또는 강조하고 싶은 곳에 특별한 색을 사용할 수도 있다. 한국방송통신대학교가 압도적인 입학정원을 보인다.
```{r echo=FALSE, message=FALSE, warning=FALSE}
datatoys::tuition %>% arrange(desc(입학정원.합.명.)) %>% slice(1:10) %>%
mutate(방송대 = ifelse(입학정원.합.명. > 236600, "방송대", "그외")) %>%
ggplot(aes(reorder(대학명, 입학정원.합.명.), 입학정원.합.명.)) +
geom_col(aes(fill = 방송대)) +
scale_fill_manual(values = c("grey", "#CD1818")) +
coord_flip() +
theme(
legend.position = "none"
) +
labs(
title = "대학별 입학정원 상위 10개 학교",
x = "학교명", y = "입학정원(명)"
)
```
### 글씨(Text)
글씨 크기, 글씨체, 굵기, 색상 등을 조절하여 시각화의 의도를 더욱 명확하게 전달할 수 있다.
### 배치(Layout)
정렬 방식, 여백, 배경 등을 조절하여 시각화의 의도를 더욱 명확하게 전달할 수 있다.
### 그 외 요소들
시각화의 의도를 더욱 명확하게 전달할 수 있는 다양한 요소들이 존재한다. 예를 들어, 시각화의 주제와 관련된 아이콘을 추가하거나, 시각화의 주제와 관련된 배경을 추가할 수도 있다.
# 시각화
## ggplot2 소개
R에서 사용할 수 있는 많은 시각화 패키지가 존재하지만, 여기서는 Hadley Wickham이 개발한 `ggplot2` 패키지 위주로 설명하고자 한다. ggplot2 문법은 데이터 시각화를 위한 매우 직관적이고 일관된 방법을 제공하여 사용자가 효율적으로 그래프를 생성하고 사용자 지정할 수 있도록 도와준다. 무엇보다 ggplot2는 다른 tidyverse 패키지와의 호환성이 뛰어나며, 많은 사용자 기반으로 풍부한 문서와 예제를 제공하여 사용자들이 학습하고 사용할 수 있다.
본 챕터에서는 ggplot2을 통해 데이터셋을 지정하고, 어떤 변수를 x축 또는 y축에 매핑할 것인지, 어떤 유형의 그래프를 그릴 것인지, 색상, 크기, 선 스타일 등의 추가적인 매개 변수를 설정하는 방법을 알아보도록 하자. 그 전에 [R 그래프 갤러리](https://r-graph-gallery.com/ggplot2-package.html)에 접속하면 R로 만들 수 있는 대부분의 시각화 결과물들과 그 코드를 볼 수 있다.
ggplot2 패키지를 사용하기 위해서는 먼저 패키지를 설치하고 불러와야 한다. ggplot2는 tidyverse 패키지에 포함되어 있으므로 tidyverse 패키지를 불러오면 ggplot2도 함께 불러와진다.
```r
library(ggplot2)
```
## ggplot2 기본 문법
ggplot2의 기본 문법은 다음과 같다. 지금은 이 문법을 외우는 것보다는 어떤 요소들이 존재하는지를 파악하는 것에 집중하자.
```r
ggplot(data = <DATA>) +
<geom_*>(
mapping = aes(<MAPPINGS>),
stat = <STAT>,
position = <POSITION>
) +
<COORDINATE_FUNCTION> +
<FACET_FUNCTION>
```
- `ggplot()` 함수는 데이터셋을 지정한다.
- `+` 기호는 ggplot2에서 여러 개의 레이어를 추가할 때 사용한다.
- `aes()` 함수는 데이터셋의 변수를 x축 또는 y축에 매핑한다. 이는 x축만 존재할 수도 있고, y축만 존재할 수도 있다. x축과 y축 모두 존재할 수도 있다. `color =`, `fill =`, `size =`, `shape =`, `linetype =` 등의 매개 변수를 사용하여 group 별 색상, 크기, 선 스타일 등을 지정할 수 있다.
- `geom_*()` 함수는 데이터셋을 어떤 유형의 그래프로 그릴 것인지를 지정한다. `geom_*()` 함수는 `geom_point()`, `geom_line()`, `geom_bar()`, `geom_boxplot()` 등이 있다.
- `stat` 매개 변수는 데이터를 어떻게 요약할 것인지를 지정한다. 예를 들어, `geom_bar()` 함수를 사용할 때 `stat = "identity"`를 지정하면 데이터셋의 값을 그대로 표현하고, `stat = "count"`를 지정하면 데이터셋의 값을 개수로 표현한다.
- `position` 매개 변수는 데이터를 어떻게 배치할 것인지를 지정한다. 예를 들어, `geom_bar()` 함수를 사용할 때 `position = "dodge"`를 지정하면 데이터를 그룹별로 나누어 표현하고, `position = "fill"`을 지정하면 데이터를 비율로 표현한다.
- `coord_*()` 함수는 좌표계를 지정한다. `coord_*()` 함수는 `coord_flip()`, `coord_polar()` 등이 있다.
- `facet_*()` 함수는 그래프를 여러 개의 패널로 나누어 표현한다. `facet_*()` 함수는 `facet_wrap()`, `facet_grid()` 등이 있다.
## 데이터셋과 좌표계 지정하기
ggplot2를 사용하기 위해서는 먼저 데이터셋을 지정해야 한다. datatoys의 `petNames` 데이터셋은 마포구 반려동물 이름 통계를 제공한다. 이 데이터셋을 사용하여 ggplot2를 사용해보자.
```{r}
library(datatoys)
library(ggplot2)
top10 <- petNames %>%
arrange(desc(건수)) %>%
slice(1:10)
```
먼저 `petNames` 데이터셋을 `건수` 변수를 기준으로 내림차순 정렬하고, 상위 10개의 데이터만 추출하여 `top10` 데이터셋을 생성하였다. 이제 `top10` 데이터셋을 사용하여 ggplot2를 사용해보자.
```{r}
ggplot(data = top10)
```
만약 빈 화면만 뜬다면 정확히 한 것이다. 여기에 `aes()` 함수를 사용하여 `x` 매개 변수에 `동물이름` 변수를 매핑하면 x축에 `동물이름` 변수를 표현할 수 있다.
```{r}
ggplot(data = top10, aes(x = 동물이름))
```
이번에는 y축에 `건수` 변수를 매핑해보자.
```{r}
ggplot(data = top10, aes(x = 동물이름, y = 건수))
```
`+`를 사용하여 `geom_col()` 함수를 추가하면 막대 그래프를 그릴 수 있다. 앞서 `ggplot()` 함수를 이용해 지정한 좌표계 위에 레이어를 쌓는 것이다.
```{r}
ggplot(data = top10, aes(x = 동물이름, y = 건수)) +
geom_col()
```
막대그래프를 통해 각 동물 이름별로 반려동물 등록 건수를 확인할 수 있지만, 정확한 값을 확인하기 어렵다. 이를 해결하기 위해서는 `geom_text()`를 사용해 새로운 레이어를 추가해준다. `geom_col()` 다음에 위치하는 것을 주목하라.
```{r}
ggplot(data = top10, aes(x = 동물이름, y = 건수)) +
geom_col() +
geom_text(aes(label = 건수))
```
기본적으로 ggplot2는 레이어(layer; 층)를 쌓으면서 그래프를 그린다. 이는 마치 투명한 셀로판지에 그린 그림 여러 장을 쌓는 것과 유사하다. 이때, 먼저 그린 그림이 아래에 위치하고, 나중에 그린 그림이 위에 위치한다. 이를 통해 먼저 그린 그림이 가려지지 않고, 나중에 그린 그림이 가려지는 효과를 얻을 수 있다.
```{r}
ggplot(data = top10, aes(x = 동물이름, y = 건수)) +
geom_text(aes(label = 건수)) +
geom_col()
```
위 그래프와 순서만 바꿨을 뿐인데 `geom_text()`의 결과가 일부 보이지 않는다. 이는 그 위에 쌓여진 `geom_col()` 함수가 그린 결과물이 `geom_text()` 함수의 결과물을 가려버렸기 때문이다. 다시 원래대로 순서를 바꿔주고, `vjust =` 매개 변수를 사용하여 텍스트의 위치를 조정해 보자. 보다 보기 좋아질 것이다.
```{r}
ggplot(data = top10, aes(x = 동물이름, y = 건수)) +
geom_col() +
geom_text(aes(label = 건수), vjust = -0.5)
```
`coord_flip()` 함수를 사용하면 x축과 y축을 바꿀 수 있다. `geom_text()` 함수의 `vjust =` 매개 변수가 `hjust =`로 바뀐 것은 `coord_flip()` 함수를 사용하면 x축과 y축이 바뀌기 때문이다.
```{r}
ggplot(data = top10, aes(x = 동물이름, y = 건수)) +
geom_col() +
geom_text(aes(label = 건수), hjust = -0.5) +
coord_flip()
```
`coord_*` 함수는 좌표계를 지정하는 함수이다. `coord_flip()` 함수는 좌표계를 수평으로 뒤집는다. `coord_polar()` 함수는 좌표계를 극좌표계로 변환한다. `coord_*` 계열 함수에는 `coord_cartesian()`, `coord_fixed()`, `coord_map()` 등이 있다.
```{r}
ggplot(data = top10, aes(x = 동물이름, y = 건수)) +
geom_col() +
geom_text(aes(label = 건수)) +
coord_polar()
```
만약 우리만 이 그래프를 볼 목적이라면 상관 없겠지만, 아무것도 모르는 사람이 이 그래프를 보면 무슨 의미인지 알 수 없다. `labs()` 함수를 사용하면 그래프의 제목(title), 부제목(subtitle), 캡션(caption), x축과 y축의 이름을 지정할 수 있다. 그래프에 대한 설명을 추가해 보다 뜻을 명확하게 해 보자.
```{r}
ggplot(data = top10, aes(x = 동물이름, y = 건수)) +
geom_col() +
geom_text(aes(label = 건수), hjust = -0.5) +
coord_flip() +
labs(
title = "마포구 반려동물 이름 통계",
subtitle = "상위 10개의 반려동물 이름",
caption = "데이터 출처: 마포구청",
x = "반려동물 이름",
y = "등록 건수"
)
```
보다 명확한 그래프를 만들었다. 충분히 아름다운 그래프지만 그래프에서 아쉬운 점을 하나 찾아본다면 막대그래프의 순서이다. 큰 순서부터, 또는 작은 순서부터 보여주는 방법은 없을까? `reorder()` 함수를 사용하면 막대그래프의 순서를 변경할 수 있다. `reorder(x, y)` 함수는 `x` 매개 변수에 지정한 변수를 `y` 매개 변수에 지정한 변수의 크기에 따라 재정렬한다. `-`를 사용하면 내림차순으로 정렬한다.
```{r}
ggplot(data = top10, aes(x = reorder(동물이름, 건수), y = 건수)) +
geom_col() +
geom_text(aes(label = 건수), hjust = -0.5) +
coord_flip() +
labs(
title = "마포구 반려동물 이름 통계",
subtitle = "상위 10개의 반려동물 이름",
caption = "데이터 출처: 마포구청",
x = "반려동물 이름",
y = "등록 건수"
)
```
## ggplot2 themes
ggplot2는 기본적으로 흰색 배경에 회색 격자를 그리는데, 이를 변경할 수 있다. `theme_*()` 함수를 사용하여 테마를 변경할 수 있다. `ggthemes` 패키지를 통해 다양한 추가 테마를 사용할 수 있다.
```{r}
library(ggthemes)
ggplot(data = top10, aes(x = reorder(동물이름, 건수), y = 건수)) +
geom_col() +
geom_text(aes(label = 건수), hjust = -0.5) +
coord_flip() +
labs(
title = "마포구 반려동물 이름 통계",
subtitle = "상위 10개의 반려동물 이름",
caption = "데이터 출처: 마포구청"
) +
theme_fivethirtyeight(base_family = "NanumGothic")
```