다양한 곳에서 진행하는 빅데이터 공모전이 있다. 필자같은 대학생이라면 학교수업이나 교내대회도 있을 것이다. 참여하기로 마음먹으면 주제에 맞는 공공데이터 포털을 뒤지면서 열심히 삽질을 반복한다. 그렇게 분석을 끝내고 나면 심사위원분들의 마음을 사로잡기 위해 ppt를 꾸며야 하는데, 단순한 막대그래프로는 모양새가 안난다. 대부분의 공공데이터는 지리정보와 관련된 내용이 많기에 이와 연관지어 분석을 진행하는 경우가 많은데, (전통시장, 교통사고, 젠트리피케이션 등의 주제) 지리적 정보와 분석을 함께 시각화하려면 지도위에 색칠하여 표시하면 직관적이고 반응도 좋은 것 같다. 따라서 이 포스팅은 빅데이터 시각화에서 자주 쓰일 지도에 색칠하기를 다루려고 한다.


시작하기 전!

서울시 빅데이터 캠퍼스에 들어가서 공모전 작품들을 보면 알겠지만 대부분 지도 시각화에는 QGIS나 arc gis가 많이 쓰인 것 같은데, 필자는 gis툴을 배우지않아서 R로 진행하려고 한다. R의 ggmap패키지를 이용하면 gis툴이 없어도 훌륭하게 시각화를 해낼 수 있다. 또 데이터 가공에는 SQL문이 약간 쓰였기 때문에 포스팅들을 읽고 활용하려면 R과 SQL을 동시에 알아야 한다. 물론 SQL없이 R의 함수만으로 따라할 수 있다면 상관없다. 

하지만 좌절할 필요는 없다. 이 편에서는 SQL문을 사용하지 않을 것이다. 또 필요하다면 해당 csv파일을 엑셀로 직접 수정하면서 진행해도 된다.(초보자라면 엑셀로 수정하는 것이 속편할 수도 있다.)


1. 데이터를 선택하자.

시, 도를 시각화하는 작업은 시, 군, 구보다 쉽다. 왜냐하면 시, 도의 경우 누락된 시, 도가 거의 없기 때문이다. 시, 군, 구의 경우 데이터에 나와있는 내용이 법정동인지 행정동인지도 다르고 명칭이 살짝 다르거나 오타가 있는 경우도 있다. 이러한 삽질을 경험하기 전에 시, 도를 먼저 시각화해봄으로서 어떤 느낌인지 알아보려고 한다. 사실 시, 도만 색칠할 수 있어도 ppt가 멋있어진다.

따라서 현재의 행정구역상 시, 도를 모두 가진 데이터만 선택하도록 하자. 또 대부분의 공공데이터가 법정동코드 순대로 정렬되어 있기 때문에 큰 문제가 될 것 같지는 않지만, 혹시나 그렇지 않은 경우도 있을 수 있으니 아래와 같은 순서로 데이터가 배치되어 있는지 확인하자. (주의할 점은 행정구역이 개편된다거나 밑 법정동코드에 변동이 생기면 밑의 순서를 따르더라도 잘못된 시각화 결과가 나올 수 있다. 다음편 시,군,구 에서는 SQL조인을 이용하기에 이런 문제가 없다. 일단은 아래의 내용을 찬찬히 따라해보자.)

서울특별시
부산광역시
대구광역시
인천광역시
광주광역시
대전광역시
울산광역시
세종특별자치시
경기도
강원도
충청북도
충청남도
전라북도
전라남도
경상북도
경상남도
제주특별자치도

데이터의 내용이 위와 같이 정렬되어있다면 바로 진행하면 되고, 아니라면 위와같이 행을 바꿔주자.

참고로 필자가 사용한 데이터는 폐기물 발생량 데이터이다. 보면서 따라하고 싶다면 다운받자.

https://www.data.go.kr/dataset/3070174/fileData.do 에서 2015년 기준 전국폐기물 배출 및 처리현황.zip2015년전국폐기물발생및처리현황 - 2015년전국폐기물발생및처리현황 - 03_02_2015_전국_시도현황_3. 폐기물 처리주체별 처리현황_3다.사업장배출시설폐기물.csv

이름이 너무 길고 이상하니 다음과 같이 바꾸어주자. 2015년_사업장배출시설폐기물_처리현황.csv

다 귀찮다면 첨부파일을 다운받자.

2015년_사업장배출시설폐기물_처리현황.csv

원데이터

데이터를 훑어보니 지자체마다 폐기물을 재활용하는 비율이 다를 것 같다.

