광명시(총/대/지)

광명시 총/대/지선 선거결과를 살펴보자.

저자
소속

1 데이터

코드
library(tidyverse)
library(krvote)

president <- krvote::election_20220309$득표율 |> 
  filter(시도명 == "경기도",
         구시군명 == "광명시")

local_sido <- krvote::local_sido_20220601 |> 
  filter(선거구명 == "경기도") |> 
  unnest(data) |> 
  filter(구시군명 == "광명시")

local_mayor <- krvote::local_sgg_20220601 |> 
  filter(시도명 == "경기도",
         구시군명 == "광명시")

chongsun <- krvote::general_2020 |> 
  filter(시도 == "경기",
         str_detect(선거구, "광명")) |> 
  unnest(data) |> 
  mutate(구분 = case_when(str_detect(구분, "^[가-힣]") ~ 구분,
                            TRUE ~ iconv(구분, from = "CP949", to = "UTF-8")))
선거 민주당 국민의힘
2022년 대선 103,470 87,112
2022년 도지사 72,415 63,270
2022년 시장 73,759 64,255
2020년 총선 갑 43,019 33,380
2020년 총선 을 58,130 27,671

2 분석

2.1 종합

코드
# 대통령
president_ttl <- president |> 
  pivot_longer(이재명:김민찬) |> 
  mutate(정당 = case_when(name == "이재명" ~ "민주당",
                          name == "윤석열" ~ "국민의힘",
                          TRUE ~ "기타")) |> 
  group_by(정당) |> 
  summarise(득표 = sum(value)) |> 
  mutate(선거 = "대선_2022")

# 도지사
local_sido_ttl <- local_sido |> 
  pivot_longer(더불어민주당_김동연:무소속_강용석) |> 
  separate(name, into = c("정당", "후보명"), sep = "_") |> 
  mutate(정당 = case_when(str_detect(정당, "더불어민주당") ~ "민주당",
                          str_detect(정당, "국민의힘") ~ "국민의힘",
                          TRUE ~ "기타")) |> 
  group_by(정당) |> 
  summarise(득표 = sum(value)) |> 
  mutate(선거 = "도지사_2022")  

# 시장
local_mayor_ttl <- local_mayor |> 
  mutate(득표 = parse_number(득표)) |> 
  mutate(정당 = case_when(str_detect(정당, "더불어민주당") ~ "민주당",
                          str_detect(정당, "국민의힘") ~ "국민의힘",
                          TRUE ~ "기타")) |> 
  group_by(정당) |> 
  summarise(득표 = sum(득표)) |> 
  mutate(선거 = "시장_2022")    

# 국회의원
chongsun_ttl <- chongsun |> 
  filter(구분 %in% c("국가혁명배당금당 김상연", "국가혁명배당금당 김현애", "더불어민주당 양기대", "더불어민주당 임오경", "무소속 권태진", "무소속 김경표", "무소속 김기윤", "미래통합당 김용태", "미래통합당 양주상", "민생당 양순필")) |> 
  separate(구분, into = c("정당", "후보"), sep = " ") |> 
  mutate(정당 = case_when(str_detect(정당, "더불어민주당") ~ "민주당",
                          str_detect(정당, "미래통합당") ~ "국민의힘",
                          TRUE ~ "기타")) |> 
  group_by(정당) |> 
  summarise(득표 = sum(사람수)) |> 
  mutate(선거 = "총선_2020")      
코드
ttl_tbl <- bind_rows(chongsun_ttl, president_ttl) |> 
  bind_rows(local_sido_ttl) |> 
  bind_rows(local_mayor_ttl) |> 
  mutate(선거 = factor(선거, levels = c("총선_2020", "대선_2022", "도지사_2022", "시장_2022")))

kwangmyung_ttl_gg <- ttl_tbl |> 
  ggplot(aes(x = 선거, y = 득표, color = 정당, group = 정당)) +
    geom_line() +
    geom_point() +
    scale_y_continuous(labels = scales::comma) +
    labs(x="", y="득표수",
         title = "광명시 역대 선거 정당별 득표수") +
    scale_color_manual(values = c("국민의힘" = "red",
                                  "민주당"   = "blue",
                                  "기타"     = "gray50")) +
    theme(legend.position = "top")

kwangmyung_ttl_gg

