R 지도 시각화 1
선거 결과 데이터 전처리하기
Dr.Kevin 8/1/2018
지난해 19대 대통령 선거가 있었습니다. 선거 결과를 지도로 시각화하는 포스팅을 공유하고자 합니다. 먼저 선거 결과 데이터는 중앙선거관리위원회 홈페이지에서 내려받았습니다.[1]
지도 위에 시각화 하려면 선거 결과 데이터를 그에 맞게 정리해야 합니다. 각 코드에 주석으로 간단한 설명을 달았습니다. 내용을 보시고 잘 따라오시기 바랍니다.
# 필요 패키지를 불러옵니다.
library(dplyr)
library(stringr)
library(readxl)
library(xlsx)
# 데이터가 저장된 폴더로 작업경로를 변경합니다.
setwd(dir = '데이터가 저장된 폴더를 지정하세요')
# 선거 결과 데이터를 불러옵니다.
result <- read_xlsx(path = '제19대 대통령선거 개표자료.xlsx')
# 컬럼명을 확인합니다.
colnames(x = result)
## [1] "시도명" "구시군명" "읍면동명"
## [4] "투표구명" "선거인수" "투표수"
## [7] "후보자별 득표수" "X__1" "X__2"
## [10] "X__3" "X__4" "X__5"
## [13] "X__6" "X__7" "X__8"
## [16] "X__9" "X__10" "X__11"
## [19] "X__12" "X__13" "무효투표수"
## [22] "기권수"
컬럼명 부분이 이상하게 되어 있습니다. 그 이유는 엑셀 파일에서 컬럼명이 두 줄로 되어 있기 때문입니다. 따라서 첫 행에서 후보자 이름을 추출하여 컬럼명을 바꿔준 다음 첫 행을 삭제해야 할 것입니다.
# 첫 행의 후보자 이름만 추출합니다.
candidates <- result[1, 7:19] %>% str_split(pattern = '\r\n') %>% sapply(FUN = `[`, 2)
# 후보자 이름을 컬럼명으로 변경합니다.
colnames(x = result)[7:19] <- candidates
colnames(x = result)[20] <- '계'
# 첫 행을 삭제합니다.
result <- result[-1, ]
처음 데이터를 불러올 때 첫 행에 후보자 이름이 있었기 때문에 숫자형 벡터여야 할 컬럼들이 모두 문자형 벡터로 강제치환(coerced)되어 있을 것입니다. 숫자형으로 바꿔주어야 연산을 할 수 있으므로 모두 바꿔줍니다.
# 문자 벡터를 숫자 벡터로 변환합니다.
result[, 7:20] <- data.matrix(frame = result[, 7:20])
이번 시각화에 사용할 자료는 시/군/구 단위로 합계 데이터를 사용할 예정이므로 아래와 같이 적절하게 조치를 취합니다.
# '읍면동명' 컬럼의 값이 '합계'인 것만 남깁니다.
result <- result[result$읍면동명 == '합계', ]
# '읍면동명' 및 '투표구명' 컬럼을 삭제합니다.
result <- result[, -c(3:4)]
# NA인 행을 삭제합니다.
result <- result[complete.cases(result), ]
# 세종특별자치시의 '구시군명'을 '세종시'로 변경합니다.
result$구시군명[result$구시군명 == '세종특별자치시'] <- '세종시'
# '시도명'과 '구시군명'을 합친 '지역명' 컬럼을 생성합니다.
result$지역명 <- str_c(result$시도명, result$구시군명, sep = ' ')
# 컬럼의 순서를 변경합니다.
result <- result[, c(21, 1:20)]
# 시와 구에 공백을 추가합니다.
result$지역명 <- result$지역명 %>% str_replace_all(pattern = '시(?=\\w+구)', replacement = '시 ')
위에서 세종특별자치시를 세종시로 변경하고, 시와 구 사이에 공백을 추가하는 이유는 나중에 사용할 행정경계구역 데이터와 병합할 때 기준 컬럼으로 사용하기 위함입니다. str_replace_all()
함수의 pattern
인자에 사용된 정규표현식은 시로 끝나는 부분을 찾으라는 전방탐색입니다. 궁금하신 분은 정규표현식을 찾아보시기 바랍니다.
이제 후보자별 득표율 컬럼을 생성합니다. 상위 5명의 후보자에 한하여 유효득표수를 분모로 한 득표율을 아래와 같이 계산합니다. 그리고 각 지역별로 득표율이 가장 높은 후보의 위치를 찾습니다. 이렇게 함으로써 최고 득표율 후보의 정당 색상을 지정해줄 수 있습니다.
# 후보별 득표율 컬럼을 생성합니다.
result[, 22:26] <- result[, 6:10] %>% sapply(FUN = function(x) (x / result$계 * 100) %>% round(digits = 1L))
colnames(x = result)[22:26] <- colnames(x = result)[6:10] %>% str_c('R')
# 지역별로 득표율이 가장 높은 후보를 확인합니다.
result$최대R <- apply(X = result[, 22:26], MARGIN = 1, FUN = function(x) which(x == max(x)))
# 최대 득표정당색을 지정합니다.
result$색상 <- ifelse(test = result$최대R == 1, yes = 'blue', no = 'red')
선거 결과 데이터를 전처리하는 과정에서 마지막으로 해야 할 일은, 전국 250개 지방자치단체 시/군/구청 이름으로 위경도 좌표를 얻는 것입니다. 이를 위해 구글 지도 API를 활용해야 합니다. 그리고 구글 지도 API 인증키도 미리 발급받아야 하구요. 이 방법에 대해서는 저의 블로그에 자세한 설명을 남겨놨으니 한 번 보시기 바랍니다.
사실 구글 지도 API 인증키가 없어도 개별 건에 대해서 위경도 좌표를 받는 것은 가능합니다. 다만 여러 건을 한꺼번에 받으려고 할 때 중간 중간에 구멍난 것처럼 NA
값이 반환됩니다. 이 경우를 회피하려면 API 인증키가 필요합니다. 일단 구글 지도 API 인증키를 받았다는 가정 하에 다음을 진행하도록 하겠습니다.
참고로 현재 CRAN에는 ggmap 패키지가 2.6
버전이 등록되어 있을 것입니다. API 인증키가 없으면 이 버전으로도 충분히 가능합니다. 하지만 API 인증키를 등록하려면 2.7
버전을 사용해야 하므로 devtools::install_github()
함수를 이용하여 최신 패키지를 설치하시기 바랍니다.
# ggmap 2.7을 설치합니다. (아직 CRAN에 등록되어 있지 않습니다.)
devtools::install_github('dkahle/ggmap')
# 필요 패키지를 불러옵니다.
library(ggmap)
# 구글 지도 API 인증키를 등록합니다.
# 만약 없다면 건너 뛰어도 무방합니다.
register_google(key = '자신의 구글 지도 API 인증키를 입력하세요')
이제 앞에서 새로 만든 지역명 컬럼에 청을 추가한 시청/구청/군청 이름으로 위경도 좌표를 받도록 하겠습니다.
# 지역명으로 위경도 좌표를 얻습니다.
areaCoords <- geocode(location = enc2utf8(x = str_c(result$지역명, '청')))
# 위경도 좌표 중 NA인 건수를 확인합니다.
(is.na(x = areaCoords) == TRUE) %>% sum()
## [1] 0
만약 API 인증키를 등록하지 않았다면 상당량(10 ~ 20% 정도)이 NA로 반환되었을 것입니다. 그럴 경우 NA인 건만 따로 추출해서 geocode()
함수를 반복적으로 실행하시면 됩니다. 모든 건에 대해서 위경도 좌표를 다 받았다면 다음을 실행합니다.
# result에 위경도 좌표를 붙입니다.
result <- cbind(result, areaCoords)
# RDS로 저장합니다.
saveRDS(object = result, file = '2017_Presidential_Election_Result.RDS')
이상으로 선거 결과 데이터를 전처리하는 방법에 대해 소개해드렸습니다.
[1] 2018년 이후 선거부터는 엑셀 파일 형태로 선거 결과 데이터를 공유하지 않고 있습니다. 추후 크롤링하는 방법을 정리해서 공유하도록 하겠습니다.