선거구 유권자수

선거획정위원회 선거구 유권자수 변화를 살펴보자.

저자
소속

1 제21대 국회의원

1.1 데이터셋

코드
# 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")

1.2 분석

1.2.1 총계

코드
library(tidyverse)

pop_tbl <- 
  read_csv("data/제21대총선_선거구_획정.csv")

pop_tbl |> 
  mutate(변동여부 = ifelse(is.na(변동), "없음", "변동")) |> 
  count(변동여부, name = "선거구수") |> 
  mutate(비율 = 선거구수 / sum(선거구수)) |> 
  janitor::adorn_totals(name = "합계")
#>  변동여부 선거구수      비율
#>      변동       45 0.1778656
#>      없음      208 0.8221344
#>      합계      253 1.0000000

1.2.2 시도별

코드
pop_tbl |> 
  mutate(변동여부 = ifelse(is.na(변동), "미변동", "변동")) |> 
  count(시도명, 변동여부, name = "선거구수") |> 
  pivot_wider(names_from = 변동여부, values_from = 선거구수, values_fill = 0) |> 
  mutate(총선거구 = 변동 + 미변동) |> 
  mutate(변동비율 = 변동 / 총선거구) |> 
  arrange(desc(변동비율))
#> # A tibble: 17 × 5
#>    시도명         미변동  변동 총선거구 변동비율
#>    <chr>           <int> <int>    <int>    <dbl>
#>  1 세종특별자치시      0     2        2    1    
#>  2 강원도              3     5        8    0.625
#>  3 전라남도            6     4       10    0.4  
#>  4 인천광역시          8     5       13    0.385
#>  5 경상북도            9     4       13    0.308
#>  6 경기도             41    18       59    0.305
#>  7 전라북도            7     3       10    0.3  
#>  8 경상남도           14     2       16    0.125
#>  9 부산광역시         16     2       18    0.111
#> 10 광주광역시          8     0        8    0    
#> 11 대구광역시         12     0       12    0    
#> 12 대전광역시          7     0        7    0    
#> 13 서울특별시         49     0       49    0    
#> 14 울산광역시          6     0        6    0    
#> 15 제주특별자치도      3     0        3    0    
#> 16 충청남도           11     0       11    0    
#> 17 충청북도            8     0        8    0

2 제20대 국회의원

2.1 데이터셋

코드
# 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")

2.2 분석

2.2.1 총계

코드
library(tidyverse)

pop20_tbl <- 
  read_csv("data/제20대총선_선거구_획정.csv")

pop21_tbl <- 
  read_csv("data/제21대총선_선거구_획정.csv")

2.2.2 시도별

코드
pop20_tbl |> 
  count(시도명, name = "선거구수", sort=TRUE) |> 
  mutate(비율 = 선거구수 / sum(선거구수)) |> 
  arrange(desc(비율)) |> 
  mutate(누적비율 = cumsum(비율)) 
#> # A tibble: 17 × 4
#>    시도명         선거구수    비율 누적비율
#>    <chr>             <int>   <dbl>    <dbl>
#>  1 경기도               65 0.246      0.246
#>  2 서울특별시           50 0.189      0.436
#>  3 부산광역시           19 0.0720     0.508
#>  4 경상남도             16 0.0606     0.568
#>  5 경상북도             13 0.0492     0.617
#>  6 인천광역시           13 0.0492     0.667
#>  7 충청남도             13 0.0492     0.716
#>  8 대구광역시           12 0.0455     0.761
#>  9 전라북도             11 0.0417     0.803
#> 10 전라남도             10 0.0379     0.841
#> 11 광주광역시            9 0.0341     0.875
#> 12 강원도                8 0.0303     0.905
#> 13 충청북도              8 0.0303     0.936
#> 14 대전광역시            7 0.0265     0.962
#> 15 울산광역시            6 0.0227     0.985
#> 16 제주특별자치도        3 0.0114     0.996
#> 17 세종특별자치시        1 0.00379    1

3 제20~21대 교차분석

코드

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=""))

3.1 제21대 선거결과

코드
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(지역구수))
#> # A tibble: 3 × 3
#>   정당명       지역구수   비율
#>   <chr>           <int>  <dbl>
#> 1 더불어민주당       11 0.524 
#> 2 무소속              1 0.0476
#> 3 미래통합당          9 0.429

3.2 제20대 선거결과

코드
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(지역구수))
#> # A tibble: 4 × 3
#>   정당명       지역구수   비율
#>   <chr>           <int>  <dbl>
#> 1 국민의당            1 0.0476
#> 2 더불어민주당        6 0.286 
#> 3 무소속              4 0.190 
#> 4 새누리당           10 0.476

4 기사화

4.1 선거구 총계

코드
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
변경된 국회의원 선거구
나무위키: 제21대 국회의원 선거/선거구 획정
총선거구 변동없음 변경 선거구수 비율
생성 소멸
253 232 21 21 8.3%
코드

chg_total_gt |>
  gtsave(filename = "images/chg_total_gt.png")

4.2 정당별 선거결과

코드
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
변경 국회의원 선거구 선거결과
나무위키 및 중앙선거관리위원회 선거통계
정당명 지역구수 비율
21 100.0%
더불어민주당 11 52.4%
미래통합당 9 42.9%
무소속 1 4.8%
코드

