본문 바로가기

Function

서울 생활인구 데이터를 격자 단위로 재할당하기


 이 글은 2018년에 작성된 것이며, 최근(2020년 12월)에 연면적 가중치 없이 R을 이용해서 재분해 하는 내용을 아래 링크에 다시 올렸다.


https://www.vw-lab.com/87



이하 원 글.

----------------------------------------------------------------------------------------------


이 글은 불규칙한 형상의 집계구 단위로 배포된 서울 생활인구 데이터를 정사각형 격자 단위로 재할당하는 방법에 대해 다룬다. 여러가지 방법이 있겠지만, 건물 연면적 데이터를 이용하여 가중치를 두어 재할당하는 기초적인 방식을 사용하였다. 일정한 크기의 공간 단위로 인구를 재할당하면 인구의 분포와 인구의 밀도를 동시에 설명할 수 있게 된다.





서울시는 생활인구 데이터를 배포하고 있다


서울시에서 제공하는 공공데이터 중 '생활인구'라는 것이 있다. 서울 전역 6000여개의 기지국에서 잡힌 KT 휴대폰 신호를 바탕으로 특정한 날 특정한 시각에 특정 공간 단위에 존재하는 모든 인구를 추정한 데이터다. 주민등록인구나 인구 총조사가 밤에 잠을 자는 장소를 중심으로 집계한 거주 인구라면, 이 생활인구는 낮 시간에 근무지에서 근무하는 인구나 보행 인구도 포함하여 추정한 수치다. 현대 도시인은 끊임없이 이동하기 때문에 낮 시간때에 거주지를 떠나 어디에 얼마만큼 몰리는지 파악할 수 있다는데 의미가 있다. 데이터에 대한 자세한 내용은 다음을 참고하면 된다.

http://data.seoul.go.kr/dataVisual/seoul/seoulLivingPopulation.do






집계구의 크기는 천차만별이고 형상은 불규칙하다


이 데이터 중 내국인 생활인구는 집계구 단위로 배포된다. 그런데 집계구는 말 그대로 인구를 조사하여 집계할 목적으로 통계청에서 편의상 분할한 단위이기 때문에 형상이 매우 불규칙하고 크기도 일정하지 않다. 사람들이 많이 사는 아파트 단지는 조밀하게 분할되어 있고, 서울 외곽이나 상업지역 처럼 사람이 별로 거주하지 않는 곳은 매우 크게 잡혀 있다.



집계구 크기와 형상은 아래와 같다. 



그림에서 서울역과 광화문 등이 보인다. 거주인구가 적은 지역은 넓게 잡혀 있고 주거지역은 작게 잡혀있다. 불규칙한 형상도 확인할 수 있다.






집계구 단위 인구를 곧바로 시각화하면.


집계구에 할당된 인구 수를 곧바로 시각화 하면 다음과 같다. 인구를 높이값으로 주고 z축으로 돌출시켰다.

이 그림은 2017년 10월 11일 수요일, 즉 평일 14시의 상황이다. 직장이나 학교 등에서 머무르는 시간대다.



그런데, 이상해보이는 부분들이 눈에 들어온다. 아래쪽의 진한 노란색이 돌출된 곳에는 서울대학교가 포함되어 있다. 주거시설은 별로 없기 때문에 집계구도 넓게 잡혔다. 그런데 낮 시간대에 학교에 와 있는 대학생들로 인해 인구가 많이 잡혔고, 집계구 면적이 넓기 때문에 이러한 시각화 방식에서는 굉장히 두드러지게 보인다. 이 시간대 집계구의 전체 인구는 종로 부근의 상업지역보다 많이 낮겠지만, 이 시각화를 보고 있자면 종로 부근의 도심 전체 인구보다 서울대학교 지역이 더 많아보인다.


일단 가장 간단하게 해볼 수 있는 대안은 집계구 인구를 곧바로 z값으로 사용하는 것이 아니라 인구를 집계구면적으로 나눈 후 z값으로 사용하는 방법이다. 그렇게 하면 높이가 곧 인구밀도가 되므로 돌출된 입체의 부피가 곧 생활인구의 양과 같아진다.


그럼에도 불구하고 또 다른 문제들이 남는다. 집계구 형상은 통계조사 작업 편의를 위해 나누어 놓은 단위이기 때문에, 인구 분포를 보는 입장에서는 집계구의 경계와 형상은 큰 의미가 없다. 게다가 산이나 강이 포함된 집계구들의 해당 지역들은 실제로 인구가 거의 없음에도 불구하고 집계구 경계로 인구를 맵핑하여 시각화할 경우, 인구가 산이나 강에도고르게 분포하는 것처럼 보이게 된다.


