---
title: "지도제작 대회"
subtitle: "선거구 유권자수"
description: |
선거획정위원회 선거구 유권자수 변화를 살펴보자.
author:
- name: 이광춘
url: https://www.linkedin.com/in/kwangchunlee/
affiliation: 한국 R 사용자회
affiliation-url: https://github.com/bit2r
title-block-banner: true
format:
html:
theme: flatly
code-fold: true
code-overflow: wrap
toc: true
toc-depth: 3
toc-title: 목차
number-sections: true
highlight-style: github
self-contained: false
default-image-extension: jpg
filters:
- lightbox
lightbox: auto
link-citations: true
knitr:
opts_chunk:
message: false
warning: false
collapse: true
comment: "#>"
R.options:
knitr.graphics.auto_pdf: true
editor_options:
chunk_output_type: console
---
# 제21대 국회의원
- [제21대 국회의원 선거/선거구 획정 ](https://namu.wiki/w/%EC%A0%9C21%EB%8C%80%20%EA%B5%AD%ED%9A%8C%EC%9D%98%EC%9B%90%20%EC%84%A0%EA%B1%B0/%EC%84%A0%EA%B1%B0%EA%B5%AC%20%ED%9A%8D%EC%A0%95)
- [제20대 국회의원 선거/선거구 획정 ](https://namu.wiki/w/%EC%A0%9C20%EB%8C%80%20%EA%B5%AD%ED%9A%8C%EC%9D%98%EC%9B%90%20%EC%84%A0%EA%B1%B0/%EC%84%A0%EA%B1%B0%EA%B5%AC%20%ED%9A%8D%EC%A0%95)
## 데이터셋
``` {r}
#| eval: false
# 0. packages -------------------------------------------------------------
library(tidyverse)
library(rvest)
# 1. data -----------------------------------------------------------------
url <- "https://namu.wiki/w/%EC%A0%9C21%EB%8C%80%20%EA%B5%AD%ED%9A%8C%EC%9D%98%EC%9B%90%20%EC%84%A0%EA%B1%B0/%EC%84%A0%EA%B1%B0%EA%B5%AC%20%ED%9A%8D%EC%A0%95"
sido_names <- read_html(url) |>
html_nodes("h3") |>
html_text()
sido_tbl <- sido_names |>
enframe() |>
separate(value, into = c("index", "시도명", "의석수"), sep = " ") |>
mutate(의석수 = parse_number(의석수)) |>
select(시도명, 의석수)
sido_tbl
sido_numbers <- sido_tbl |>
pull(의석수)
## 1.2. 시도 인구수-----------------------------------------------------------------
sido_raw <- read_html(url) |>
html_nodes("table") |>
html_table(header = TRUE)
sido_pop <- sido_raw |>
enframe() |>
mutate(ncol = map_int(value, ncol),
nrow = map_int(value, nrow)) |>
filter(ncol == 4) |>
mutate(check = ifelse(nrow %in% sido_numbers, TRUE, FALSE)) |>
filter(check) |>
mutate(names = map(value, names)) |>
mutate(names = map_chr(names, paste0, collapse=" ")) |>
filter(str_detect(names, "변동 인구")) |>
select(value)
## 1.3. 결합-----------------------------------------------------------------
pop_tbl <- bind_cols(sido_tbl, sido_pop) |>
unnest(value) |>
rename(인구수 = `인구[A]`) |>
mutate(인구수 = parse_number(인구수)) |>
mutate(선거구 = str_remove(선거구, "\\[\\d{1,3}\\]"))
pop_tbl |>
write_csv("data/제21대총선_선거구_획정.csv")
```
## 분석
### 총계
```{r}
library(tidyverse)
pop_tbl <-
read_csv("data/제21대총선_선거구_획정.csv")
pop_tbl |>
mutate(변동여부 = ifelse(is.na(변동), "없음", "변동")) |>
count(변동여부, name = "선거구수") |>
mutate(비율 = 선거구수 / sum(선거구수)) |>
janitor::adorn_totals(name = "합계")
```
### 시도별
```{r}
pop_tbl |>
mutate(변동여부 = ifelse(is.na(변동), "미변동", "변동")) |>
count(시도명, 변동여부, name = "선거구수") |>
pivot_wider(names_from = 변동여부, values_from = 선거구수, values_fill = 0) |>
mutate(총선거구 = 변동 + 미변동) |>
mutate(변동비율 = 변동 / 총선거구) |>
arrange(desc(변동비율))
```
# 제20대 국회의원
## 데이터셋
``` {r}
#| eval: false
# 0. packages -------------------------------------------------------------
library(tidyverse)
library(rvest)
# 1. data -----------------------------------------------------------------
url <- "https://namu.wiki/w/%EC%A0%9C20%EB%8C%80%20%EA%B5%AD%ED%9A%8C%EC%9D%98%EC%9B%90%20%EC%84%A0%EA%B1%B0/%EC%84%A0%EA%B1%B0%EA%B5%AC%20%ED%9A%8D%EC%A0%95"
sido_names <- read_html(url) |>
html_nodes("h3") |>
html_text()
sido20_tbl <- sido_names |>
enframe() |>
separate(value, into = c("index", "idx2", "시도명"), sep = "\\.") |>
mutate(시도명 = str_extract(시도명, pattern = '(.*?)(?=\\[)') |> str_trim()) |>
select(시도명)
sido20_tbl
## 1.2. 시도 인구수-----------------------------------------------------------------
sido20_raw <- read_html(url) |>
html_nodes("table") |>
html_table(header = TRUE)
sido20_pop <- sido20_raw |>
enframe() |>
mutate(names = map(value, names)) |>
mutate(names = map_chr(names, paste0, collapse=" ")) |>
filter(str_detect(names, "선거구의 명칭")) |>
select(value)
## 1.3. 결합-----------------------------------------------------------------
pop20_tbl <- bind_cols(sido20_tbl, sido20_pop) |>
unnest(value) |>
janitor::clean_names(ascii = FALSE) |>
rename(인구수 = 인구,
선거구 = 선거구의_명칭) |>
mutate(인구수 = parse_number(인구수)) |>
mutate(선거구 = str_remove(선거구, "\\[\\d{1,3}\\]"))
pop20_tbl |>
write_csv("data/제20대총선_선거구_획정.csv")
```
## 분석
### 총계
```{r}
library(tidyverse)
pop20_tbl <-
read_csv("data/제20대총선_선거구_획정.csv")
pop21_tbl <-
read_csv("data/제21대총선_선거구_획정.csv")
```
### 시도별
```{r}
pop20_tbl |>
count(시도명, name = "선거구수", sort=TRUE) |>
mutate(비율 = 선거구수 / sum(선거구수)) |>
arrange(desc(비율)) |>
mutate(누적비율 = cumsum(비율))
```
# 제20~21대 교차분석
```{r}
pop_tbl <- pop21_tbl |> rename(인구수21 = 인구수) |>
full_join(pop20_tbl |> rename(인구수20 = 인구수) |> select(-상세),
by = c("시도명", "선거구")) |>
distinct() |>
relocate(인구수20, .before=인구수21) |>
mutate(변경여부 = ifelse(is.na(인구수20) | is.na(인구수21), "변경", "미변경")) |>
mutate(변경내역 = case_when(is.na(인구수20) & !is.na(인구수21) ~ "생성",
!is.na(인구수20) & is.na(인구수21) ~ "소멸",
TRUE ~ "변동없음")) |>
mutate(선거구 = str_extract_all(선거구, "[가-힣]+")) |>
mutate(선거구 = map_chr(선거구, paste0, collapse=""))
```
## 제21대 선거결과
```{r}
winner_21 <- krvote::chongun_winner |>
ungroup() |>
rename(시도명 = sido_name,
선거구 = 선거구명) |>
filter(cs_name == "제21대")
pop_tbl |>
filter(변경내역 == "생성") |>
left_join(winner_21, by = c("시도명", "선거구")) |>
count(정당명, name = "지역구수") |>
mutate(비율 = 지역구수 / sum(지역구수))
```
## 제20대 선거결과
```{r}
winner_20 <- krvote::chongun_winner |>
ungroup() |>
rename(시도명 = sido_name,
선거구 = 선거구명) |>
filter(cs_name == "제20대")
pop_tbl |>
filter(변경내역 == "소멸") |>
left_join(winner_20, by = c("시도명", "선거구")) |>
count(정당명, name = "지역구수") |>
mutate(비율 = 지역구수 / sum(지역구수))
```
# 기사화
## 선거구 총계
```{r}
library(gt)
library(gtExtras)
chg_total_gt <- pop_tbl |>
count(변경내역, name = "선거구수") |>
pivot_wider(names_from = 변경내역, values_from = 선거구수) |>
mutate(비율 = 생성 / (변동없음+생성),
총선거구 = 생성 + 변동없음) |>
relocate(총선거구, .before = 변동없음) |>
gt() |>
gt_theme_538() |>
tab_options(
heading.title.font.size = px(16L),
column_labels.font.size = px(14L),
table.font.size = px(12L)
) |>
cols_align(align = "center") |>
tab_header(
title = md("변경된 국회의원 선거구"),
subtitle = md("나무위키: 제21대 국회의원 선거/선거구 획정 ")
) |>
fmt_percent(columns = 비율, decimals = 1) |>
tab_spanner(
label = "변경 선거구수",
columns = c(
생성, 소멸
)
) |>
tab_style(
style = cell_text(color = "blue", size = px(15L), weight = "bold"),
locations = cells_body(
columns = 비율
)
)
chg_total_gt
chg_total_gt |>
gtsave(filename = "images/chg_total_gt.png")
```
## 정당별 선거결과
```{r}
winner_21 <- krvote::chongun_winner |>
ungroup() |>
rename(시도명 = sido_name,
선거구 = 선거구명) |>
filter(cs_name == "제21대")
chg_party_gt <- pop_tbl |>
filter(변경내역 == "생성") |>
left_join(winner_21, by = c("시도명", "선거구")) |>
count(정당명, name = "지역구수") |>
mutate(비율 = 지역구수 / sum(지역구수)) |>
arrange(desc(지역구수)) |>
gt() |>
gt_theme_538() |>
tab_options(
heading.title.font.size = px(16L),
column_labels.font.size = px(14L),
table.font.size = px(12L)
) |>
cols_align(align = "center") |>
tab_header(
title = md("변경 국회의원 선거구 선거결과"),
subtitle = md("나무위키 및 중앙선거관리위원회 선거통계")
) |>
fmt_percent(columns = 비율, decimals = 1) |>
## 표 전체 합계 -------------------------------------
grand_summary_rows(
columns = c(지역구수),
fns = list(label = "", fn = "sum"),
fmt = ~ fmt_integer(.),
side = "top"
) |>
grand_summary_rows(
columns = 비율,
fns = list(label = "", fn = "sum"),
fmt = ~ fmt_percent(., decimals = 1),
side = "top"
)
chg_party_gt
chg_party_gt |>
gtsave(filename = "images/chg_party_gt.png")
```
## 시도별 선거구
```{r}
winner_21 <- krvote::chongun_winner |>
ungroup() |>
rename(시도명 = sido_name,
선거구 = 선거구명) |>
filter(cs_name == "제21대")
chg_party_sido_gt <- pop_tbl |>
filter(변경내역 == "생성") |>
left_join(winner_21, by = c("시도명", "선거구")) |>
count(시도명, 정당명, name = "지역구수") |>
mutate(비율 = 지역구수 / sum(지역구수)) |>
arrange(desc(지역구수)) |>
gt(groupname_col = "정당명") |>
gt_theme_538() |>
tab_options(
heading.title.font.size = px(16L),
column_labels.font.size = px(14L),
table.font.size = px(12L)
) |>
cols_align(align = "center") |>
tab_header(
title = md("시도별 변경 국회의원 선거구 선거결과"),
subtitle = md("나무위키 및 중앙선거관리위원회 선거통계")
) |>
fmt_percent(columns = 비율, decimals = 1) |>
## 표 전체 합계 -------------------------------------
grand_summary_rows(
columns = c(지역구수),
fns = list(label = "", fn = "sum"),
fmt = ~ fmt_integer(.),
side = "top"
) |>
grand_summary_rows(
columns = 비율,
fns = list(label = "", fn = "sum"),
fmt = ~ fmt_percent(., decimals = 1),
side = "top"
)
chg_party_sido_gt
chg_party_sido_gt |>
gtsave(filename = "images/chg_party_sido_gt.png")
```
# 상세
```{r}
pop_tbl |>
filter(변경내역 == "생성") |>
left_join(winner_21, by = c("시도명", "선거구")) |>
select(시도명, 선거구, 정당명, `성명(한자)`, 득표수, 득표율, 관할구역) |>
gt(groupname_col = "시도명") |>
gt_theme_538() |>
tab_options(
heading.title.font.size = px(16L),
column_labels.font.size = px(14L),
table.font.size = px(12L)
) |>
cols_align(align = "center") |>
tab_header(
title = md("변경 국회의원 선거구 선거결과 상세"),
subtitle = md("나무위키 및 중앙선거관리위원회 선거통계")
)
```