서울시장

서울시장 민주당 박영선 후보와 국민의 힘 오세훈 후보 득표를 분석합니다.

자치구별 투표율

library(tidyverse)
library(rvest)
library(reactable)

## 위키백과 HTML 웹페이지 긁어오기
seoul_wiki_url <- "https://ko.wikipedia.org/wiki/2021%EB%85%84_%EC%84%9C%EC%9A%B8%ED%8A%B9%EB%B3%84%EC%8B%9C%EC%9E%A5_%EB%B3%B4%EA%B6%90%EC%84%A0%EA%B1%B0"

seoul_wiki_html <- seoul_wiki_url %>% 
  read_html() 

# Sys.setlocale("LC_ALL", locale = "C")

## 투표수와 투표율 표 긁어내기
seoul_vote_raw <- seoul_wiki_html %>% 
  html_nodes(xpath = '//*[@id="mw-content-text"]/div[1]/table[8]') %>% 
  html_table(fill = TRUE) %>% 
  .[[1]] %>% 
  as_tibble()

# Sys.setlocale("LC_ALL", locale = "Korean")


## 투표수와 투표율 표 데이터 전처리
seoul_vote_tbl <- seoul_vote_raw %>%
  filter( != "서울특별시") %>% 
  mutate(유권자 = parse_number(유권자),
         투표수 = parse_number(투표수),
         투표율 = parse_number(투표율) / 100) %>% 
  mutate(서울권역 = case_when( %in% c("종로구", "중구", "용산구", "은평구", "서대문구", "마포구") ~ "강북서권",
                               %in% c("성동구", "광진구", "동대문구", "중랑구", "성북구", "강북구", "도봉구", "노원구") ~ "강북동권",
                               %in% c("양천구", "강서구", "구로구", "금천구", "영등포구", "동작구", "관악구") ~ "강남서권",
                               %in% c("서초구", "강남구", "송파구", "강동구") ~ "강남동권")) %>% 
  relocate(서울권역, .before = )
 

## 투표수와 투표율 표 

seoul_vote_tbl %>% 
  reactable::reactable(
    groupBy = "서울권역",
    filterable = TRUE,
    searchable = TRUE, minRows = 4,
      columns = list(
        서울권역 = colDef(minWidth = 160),
        유권자 = colDef(minWidth = 140, format = colFormat(separators = TRUE, digits = 0), aggregate = "sum"),
        투표수 = colDef(minWidth = 140, format = colFormat(separators = TRUE, digits = 0), aggregate = "sum"),
        투표율 = colDef(minWidth = 140, format = colFormat(percent = TRUE, digits = 1), aggregate = "mean")
      ),
      bordered = TRUE,
      highlight = TRUE
)

출구조사

2021년 4월 7일 오전 6시부터 오후 7시까지 조사하였으며, 표본오차는 95% 신뢰수준, 서울 ± 1.7%p 부산 ± 2.3%p이다. 조사 장소는 서울 50개 투표소, 부산 30개 투표소이며, 조사 인원은 서울 10,114명, 부산 5,639명이다.

구별 득표

https://ko.wikipedia.org/wiki/2021년_서울특별시장_보궐선거 웹페이지에서 자치구별 결과를 가져온다.

## 득표

# Sys.setlocale("LC_ALL", locale = "C")

seoul_raw <- seoul_wiki_html %>% 
  html_nodes(xpath = '//*[@id="mw-content-text"]/div[1]/div[4]/table/tbody/tr/td[1]/table') %>% 
  html_table(fill = TRUE) %>% 
  .[[1]] %>% 
  janitor::clean_names() %>% 
  as_tibble()

# Sys.setlocale("LC_ALL", locale = "Korean")

## 투표수와 투표율 표 데이터 전처리
seoul_tbl <- seoul_raw %>%
  select(1, 2, 3, 5, 6) %>% 
  set_names(c("구", "박영선", "오세훈", "박득표율", "오득표율")) %>% 
  slice(2:n()) %>% 
  filter( != "서울특별시") %>% 
  mutate(박영선 = parse_number(박영선),
         오세훈 = parse_number(오세훈),
         박득표율 = parse_number(박득표율) /100,
         오득표율 = parse_number(오득표율) /100) %>% 
  mutate(서울권역 = case_when( %in% c("종로구", "중구", "용산구", "은평구", "서대문구", "마포구") ~ "강북서권",
                               %in% c("성동구", "광진구", "동대문구", "중랑구", "성북구", "강북구", "도봉구", "노원구") ~ "강북동권",
                               %in% c("양천구", "강서구", "구로구", "금천구", "영등포구", "동작구", "관악구") ~ "강남서권",
                               %in% c("서초구", "강남구", "송파구", "강동구") ~ "강남동권")) %>% 
  relocate(서울권역, .before = ) 
  

seoul_tbl %>% 
    reactable::reactable(
    groupBy = "서울권역",
    filterable = TRUE,
    searchable = TRUE, minRows = 4,
      columns = list(
        서울권역 = colDef(minWidth = 160),
        박영선 = colDef(minWidth = 140, format = colFormat(separators = TRUE, digits = 0), aggregate = "sum"),
        오세훈 = colDef(minWidth = 140, format = colFormat(separators = TRUE, digits = 0), aggregate = "sum"),
        박득표율 = colDef(minWidth = 140, format = colFormat(percent = TRUE, digits = 1), aggregate = "mean"),
        오득표율 = colDef(minWidth = 140, format = colFormat(percent = TRUE, digits = 1), aggregate = "mean")
      ),
      bordered = TRUE,
      highlight = TRUE
)

투표구별

seoul_tbl <- read_rds("data/seoul_tbl.rds")

seoul_tbl %>% 
  mutate(표차이 = 국힘당 - 민주당) %>% 
  select(-기권) %>% 
    reactable::reactable(
    groupBy = c("구명", "읍면동명", "투표구명"),
    filterable = TRUE,
    searchable = TRUE, 
    defaultPageSize = 25,
      columns = list(
        구명 = colDef(minWidth = 100),
        읍면동명 = colDef(minWidth = 140),
        투표구명 = colDef(minWidth = 140),
        선거인수 = colDef(minWidth = 100, format = colFormat(separators = TRUE, digits = 0), aggregate = "sum"),
        투표수 = colDef(minWidth = 100, format = colFormat(separators = TRUE, digits = 0), aggregate = "sum"),
        민주당 = colDef(minWidth = 100, format = colFormat(separators = TRUE, digits = 0), aggregate = "sum"),
        국힘당 = colDef(minWidth = 100, format = colFormat(separators = TRUE, digits = 0), aggregate = "sum"),
        표차이 = colDef(minWidth = 100, format = colFormat(separators = TRUE, digits = 0), aggregate = "sum")
      ),
      bordered = TRUE,
      highlight = TRUE
)