chg_party_gt |>
  gtsave(filename = "images/chg_party_gt.png")

4.3 시도별 선거구

코드
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
시도별 변경 국회의원 선거구 선거결과
나무위키 및 중앙선거관리위원회 선거통계
시도명 지역구수 비율
21 100.0%
더불어민주당
경기도 5 23.8%
세종특별자치시 2 9.5%
전라남도 2 9.5%
강원도 1 4.8%
인천광역시 1 4.8%
미래통합당
강원도 4 19.0%
경상북도 4 19.0%
인천광역시 1 4.8%
무소속
인천광역시 1 4.8%
코드

chg_party_sido_gt |>
  gtsave(filename = "images/chg_party_sido_gt.png")

5 상세

코드
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("나무위키 및 중앙선거관리위원회 선거통계")
  ) 
변경 국회의원 선거구 선거결과 상세
나무위키 및 중앙선거관리위원회 선거통계
선거구 정당명 성명(한자) 득표수 득표율 관할구역
인천광역시
중구강화군옹진군 미래통합당 배준영(裵俊英) 62484 50.28 중구 전 지역, 강화군 전 지역, 옹진군 전 지역
동구미추홀구갑 더불어민주당 허종식(許琮植) 63480 48.77 미추홀구 주안1동, 주안2동, 주안3동, 주안4동, 주안5동, 주안6동, 주안7동, 주안8동, 도화1동, 도화2·3동 + 동구 전 지역
동구미추홀구을 무소속 윤상현(尹相現) 46493 40.59 미추홀구 용현1·4동, 용현2동, 용현3동, 용현5동, 숭의1·3동, 숭의2동, 숭의4동, 학익1동, 학익2동, 관교동, 문학동
세종특별자치시
세종특별자치시갑 더불어민주당 홍성국(洪性國) 55947 56.45 부강면, 금남면, 장군면, 한솔동, 새롬동, 도담동, 소담동, 보람동, 대평동
세종특별자치시을 더불어민주당 강준현(康準鉉) 46002 57.96 조치원읍, 연기면, 연동면, 연서면, 전의면, 전동면, 소정면, 아름동, 종촌동, 고운동
경기도
부천시갑 더불어민주당 김경협(金炅俠) 48002 59.17 부천시 심곡동, 부천동
부천시을 더불어민주당 설훈(薛勳) 80889 54.9 부천시 중동, 신중동, 상동
부천시병 더불어민주당 김상희(金相姬) 77577 60.55 부천시 대산동, 소사본동, 범안동
부천시정 더불어민주당 서영석(徐暎錫) 49552 56.74 부천시 성곡동, 오정동
군포시 더불어민주당 이학영(李學永) 91256 57.41 군포시 전 지역
강원도
춘천시철원군화천군양구군갑 더불어민주당 허영(許榮) 66932 51.32 춘천시 후평1동, 후평2동, 후평3동, 효자1동, 효자2동, 효자3동, 약사명동, 조운동, 근화동, 소양동, 석사동, 퇴계동, 강남동, 동산면, 신동면, 동내면, 남산면, 남면
춘천시철원군화천군양구군을 미래통합당 한기호(韓起鎬) 43083 52.07 춘천시 신사우동, 신북읍, 사북면, 북산면, 동면, 서면 + 철원군 전 지역, 화천군 전 지역, 양구군 전 지역
동해시태백시삼척시정선군 미래통합당 이철규(李喆圭) 71604 53.6 동해시 전 지역, 태백시 전 지역, 삼척시 전 지역, 정선군 전 지역
속초시인제군고성군양양군 미래통합당 이양수(李亮壽) 50188 52.56 속초시 전 지역, 인제군 전 지역, 고성군 전 지역, 양양군 전 지역
홍천군횡성군영월군평창군 미래통합당 유상범(劉相凡) 55975 48.59 홍천군 전 지역, 횡성군 전 지역, 영월군 전 지역, 평창군 전 지역
전라남도
순천시광양시곡성군구례군갑 더불어민주당 소병철(蘇秉哲) 78480 58.56 순천시 왕조1동, 왕조2동, 매곡동, 삼산동, 조곡동, 덕연동, 풍덕동, 남제동, 저전동, 장천동, 중앙동, 도사동, 향동, 승주읍, 황전면, 월등면, 주암면, 송광면, 외서면, 낙안면, 별량면, 상사면, 서면
순천시광양시곡성군구례군을 더불어민주당 서동용(徐東榕) 92442 64.75 순천시 해룡면 + 광양시 전 지역, 곡성군 전 지역, 구례군 전 지역
경상북도
안동시예천군 미래통합당 김형동(金亨東) 58183 47.1 안동시 전 지역, 예천군 전 지역
영주시영양군봉화군울진군 미래통합당 박형수(朴亨修) 68026 55.83 영주시 전 지역, 영양군 전 지역, 봉화군 전 지역, 울진군 전 지역
상주시문경시 미래통합당 임이자(林利子) 65558 64.8 상주시 전 지역, 문경시 전 지역
군위군의성군청송군영덕군 미래통합당 김희국(金熙國) 71532 79.3 군위군 전 지역, 의성군 전 지역, 청송군 전 지역, 영덕군 전 지역