작업디렉토리를 지정하고 csv파일을 R로 불러와보자.(작업디렉토리는 우리가 사용하려는 파일들이 있는 폴더이다. 포스팅에 사용된 파일들은 모두 이 폴더에 모아두면 된다.)

setwd("E:/study")  ##일반적인 파일 경로에 사용되는 역슬래쉬가(\) 아니라 슬래쉬(/)를 이용해야 한다!

factory_trash<-read.csv("2015년_사업장배출시설폐기물_처리현황.csv")

이제 지도 데이터에 매핑해주기 위한 작업을 하겠다. 현재 시, 도를 구분하는 값은 ~~시, ~~도이다. 이를 명목형 자료라고 한다. 이러한 명목형 자료는 사람이 보기에는 편하지만 컴퓨터가 처리하기에는 불편하고, 중복되는 이름이 있는 경우에는 어떻게 처리해야 할 지 복잡해진다. 그래서 이를 대체하기 위하여 고유한 숫자를 부여한다. 마치 대학교에서 사용하는 학생들의 학번과 비슷한 역할이다. 위 시,도 데이터에도 학번과 같이 id를 부여해주자.

factory_trash$id<-0:16

또 폐기물의 총합과 그에 따른 폐기물 재활용 비율도 계산해보자. (이 부분은 복사하기를 권장한다.)

factory_trash$total_trash<-factory_trash$자치단체_매립.톤.일.+factory_trash$자치단체_소각.톤.일.+factory_trash$자치단체_재활용.톤.일.+factory_trash$자치단체_해역배출.톤.일.+factory_trash$처리업체_매립.톤.일.+factory_trash$처리업체_소각.톤.일.+factory_trash$처리업체_재활용.톤.일.+factory_trash$처리업체_해역배출.톤.일.+factory_trash$자가처리_매립.톤.일.+factory_trash$자가처리_소각.톤.일.+factory_trash$자가처리_재활용.톤.일.+factory_trash$자가처리_해역배출.톤.일.

factory_trash$recycle_rate<-(factory_trash$자치단체_재활용.톤.일.+factory_trash$처리업체_재활용.톤.일.+factory_trash$자가처리_재활용.톤.일.)/factory_trash$total_trash*100


참고로 윗 부분은 엑셀을 이용하면 훨씬 편하다. 위 csv파일에서 id, total_trash, recycle_rate칼럼을 만들고 sum함수를 활용하면 타이핑안해도 되고 편하다.

R함수로 가공을 하던 csv를 직접 편집을 하던 아래와 같은 결과가 되었는지 확인해보자.

View(factory_trash)

가공 데이터



이제 지도 데이터에 매핑해줄 차례이다.

http://www.gisdeveloper.co.kr/?p=2332 에 들어가 지도 데이터를 다운받자.(대단히 감사한 분이다!) 우리는 2015년 데이터를 시각화하는 중이니 2015년 이후 파일을 다운로드받으면 되는데, 실습에서는 2017년 3월에 업데이트된 파일을 사용했다. (2015년과 2016년 파일은 실습을 진행하는데 다소 문제가 있기도 했다. 2017년 파일이 법정동코드대로 정렬되어있어 편했다. shp파일 자체를 정렬하면 될 것 같았지만 다음단계를 진행하면 정렬이 풀려 2017년 데이터로 진행한다.)

아까 csv파일이 있는 폴더에 CTPRVN_201506.zip파일의 압축을 푼다. 그리고 R에서 파일을 부른다. 이 지도데이터를 읽어들이기 위해서 R에 추가적인 패키지를 설치해주어야 한다.

install.packages("ggmap") install.packages("ggplot2") install.packages("raster") install.packages("rgeos") install.packages("maptools") install.packages("rgdal")

