학습 목표

제18대 대선 데이터

2012년도 대통령 선거 투표결과 데이터는 중앙선거관리위원회 홈페이지에서 다운로드 받을 수 있다.

중앙선거관리위원회 → 분야별 정보 → 선거정보 → 하단 자료실

환경설정

공간정보를 활용하여 18대 대선 투표결과를 시각화하는데 많은 팩키지가 동원된다.

# 0. 환경설정-------------------------------------------
library(tidyverse)
library(readxl)
library(ggmap)
library(maps)
library(maptools)
library(RColorBrewer)
library(scales)
library(rgdal)
library(rgeos)
library(maptools)
library(gpclib)
library(tmap)
library(viridis)
library(stringr)
library(xts)
library(zoo)
#gpclibPermit()

데이터 가져오기

지리정보를 시각화할 경우 지도데이터(.shp)와 투표결과데이터(엑셀 파일, 선관위 배포 기준)가 필요하다.

지도데이터

지도데이터는 그 시점에 맞는 행정지도를 받아 활용한다. 최신 행정구역(SHP) 다운로드 받을 때, 투표 주제도를 시각화할 단위를 시도, 시군구, 읍면동, 기준에 맞춰 미리 결정한다.

# 1. 지도 가져오기-------------------------------------------

korea_sido_shp <-  readShapeSpatial("data/shapefile_sido/TL_SCCO_CTPRVN.shp", verbose=TRUE, 
                                     proj4string=CRS("+proj=tmerc +lat_0=38 +lon_0=127 +k=1 +x_0=955000 +y_0=2000000 
                                                     +ellps=GRS80 +units=m +no_defs"))
Shapefile type: Polygon, (5), # of Shapes: 17
Shapefile type: Polygon, (5), # of Shapes: 17

대선 투표 데이터

지도데이터와 마찬가지로 선관위 홈페이지에서 다운로드 한 엑셀 파일을 지도데이터에 맞춰 가공한다.

# 2. 데이터 가져오기-------------------------------------------
## 2.1. 대선 투표 데이터 --------------------------------------
dat <- read_excel("data/제18대 대선 투표구별 개표자료.xls", sheet="대통령", skip=4)
names(dat) <- c("sido", "sigun", "emd", "vote_station", "polls", "votes", "pgh", "mji","etc_01", "etc_02", "etc_03", "etc_04","subtlt", "invalid", "abstain")
glimpse(dat)
Observations: 18,122
Variables: 15
$ sido         <chr> "전국", "서울특별시", "서울특별시", "서울특별시", "서울특별시", "서울특별시"...
$ sigun        <chr> "합계", "합계", "종로구", "종로구", "종로구", "종로구", "종로구", "종...
$ emd          <chr> NA, NA, "소계", "재외투표", "국내부재자투표", "소계", "청운효자동", N...
$ vote_station <chr> NA, NA, NA, NA, NA, NA, "소계", "청운효자동제1투", "청운효자동제...
$ polls        <dbl> 40507842, 8393847, 141447, 2138, 2689, 136620, 11...
$ votes        <dbl> 30721459, 6307869, 103189, 1626, 2507, 99052, 890...
$ pgh          <dbl> 15773128, 3024572, 49422, 798, 1167, 47457, 4233,...
$ mji          <dbl> 14692632, 3227639, 52747, 807, 1274, 50662, 4598,...
$ etc_01       <dbl> 12854, 3559, 73, 1, 2, 70, 4, 1, 3, 0, 4, 2, 2, 0...
$ etc_02       <dbl> 16687, 3793, 86, 0, 3, 83, 10, 4, 3, 3, 5, 2, 3, ...
$ etc_03       <dbl> 53303, 11829, 211, 5, 6, 200, 18, 8, 4, 6, 10, 4,...
$ etc_04       <dbl> 46017, 5307, 97, 6, 7, 84, 4, 1, 2, 1, 2, 1, 1, 2...
$ subtlt       <dbl> 30594621, 6276699, 102636, 1617, 2459, 98556, 886...
$ invalid      <dbl> 126838, 31170, 553, 9, 48, 496, 40, 8, 15, 17, 20...
$ abstain      <dbl> 9786383, 2085978, 38258, 512, 182, 37568, 2698, 9...
dat <- dat %>% dplyr::filter(sigun !="합계") %>% 
  mutate(emd = na.locf(emd)) %>% 
  dplyr::filter(emd != "소계") %>% 
  mutate(vote_station = ifelse(is.na(vote_station), paste0(emd, "_", sigun), vote_station)) %>% 
  dplyr::filter(vote_station != "소계") %>% ungroup


by_sido <- dat %>% dplyr::group_by(sido) %>% 
  dplyr::summarise(polls_tlt = sum(polls),
                   votes_tlt = sum(votes),
                   pgh_tlt = sum(pgh),
                   mji_tlt = sum(mji),
                   invalid_tlt = sum(invalid),
                   abstain_tlt = sum(abstain)) %>% 
  mutate(vote_diff = pgh_tlt - mji_tlt) %>% ungroup

names(by_sido) <- c("CTP_KOR_NM", "votes_tlt", "ballot_tlt", "pgh", 
                    "mji", "invalid_tlt", "abstain_tlt", "vote_diff")

지도데이터와 투표데이터 병합

# 3. 지도 데이터 병합(@data 방식)-------------------------------------------
sido_vote_shp <- merge(korea_sido_shp,  by_sido, by='CTP_KOR_NM')

대선 투표결과 시각화

시도별 총투표수

투표 결과를 각 시도별로 viridis 색상을 활용하여 총투표수를 시각화한다.

# 4. 주제도 시각화(tmap)-------------------------------------------
## 4.1. 전체 -------------------------------
pal10 <- viridis(10, option="D")

tm_shape(sido_vote_shp) + 
  tm_fill("ballot_tlt",
    style = "kmeans",
    title = "총투표",
    palette=pal10,
    n=10) +
  tm_borders(alpha=.7, lwd=2) +
  tm_layout(outer.margins=0, asp=0, scale=.8) 

시도별 총투표수

투표결과를 facet 기능을 활용하여 각 시도별로 나눠 살펴볼 수도 있다. 각 시도 수준에서는 큰 의미는 없지만, 이런 기능도 가능하다는 정도로 살펴본다.

## 4.2. Facet -------------------------------
pal10 <- viridis(10, option="D")
# tmap_mode("plot")

tm_shape(sido_vote_shp) + 
  tm_fill("ballot_tlt",
          style = "kmeans",
          title = "총투표",
          palette=pal10,
          n=10) +
  tm_borders(alpha=.7, lwd=2) +
  tm_facets(by="CTP_KOR_NM", free.coords=TRUE) +
  tm_layout(legend.show = FALSE, outer.margins=0)

박근혜, 문재인 두 후보 비교 1

박근혜, 문재인 두 후보 투표수를 나란히 지리정보를 활용하여 비교할 경우 grid 팩키지의 도움을 받아 구현한다. 박근혜 후보 투표수 주제도, 문재인 후보 투표수 주제도를 객체로 저장해 놓고서 grid 팩키지를 활용하여 한장의 그림을 완성한다.

## 4.3. 박근혜 vs 문재인 -------------------------------
## 박근혜 문재인 투표 나란히 비교
# tmap_mode("plot")
pal10 <- viridis(6, option="D")

pgh_tmap <- tm_shape(sido_vote_shp) + 
  tm_fill("pgh",
          style = "fixed",
          title = "박근혜",
          palette=pal10,
          breaks=c(seq(0,3000000, by=500000))) +
  tm_borders(alpha=.7, lwd=2) +
  tm_layout(outer.margins=0, asp=0, scale=.8) 

mji_tmap <- tm_shape(sido_vote_shp) + 
  tm_fill("mji",
          style = "fixed",
          title = "문재인",
          palette=pal10,
          breaks=c(seq(0,3000000, by=500000))) +
  tm_borders(alpha=.7, lwd=2) +
  tm_layout(outer.margins=0, asp=0, scale=.8) 

## 나란히 한장에 찍기
library(grid)
grid.newpage()
pushViewport(viewport(layout=grid.layout(1,2)))
print(pgh_tmap, vp=viewport(layout.pos.col = 1))
print(mji_tmap, vp=viewport(layout.pos.col = 2))

박근혜, 문재인 표차이 인터랙티브 분석

박근혜, 문재인 두 후보간 표차이를 leaflet 기능을 활용하여 인터랙티브하게 작성한다. tmap에는 tmap_mode(“plot”) 모드로 정적 공간정보 시각화 방식과 tmap_mode(“view”) 모드를 활용하여 인터랙티브 공간정보 분석이 가능하다.

## 4.3. 표차이 분석 : 박근혜 - 문재인 -------------------------------
pal10 <- brewer.pal(10, "RdYlBu")

# 박근혜 vs. 문재인 인터랙티브 팝업
vote_diff_tmap <- tm_shape(sido_vote_shp) + 
  tm_fill("vote_diff",
          style = "kmeans",
          palette=pal10,
          n=10,
          title=c("표차이", "표차이", "박근혜", "문재인"),
          popup.vars=c("CTP_KOR_NM", "vote_diff", "pgh", "mji")) + 
  tm_borders(alpha=.7, lwd=2) +
  tm_layout(outer.margins=0, asp=0, scale=.8)

tmap_mode("view")
vote_diff_tmap
# save_tmap(vote_diff_tmap, "sido_vote_diff.html")

  1. Plot 2 tmap objects side-by-side