물론, 사람마다 목적이 다르므로 집계구라는 것이 누군가에게는 편리한 분할단위일 수 있다. 집계구 코드에서 앞 부분은 행정동 코드이기 때문에, 실제 행정이 이루어지는 단위에서 인구를 파악하고자 할 때 집계구는 편리한 단위가 될 수도 있다. 그렇지만 바로 앞에서 언급한 불편함도 있기 때문에 동일한 크기의 격자로 재할당하여 다시 그림을 그려보기로 하겠다.





인구를 재할당해보자


그렇다면 어떻게 격자로 재할당해야할까?

여기서는 건물 연면적에 비례한다고 가정하는 '속 편한' 방식을 써보기로 한다. 실제로 많은 사람들이 건물과 그 주변에서 활동하고 있기 때문에 건물 연면적을 가중치로 두어 재할당하면 어느 정도는 그럴듯하게 분할된다. 그렇지만 한강 고수부지나 공원처럼 건물이 없는 곳에 있는 사람들은 추정되지 않는다는 단점이 있다.


어쨌든, 건물 연면적 지도를 '가중치 참조값'으로 부른다면, 가중치 참조값은 또 다른 정밀한 방식으로 업그레이드 할 수 있기 때문에 아래 설명하는 과정에서 독립적으로 취급할 수 있다. 여기서는 가중치 참조값을 만드는 방법론보다는, 하나의 가중치 참조값에 근거해서 불규칙한 형상을 규칙적인 형상으로 재할당하는 방법에 무게를 두어 설명하겠다.


한 가지 짚고 넘어갈 부분은, 이러한 접근은 어쩔 수 없는 오류를 내포한다는 점이다. 집계구에 할당된 생활인구수도 본래 기지국 단위의 인구를 주민등록인구,건물연면적 등 여러가지 도시데이터에 근거하여 추정해낸 것이다. 그런데 여기서서는 그 추정된 데이터를 연면적을 이용하여 다시 다른 단위로 추정하려고 한다. 비유하자면, 한국어 문장을 구글 번역기에서 영어로 바꾸고, 다시 그 영어를 번역기에 넣어 한국어로 바꾸는 작업과도 비슷하다. 


그렇기 때문에 좁은 지역의 세밀한 추정이 필요한 사람들은 가장 원시(raw) 상태의 데이터인 기지국 데이터를 어떻게든 구입해서 작업해야 한다. 이 작업의 목적은 단지, 인구의 대략적인 분포를 위 그림보다는 좀 더 직관적이고 편한 그림으로 바꾸기 위한 과정이다.



전체적인 과정을 요약하면 이렇다.

1. 건물 연면적을 건물 polygon 내부의 점들에 고르게 배분한다.

2. 해당 점들이 어떤 격자에 들어오는지 파악하여 표로 정리한다.

3. 이번에는 위의 점들이 어떤 집계구에 속하는지 파악한다.

4. 위의 두 내용을 바탕으로 [격자번호-집계구-가중치]로 정리된 표를 만든다.

5. 빈 격자들 하나씩 돌아가면서 4번의 표를 근거로 인구를 계산한다.





연면적을 기준으로 재할당 하는 방식과 그 한계점은 이러하다


이제 하나하나 다시 설명해보겠다.


일단 건물의 연면적, 즉 건물 모든 바닥면적의 크기가 클수록 사람들이 많이 몰린다고 가정한다. 이 한 가지 가정에 따라 집계구 인구를 격자로 재분배한다. 이 가정은 여러가지 오류를 수반한다는 사실을 쉽게 생각해볼 수 있다. 몇 가지를 언급해보자면 다음과 같다.


. 도로, 공원, 광장처럼 건물 아닌 곳에는 인구가 전혀 재할당되지 않는다.

. 새벽의 인구를 재할당할 경우 새벽에 문을 닫는 상점에 인구가 할당될 수 있다.

. 건물의 용도마다 사람들의 사용 밀도가 다르므로 창고처럼 사람의 이용 밀도가 적은 시설에는 과다추정될 수 있다.


따라서 집계구의 인구를 재할당하는 과정의 가장 어려운 부분은 바로 '어떤 방식으로 시간, 지역, 건물용도, 이벤트 등에 따라 달라지는 인구 가중치 참조값을 만들어낼 것인가'다. 여기서는 그 가중치 참조값을 건물 연면적에만 한정하였다. 그게 바로 위에서 '속 편한 방식'이라고 언급한 이유다.