여기서 설치 순서가 중요하다! 지도 색칠 실습을 하다보면 istrue(gpclibpermitstatus()) is not true 혹은 Error: TopologyException: Input geom 1 is invalid 따위의 오류가 발생할 수 있다. .libPaths() 를 실행하여 R패키지가 설치된 경로를 확인하고 해당 위치로 이동한다, 이미 rgdal, rgeos, maptools이 깔려있다면 모두 삭제해준다. 삭제했다면(혹은 해당 패키지들이 없었다면) rgeos, maptools를 설치한 후에 rgdal를 설치해준다.(순서 중요!!) 이러면 위의 이상한 오류들이 발생하지 않는다.(이 오류를 해결하느라 얼마나 고생했는지 모른다....ㅠㅠ) 혹시 위의 3가지 패키지를 삭제하고 재설치하는데 Error in if (file.exists(dest) && file.mtime(dest) > file.mtime(lib) &&  :    missing value where TRUE/FALSE needed 같은 오류가 발생한다면 다른 버전의 R로 시도해보자. 필자는 3.4.0버전을 사용하다가 이러한 문제를 해결한 3.4.1 버전으로 진행하니 위의 오류가 발생하지 않았다.

library(ggmap) library(ggplot2) library(raster) library(rgeos) library(maptools) 를 차례로 실행하여 패키지들을 로딩해준다.

korea<- shapefile("TL_SCCO_CTPRVN.shp")  ##실행하여 shp파일을 불러와준다.

여기서 중요한 점! 이 shp파일에는 우리가 아는 위도, 경도의 좌표계가 설정되어 있지 않다. 이를 해결하기 위하여 좌표계를 설정해준다.

korea<- spTransform(korea, CRS("+proj=longlat"))

fortify함수는 shp파일을 R의 데이터프레임으로 바꿔주는 함수이다. merge함수로 위에서 가공한 factory_trash를 합치기 위해서 실행한다.

korea_map<-fortify(korea)

merge_result<-merge(korea_map, factory_trash, by="id")

이제 드디어 지도데이터와 가공데이터를 표시해줄 차례이다.

ggplot() + geom_polygon(data=merge_result, aes(x=long, y=lat, group=group, fill=recycle_rate))+labs(fill="발생량 대비 재활용 비율(%)")

시각화

드디어 완성!! 그런데 하고보니 색도 우중충하고 색깔에도 나름 의미부여를 해보고 싶다. 그렇다면 이 지도 자체를 객체에 저장하여 색을 지정할 수 있다. 재활용을 많이 할 수록 청정하다는 뜻으로 연두색을 부여했고 재활용을 덜 할수록 경고한다는 뜻으로 빨간색을 부여했다.

p<-ggplot() + geom_polygon(data=merge_result, aes(x=long, y=lat, group=group, fill=recycle_rate))+ labs(fill="발생량 대비 재활용 비율(%)")

p+scale_fill_gradient(low='red', high='green')

다양한 색넣은 지도

low='red', high='green' 부분에서는 red나 green대신 다른 색도 넣을 수 있고, #00ff2c 같이 RGB값을 직접 넣어줄 수도 있다.

만약 실제 지도를 함께 표시하고 싶다면 아래와 같은 코드를 추가하자.

map <- get_map(location='south korea', zoom=7, maptype='roadmap', color='bw')

q<-ggmap(map)+geom_polygon(data=merge_result, aes(x=long, y=lat, group=group, fill=recycle_rate),alpha=0.7)+labs(fill="발생량 대비 재활용 비율(%)")

q+scale_fill_gradient(low='red', high='green')

실제 지도 위에 표시

복잡한 설명은 최대한 생략하고 법정동코드도 이용하지 않았다. 필자는 작년에 갑작스럽게 공모전에 나가게 되어 시각화를 할 때 매우 애를 먹었다. 빅데이터에 대한 관심이 많이지고 빅데이터 공모전이 더 많아질 것으로 예상되는데, 위의 방법들을 알아두면 삽질하지 않고 쉽게 접근할 수 있을 것이다. 다음 포스팅에서는 시, 군, 구를 시각화하는 방법을 다룰 것이다. 시, 군, 구를 시각화할 수 있게되면 위와같이 전체 우리나라가 아닌 부분 지역의 시각화를 할 수 있게 된다.

  1. 지도그리기 2018.11.10 08:12

    안녕하세요
    좋은 자료 감사드립니다
    이거 보면서 지도 그리고 있는데요 spTransform해서 좌표계 넣는데서부터 에러가 나요
    korea=spTransform(korea,CRS("+proj=longlat"))
    Error in spTransform(xSP, CRSobj, ...) :
    No transformation possible from NA reference system
    뭐가 문제일까요?

    • 얼음케잌 2018.11.11 00:12 신고

      블로그 글쓰기와 R언어 사용을 안한지 오래 되었지만 기억을 되살려서 한 번 써보겠습니다. 일단 블로그에 나와있는 코드와 데이터를 가지고 테스트해주세요. 제가 다시 코드를 실행해본 결과, 잘 됩니다. 다만 현재는 구글 map API 정책이 바뀌어서 지도 자체를 가져오는 건 안되더라구요.
      좌표계 부분이 어려운 부분이라 저도 잘은 모르겠지만, 아마 shp파일을 뜯어보시면 뭔가 NA값이 있어서 나오는 오류가 아닐까 싶습니다.

  2. 2018.11.22 15:55

    비밀댓글입니다

+ Recent posts