ragg::agg_jpeg("images/kwangmyung/광명시_총계.jpeg",
              width = 10, height = 7, units = "in", res = 600)
kwangmyung_ttl_gg
dev.off()

2.2 동별

코드
# 대통령
president_dong <- president |> 
  pivot_longer(이재명:김민찬) |> 
  mutate(정당 = case_when(name == "이재명" ~ "민주당",
                          name == "윤석열" ~ "국민의힘",
                          TRUE ~ "기타")) |> 
  filter(!str_detect(읍면동명, "^잘못")) |> 
  mutate(읍면동명 = case_when(str_detect(읍면동명, "국외|재외") ~ "국외부재자",
                              str_detect(읍면동명, "거소") ~ "거소·선상",
                              TRUE ~ 읍면동명)) |>   
  group_by(읍면동명, 정당) |> 
  summarise(득표 = sum(value)) |> 
  ungroup() |> 
  mutate(선거 = "대선_2022")

# 도지사
local_sido_dong <- local_sido |> 
  pivot_longer(더불어민주당_김동연:무소속_강용석) |> 
  separate(name, into = c("정당", "후보명"), sep = "_") |> 
  mutate(정당 = case_when(str_detect(정당, "더불어민주당") ~ "민주당",
                          str_detect(정당, "국민의힘") ~ "국민의힘",
                          TRUE ~ "기타")) |> 
  filter(!str_detect(읍면동명, "^잘못")) |> 
  mutate(읍면동명 = case_when(str_detect(읍면동명, "국외|재외") ~ "국외부재자",
                              str_detect(읍면동명, "거소") ~ "거소·선상",
                              TRUE ~ 읍면동명)) |>   
  group_by(읍면동명, 정당) |> 
  summarise(득표 = sum(value)) |> 
  ungroup() |>   
  mutate(선거 = "도지사_2022")

# 시장
local_mayor_dong <- local_mayor |> 
  mutate(득표 = parse_number(득표)) |> 
  mutate(정당 = case_when(str_detect(정당, "더불어민주당") ~ "민주당",
                          str_detect(정당, "국민의힘") ~ "국민의힘",
                          TRUE ~ "기타")) |> 
  filter(!str_detect(읍면동명, "^잘못")) |> 
  mutate(읍면동명 = case_when(str_detect(읍면동명, "국외|재외") ~ "국외부재자",
                              str_detect(읍면동명, "거소") ~ "거소·선상",
                              TRUE ~ 읍면동명)) |>   
  group_by(읍면동명, 정당) |> 
  summarise(득표 = sum(득표)) |> 
  ungroup() |>     
  mutate(선거 = "시장_2022")


# 국회의원
chongsun_dong <- chongsun |> 
  filter(구분 %in% c("국가혁명배당금당 김상연", "국가혁명배당금당 김현애", "더불어민주당 양기대", "더불어민주당 임오경", "무소속 권태진", "무소속 김경표", "무소속 김기윤", "미래통합당 김용태", "미래통합당 양주상", "민생당 양순필")) |> 
  separate(구분, into = c("정당", "후보"), sep = " ") |> 
  mutate(정당 = case_when(str_detect(정당, "더불어민주당") ~ "민주당",
                          str_detect(정당, "미래통합당") ~ "국민의힘",
                          TRUE ~ "기타")) |> 
  filter(!str_detect(읍면동명, "^잘못")) |> 
  mutate(읍면동명 = case_when(str_detect(읍면동명, "국외|재외") ~ "국외부재자",
                              str_detect(읍면동명, "거소") ~ "거소·선상",
                              TRUE ~ 읍면동명)) |>   
  group_by(읍면동명, 정당) |> 
  summarise(득표 = sum(사람수)) |> 
  ungroup() |>       
  mutate(선거 = "총선_2020")
     
  
코드
dong_tbl <- bind_rows(chongsun_dong, president_dong) |> 
  bind_rows(local_sido_dong) |> 
  bind_rows(local_mayor_dong) |> 
  mutate(선거 = factor(선거, levels = c("총선_2020", "대선_2022", "도지사_2022", "시장_2022")))