이제 그 절차를 설명해보자.





연면적 데이터를 준비해보자



건축물 연면적 데이터는 아래 링크에서 GIS건물통합정보를 사용했다.

http://openapi.nsdi.go.kr/nsdi/index.do


수치지도에 건축물대장 정보를 join 한 데이터라고 하는데 위의 그림처럼 부족한 부분이 많다. 위의 지도는 답십리역과 신답역 부근이다. 화면 우측 상단에 공지처럼 보이는 곳은 지어진지 5년쯤 된 아파트 단지다. 아직도 비어 있다. 그리고 위의 건물들은 50%의 투명도로 그려본 것인데, 진한 부분들은 동일한 건물이 두개씩 혹은 그 이상 중복된 곳들이다. 분명히 공공에서 직접 생산하지 않고 어떤 업체에서 용역을 받아 작업을 할텐데, 그 작업 결과를 검수하는 절차가 제대로 되어 있지 않은 것 같다.


이런 데이터를 보다 정확하게 만드는 것은 안타깝게도 사용자의 몫이다. 서울 전체를 올바로 뜯어고치겠다는 호기는 부리지 말고, 부디 필요한 곳들 위주로 수정해서 사용하기 바란다. 






건물 도형과 연면적을 점들의 분포로 배분한다




데이터를 준비했으면 이제 본격적으로 시작해보자.


위의 그림은 50m 격자와 건물, 그리고 건물 폴리곤 안에 배열한 점들로 이루어져 있다.

건물을 단 하나의 점으로 치환하지 않고 일정한 간격의 점 배열로 다시 분할하는 이유는 위의 그림에서 볼 수 있듯이 하나의 건물이 여러개의 격자에 걸쳐 있는 경우가 있기 때문이다. 특히 쇼핑몰이나 종합운동장 같은 큰 건물들을 단 하나의 점으로 치환시킬 경우 열 개 이상의 격자에 분포되어야 할 인구가 단 하나의 격자로 몰리게 되는 현상이 발생하므로 주의해야 한다.


여기서는 건물 폴리곤 안에 가로세로 5m 간격의 점들을 나열한 후, 각 점에 건물 연면적을 동일하게 나누어 속성 값으로 주었다. 5m 간격의 점이 하나도 찍히지 않는 작은 건물에는 단 하나의 점을 찍었다.






위의 표가 건물 연면적을 점들의 분포로 재할당한 결과다. 가장 좌측 열부터 속성 내용은, [점이 속한 격자의 번호], [점의 x좌표], [점의 y좌표], [분할된 연면적] 이다. 예를 들어 연면적이 204.764로 보이는 다섯 줄은 건물 연면적이  1023.82 였으며, 그 안에 다섯개의 점이 찍혔기 때문에 5로 나누어 204.764제곱미터를 할당한 것이다. x와 y좌표는 UTMK(EPSG:5179) 좌표계를 사용하였다. 


여기서는 서울 전체를 포함하는 직사각형을 영역을 설정한 후 좌하단 기준점을 (x : 935300, y : 1936850)으로 두고 가로 805개, 세로 600개의 50m x 50m 격자를 그렸다. 그래서 좌하단 격자를 0번, 오른쪽으로 일련번호를 붙여 나가 우하단격자를 804번, 다시 좌하단 격자 바로 위로 돌아와서 805번.... 이렇게 행 우선 진행방식을 취하면서 일련번호를 붙였다. 일련번호만 알아도 위와 같은 규칙에 따라 해당 격자의 네 귀퉁이 좌표값을 쉽게 계산할 수 있다.

위의 기준으로 총 805 x 600 = 483,000개의 격자가 만들어지며, 위의 표에서 가장 좌측은 이 격자의 일련번호 중 하나가 된다.






격자별로 집계구의 가중치 표를 만든다





일단 결과부터 말해보자 .위의 표가 이번 단계에서 만들려고 하는 표다. 녹색으로 강조한 부분을 설명해보자면 다음과 같다. 


262158번 격자는 3개의 집계구에 걸쳐 있으며, 1106088020008번 집계구의 인구 중 0.0191 (1.9%)을 이 격자에 할당하면 된다. 1106088020003번 집계구의 인구 중 0.0543 만큼을 할당하면 되며, 1106088020013번 집계구의 인구 중 01098만큼을 할당하면 된다. 그것이 바로 262158번 격자에 재할당될 총 인구다.