kwangmyung_dong_gg <- dong_tbl |> 
  ggplot(aes(x = 선거, y = 득표, color = 정당, group = 정당)) +
    geom_line() +
    geom_point() +
    scale_y_continuous(labels = scales::comma) +
    labs(x="", y="득표수",
         title = "광명시 역대 선거 정당별 득표수") +
    scale_color_manual(values = c("국민의힘" = "red",
                                  "민주당"   = "blue",
                                  "기타"     = "gray50")) +
    theme(legend.position = "top") +
    facet_wrap(~읍면동명, scales = "free_y")

kwangmyung_dong_gg

ragg::agg_jpeg("images/kwangmyung/광명시_동별.jpeg",
              width = 10, height = 7, units = "in", res = 600)
kwangmyung_dong_gg
dev.off()

3 인구수

3.1 데이터

행정안전부 주민등록 인구통계

코드
library(readxl)

# 2020-04-15 ---------------------------------
pop_202004_raw <- read_excel("data/202004_202004_연령별인구현황_월간.xlsx", skip = 2)

pop_202004 <- pop_202004_raw |> 
  janitor::clean_names(ascii = FALSE) |> 
  select(x1, x2, x107:x208, x210:x311) |> 
  janitor::row_to_names(row_number = 1) |> 
  janitor::clean_names(ascii = FALSE) |> 
  pivot_longer(cols = 연령구간인구수:x100세_이상_2) |> 
  filter(!str_detect(name, "^연령구간")) |> 
  mutate(성별 = ifelse(str_detect(name, "_2$"), "여자", "남자")) |> 
  mutate(나이 = parse_number(name),
         인구수 = parse_number(value)) |> 
  filter(!str_detect(행정기관, "경기도 경기도") )  |> 
  mutate(행정동 = str_remove(행정기관, "경기도 광명시 ")) |> 
  mutate(시점 = "2020-04-15") |> 
  select(시점, 행정동, 성별, 나이, 인구수) 

pop_202004

# 2022-03-15 ---------------------------------
pop_202203_raw <- read_excel("data/202203_202203_연령별인구현황_월간.xlsx", skip = 2)

pop_202203 <- pop_202203_raw |> 
  janitor::clean_names(ascii = FALSE) |> 
  select(x1, x2, x107:x208, x210:x311) |> 
  janitor::row_to_names(row_number = 1) |> 
  janitor::clean_names(ascii = FALSE) |> 
  pivot_longer(cols = 연령구간인구수:x100세_이상_2) |> 
  filter(!str_detect(name, "^연령구간")) |> 
  mutate(성별 = ifelse(str_detect(name, "_2$"), "여자", "남자")) |> 
  mutate(나이 = parse_number(name),
         인구수 = parse_number(value)) |> 
  filter(!str_detect(행정기관, "경기도 경기도") )  |> 
  mutate(행정동 = str_remove(행정기관, "경기도 광명시 ")) |> 
  mutate(시점 = "2022-03-15") |> 
  select(시점, 행정동, 성별, 나이, 인구수) 

pop_202203

# 2023-07-15 ---------------------------------
pop_202307_raw <- read_excel("data/202307_202307_연령별인구현황_월간.xlsx", skip = 2)

pop_202307 <- pop_202307_raw |> 
  janitor::clean_names(ascii = FALSE) |> 
  select(x1, x2, x107:x208, x210:x311) |> 
  janitor::row_to_names(row_number = 1) |> 
  janitor::clean_names(ascii = FALSE) |> 
  pivot_longer(cols = 연령구간인구수:x100세_이상_2) |> 
  filter(!str_detect(name, "^연령구간")) |> 
  mutate(성별 = ifelse(str_detect(name, "_2$"), "여자", "남자")) |> 
  mutate(나이 = parse_number(name),
         인구수 = parse_number(value)) |> 
  filter(!str_detect(행정기관, "경기도 경기도") )  |> 
  mutate(행정동 = str_remove(행정기관, "경기도 광명시 ")) |> 
  mutate(시점 = "2023-07-15") |> 
  select(시점, 행정동, 성별, 나이, 인구수) 

pop_202307

pop_tbl <- bind_rows(pop_202307, pop_202203, pop_202004)

pop_tbl |> 
  write_rds("data/kwangmyung_pop.rds")

3.2 분석

3.2.1 유권자

코드
library(ggrepel)

pop_tbl <- 
  read_rds("data/kwangmyung_pop.rds") |> 
  mutate(시점 = lubridate::ymd(시점))