위와 같은 표가 만들어지면 262158번 격자의 인구를 계산할 때 위에서 언급한 3개 집계구의 인구만 알면 곱셈과 덧셈으로 바로 계산할 수 있다.


이 표를 만들기 위하여 우선 집계구를 순서대로 돌아가면서 해당 집계구에 포함되는 점들을 찾아내야 한다. 앞서 1번의 결과로 총 410만개의 많은 점들이 만들어졌기 때문에 그냥 loop로 돌리지 말고 quadtree 같은 2차원 공간검색에 유용한 자료구조를 사용하여 집계구에 포함되는 점들을 찾아내면 훨씬 속도가 빨라진다.

폴리곤 안에 점이 포함되는지 판별하는 방법은 인터넷에서 여러가지 언어의 코드 형태로 쉽게 찾아볼 수 있다.


집계구에 포함된 점을 찾아내면 그 점에서 앞의 작업에서 저장해두었던 값들을 읽어올 수 있다. 그 점이 속한 격자에, 현재 계산중인 집계구 번호 밑으로 연면적 값을 등록시킨다. 예를 들어 현재 계산중인 집계구가 1106088020008번이라면, 아래의 표처럼 총 18개의 격자에 걸쳐 있다. 연면적 점들이 있는 격자들만 계산하였다. 앞의 표와 마찬가지로 좌측부터 [격자 번호], [집계구 번호], [집계구 인구 중 해당 격자에 할당할 인구의 가중치]가 속성에 해당한다.




1106088020008번에 속한 점들의 모든 연면적의 합이 100이라면, 그 중 262157번 격자에 속한 연면적의 합은 5.07이다. 262158번 격자에 속한 점들의 연면적의 합은 1.9가 된다. 이러한 방식으로 1106088020008번 집계구에 속한 인구를 관련된 격자에 모두 배분할 수 있다. 위의 표에서 계산해 낸 연면적의 비율만큼 18개의 격자에 배분하면 된다.


같은 내용을 격자 입장에서 풀어보면, 262157번 격자의 인구를 계산할 때는 1106088020008번 격자의 인구 중 0.507만큼만 가져오면 된다. 물론 262157번 격자가 두 개 혹은 그 이상의 집계구에 걸쳐 있다면 총 인구는 다른 집계구의 값에서도 배분받아야 한다.


아래 그림에서 붉은 색으로 표시된 콩나물 머리 모양의 집계구가 바로 1106088020008번 집계구다.




이런 방법으로 약 19000개의 집계구를 모두 순회하면서 계산하면 위와 같은 표 전체를 완성할 수 있다. 각 속성들은 왼쪽부터, [격자 번호], [집계구 번호], [집계구 인구 중 해당 격자에 할당할 인구의 가중치]가 된다. 




서울시 생활인구를 가중치 표에 따라 격자로 재할당한다


앞의 단계가 완성되었다면, 이 과정은 별로 어렵지 않다. 예를 들어 집계구의 총인구를 격자로 배분한다고 해보자. 서울시에서 배포하는 데이터는 총 인구 이외에도 나이와 연령에 따른 세부적인 인구수도 포함하고 있다.


일단 집계구코드와 각 집계구의 인구를 읽어들여 <Key, Value> 의 형태로 저장한다.


그 다음에는, 앞 단계에서 완성한 표에서 격자 번호를 하나씩 순회하면서 격자의 인구를 계산한다. 각 격자마다 한 개 혹은 여러개의 집계구와 가중치가 등록되어 있을 것이고, 바로 앞단계에서 저장한 집계구 코드와 집계구 인구 데이터와 조합해가면서 격자의 인구를 계산하면 된다.






이제 다시 그려보자



대표이미지

50m x 50m 격자로 재할당한 인구를 시각화해보았다. 높이는 해당 격자의 인구다. 단위 크기가 동일하므로 그대로 인구 밀도의 분포를 비교할 수 있게 된다. 집계구에 할당된 데이터를 그대로 시각화하는 것보다 조금 더 직관적으로 이해할 수 있다.


그런데 위의 그림을 보면 여의도와 금천구 등 곳곳에 과도하게 좁은 지역에 인구가 몰리는 것처럼 보이는 부분들이 있다. 많은 경우 기본 가중치 배분(건물 연면적)이 잘못되어 있을 가능성이 크다. 계산 절차에 문제가 없다면 건물 연면적들을 다시 확인해가며 수정해야 한다.



아래는 두 가지 방식의 시각화를 간단하게 비교하였다. 전반부 30초는 집계구 그대로, 후반부 30초는 격자에 재할당 한후 작업하였다.