km_voter_ttl_gg <- pop_tbl |> 
  mutate(유권자 = ifelse(나이 >= 19, "유권자", "무권자")) |> 
  group_by(시점, 유권자) |> 
  summarise(인구수 = sum(인구수)) |> 
  ggplot(aes(x = 시점, y = 인구수, group = 유권자, color = 유권자)) +
    geom_line() +
    geom_point(size = 3) +
    scale_y_continuous(labels = scales::comma) +
    expand_limits(y = c(0, 300000)) +
    geom_text_repel(aes(label = scales::comma(인구수))) +
    labs(x = "",
         y = "인구수",
         title = "광명시 최근 인구수와 유권자수",
         subtitle = "행정안전부 주민등록, 광명시 19세이상 유권자 기준") +
    theme(legend.position = "top") +
    scale_color_manual(values = c("유권자" = "blue",
                                  "무권자" = "gray30")) +
    scale_x_date(date_labels = "%y-%m", date_breaks = "6 month")

km_voter_ttl_gg

ragg::agg_jpeg("images/kwangmyung/광명시_유권자수.jpeg",
              width = 10, height = 7, units = "in", res = 600)
km_voter_ttl_gg
dev.off()  

3.2.2 동별 유권자

코드
km_voter_dong_gg <- pop_tbl |> 
  mutate(유권자 = ifelse(나이 >= 19, "유권자", "무권자")) |> 
  group_by(시점, 행정동, 유권자) |> 
  summarise(인구수 = sum(인구수)) |> 
  mutate(유권자비율 = 인구수 / sum(인구수)) |> 
  ungroup() |> 
  ggplot(aes(x = 시점, y = 인구수, group = 유권자, color = 유권자)) +
    geom_line() +
    geom_point(size = 3) +
    scale_y_sqrt(labels = scales::comma) +
    expand_limits(y = c(0, 45000)) +
    geom_text_repel(aes(label = scales::comma(인구수))) +
    labs(x = "",
         y = "인구수",
         title = "광명시 동별 인구수와 유권자수",
         subtitle = "행정안전부 주민등록, 광명시 19세이상 유권자 기준") +
    theme(legend.position = "top",
          axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
    scale_color_manual(values = c("유권자" = "blue",
                                  "무권자" = "gray30")) +
    facet_wrap(~행정동) +
    scale_x_date(date_labels = "%y-%m", date_breaks = "6 month")
  

km_voter_dong_gg

ragg::agg_jpeg("images/kwangmyung/광명시_동별_유권자수.jpeg",
              width = 10, height = 7, units = "in", res = 600)
km_voter_dong_gg
dev.off()  

3.2.3 세대별 (3040기준)

코드
km_age_ttl_gg <- pop_tbl |> 
  mutate(세대 = case_when(나이 >= 19 & 나이 < 30 ~ "1020대",
                            나이 >= 30 & 나이 < 50 ~ "3040대",
                            나이 >= 50 ~ "50이상")) |> 
  filter(!is.na(세대)) |> 
  group_by(시점, 세대) |> 
  summarise(인구수 = sum(인구수)) |> 
  ungroup() |> 
  ggplot(aes(x = 시점, y = 인구수, group = 세대, color = 세대)) +
    geom_line() +
    geom_point(size = 3) +
    scale_y_continuous(labels = scales::comma) +
    expand_limits(y = c(50000, 120000)) +
    geom_text_repel(aes(label = scales::comma(인구수))) +
    labs(x = "",
         y = "인구수",
         title = "광명시 연령별 유권자수",
         subtitle = "행정안전부 주민등록, 광명시 19세이상 유권자 기준") +
    theme(legend.position = "top",
          axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
    scale_color_manual(values = c("1020대" = "black",
                                  "3040대" = "blue",
                                  "50이상" = "red")) +
    scale_x_date(date_labels = "%y-%m", date_breaks = "6 month")
  

km_age_ttl_gg

ragg::agg_jpeg("images/kwangmyung/광명시_세대별_유권자수.jpeg",
              width = 10, height = 7, units = "in", res = 600)
km_age_ttl_gg
dev.off()  

3.2.4 세대별 (4050기준)

코드
km_age_ttl_4050_gg <- pop_tbl |> 
  mutate(세대 = case_when(나이 >= 19 & 나이 < 40 ~ "1030대",
                            나이 >= 40 & 나이 < 60 ~ "4050대",
                            나이 >= 60 ~ "60이상")) |> 
  filter(!is.na(세대)) |> 
  group_by(시점, 세대) |> 
  summarise(인구수 = sum(인구수)) |> 
  ungroup() |> 
  ggplot(aes(x = 시점, y = 인구수, group = 세대, color = 세대)) +
    geom_line() +
    geom_point(size = 3) +
    scale_y_continuous(labels = scales::comma) +
    expand_limits(y = c(50000, 120000)) +
    geom_text_repel(aes(label = scales::comma(인구수))) +
    labs(x = "",
         y = "인구수",
         title = "광명시 연령별 유권자수",
         subtitle = "행정안전부 주민등록, 광명시 19세이상 유권자 기준") +
    theme(legend.position = "top",
          axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
    scale_color_manual(values = c("1030대" = "black",
                                  "4050대" = "blue",
                                  "60이상" = "red")) +
    scale_x_date(date_labels = "%y-%m", date_breaks = "6 month")
  

km_age_ttl_4050_gg

ragg::agg_jpeg("images/kwangmyung/광명시_세대별_4050_유권자수.jpeg",
              width = 10, height = 7, units = "in", res = 600)
km_age_ttl_4050_gg
dev.off()  

3.2.5 동별X세대별 (3040기준)

코드
km_age_dong_gg <- pop_tbl |> 
  mutate(세대 = case_when(나이 >= 19 & 나이 < 30 ~ "1020대",
                            나이 >= 30 & 나이 < 50 ~ "3040대",
                            나이 >= 50 ~ "50이상")) |> 
  filter(!is.na(세대)) |> 
  group_by(시점, 행정동, 세대) |> 
  summarise(인구수 = sum(인구수)) |> 
  ungroup() |> 
  ggplot(aes(x = 시점, y = 인구수, group = 세대, color = 세대)) +
    geom_line() +
    geom_point(size = 3) +
    scale_y_continuous(labels = scales::comma) +
    geom_text_repel(aes(label = scales::comma(인구수))) +
    labs(x = "",
         y = "인구수",
         title = "광명시 동별, 연령별 유권자수(3040기준)",
         subtitle = "행정안전부 주민등록, 광명시 19세이상 유권자 기준") +
    theme(legend.position = "top",
          axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
    scale_color_manual(values = c("1020대" = "black",
                                  "3040대" = "blue",
                                  "50이상" = "red")) +
    scale_x_date(date_labels = "%y-%m", date_breaks = "6 month") +
    facet_wrap(~행정동)
  

km_age_dong_gg

ragg::agg_jpeg("images/kwangmyung/광명시_동별_세대별_유권자수.jpeg",
              width = 10, height = 7, units = "in", res = 600)
km_age_dong_gg
dev.off()  

3.2.6 동별X세대별 (4050기준)

코드
km_age_dong_4050_gg <- pop_tbl |> 
  mutate(세대 = case_when(나이 >= 19 & 나이 < 40 ~ "1030대",
                            나이 >= 40 & 나이 < 60 ~ "4050대",
                            나이 >= 60 ~ "60이상")) |> 
  filter(!is.na(세대)) |> 
  group_by(시점, 행정동, 세대) |> 
  summarise(인구수 = sum(인구수)) |> 
  ungroup() |> 
  ggplot(aes(x = 시점, y = 인구수, group = 세대, color = 세대)) +
    geom_line() +
    geom_point(size = 3) +
    scale_y_continuous(labels = scales::comma) +
    geom_text_repel(aes(label = scales::comma(인구수))) +
    labs(x = "",
         y = "인구수",
         title = "광명시 연령별 행정동별 유권자수 (4050기준)",
         subtitle = "행정안전부 주민등록, 광명시 19세이상 유권자 기준") +
    theme(legend.position = "top",
          axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
    scale_color_manual(values = c("1030대" = "black",
                                  "4050대" = "blue",
                                  "60이상" = "red")) +
    scale_x_date(date_labels = "%y-%m", date_breaks = "6 month") +
    facet_wrap(~행정동)

km_age_dong_4050_gg

ragg::agg_jpeg("images/kwangmyung/광명시_세대별_동별_4050_유권자수.jpeg",
              width = 10, height = 7, units = "in", res = 600)
km_age_dong_4050_gg
dev.off()