티스토리 뷰

visualization

서울의 도로교통 패턴 #1

glasvase 2017. 12. 2. 17:25

이 시도는 현재 서울의 도로교통 패턴을 눈으로 보고 싶다는 생각에서 시작하였다. 말은 간단하지만 보기보다 간단치 않다. 이 생각은 도시와 자율주행의 상호작용이라는 보다 커다란 (매우 커다란) 질문의 과정에서 떠오른 것인데, 그 맥락 속에서도 ‘현재’라는 시간 단위와 ‘패턴’이라는 공간 또는 시공간 단위를 어떻게 정의하는 것이 좋을지 결정하기는 쉽지 않다. 오히려 많은 경우 그렇듯 자료의 유무와 가용도에 따라 결과물의 내용이 좌우될 것이어서, 일단은 어떤 자료를 끌어올 수 있는지 살펴보았다.


사실 교통분야는 다른 도시분야에 비해 공인된 대규모 데이터가 풍부한 편이다. 2017년 현재 국토교통부 산하 국가교통정보센터와 서울시 산하 서울교통정보센터(이하 TOPIS)에서는 실시간 도로소통 현황을 포함해 몇 가지 데이터를 지도화해 띄워놓고 있다. 각종 통계자료도 open API 또는 구식이지만 한국 공공기관이 사랑하는 xls 파일 형태로 제공하고 있다. (그래도 hwp가 아님에 감사하게 되는 이 마음의 연식은..) TOPIS에서 제공하는 정보는 사실 예상 밖으로 다양한 편이라 느꼈다. 교통예보, 예측지도와 같이 과거 데이터를 이용해 패턴을 읽으려는 노력도 보여주고 있으며, ‘가상 운영’이라는 링크를 누르면 서울시 교통상황과 도로별 이력 전반을 확인할 수 있기도 하다.


실시간 도로 소통상황 지도. 국가교통정보센터


실시간 도로 소통상황 지도. 서울교통정보센터


서울의 소통 상황 대시보드. 서울교통정보센터


TOPIS 웹사이트를 보며 든 생각은, 세부자료보다 총량지표가 중요한 공무원 조직에게는 이 화면이 매력적인 표현방식이겠다는 것이다. 그러나 이렇게 펼쳐놓은 방식으로 내가 보려는 직관적인 정보를 얻기는 어려웠다. 무엇보다 평균값을 남용한다는 생각이 들었다. 서울시 전체 평균속도가 궁금한 사람이 지구에 몇 명이나 될까? 그래서 도로교통의 변화 패턴을 보다 직관적으로 읽을 수 있는 표현방법, 다시 말해 내 취향에 맞는 그림을 모색해 보기로 했다.

기특하게도 서울시는 TOPIS 웹사이트의 소스가 되는 원시데이터 대부분을 공개하고 있다. TOPIS 자료실에는 2005년 이후 100여 개 지점별 교통량 데이터, 2014년 이후 5000개에 가까운 도로링크의 매일 매시간 평균속도 데이터를 게시해두고 있다. 한편 서울시의 데이터 허브 역할을 하는 열린데이터광장(이하 data.seoul)에는 실시간 소통상황을 포함해 수십 가지 교통 관련 데이터가 검색된다. 이 모든 데이터가 쓸모있거나 훌륭하기만 한 것은 아니지만 말이다.


처음에는 data.seoul의 실시간 도로 속도 데이터를 시각화의 주된 재료로 삼으려고 했다. TOPIS 등에서 보여주는 실시간 지도의 가독성이 낮아, 이걸 개선하면 어떤 패턴이 보이지 않을까 하는 생각을 했다. 상당한 잠재력을 가지고 있을 것 같은 이 매력적인 데이터를 만져보고 싶기도 했다. 우선 이 데이터가 어떻게 생성되는 것인지 살펴보았다.

관련 보고서(김은정 외, 2015)를 살펴보면, 서울시에서 제공하는 실시간 도로 소통 데이터란 서울 택시 7만 대 전체의 운행기록계(DTG; digital tachograph)에서 10초마다 수집되는 위치 및 속도 정보를 가공해 추정한 서울 시내 모든 도로구간(중앙선이 있는 2차로 이상의 도로로, 한국도로공사나 지자체 같은 도로관리주체의 협조를 받아 국토교통부가 표준링크로 지정하며 ID번호가 부여된다)별 속도를 말한다. 이 데이터는 기본 5분 단위로 갱신되며, 만약 5분이 지나도 도로를 지나는 프로브(probe, 여기서는 프로토스 프로브가 아니라 서울 택시)가 없어 해당 도로 속도 정보를 얻을 수 없으면 과거 자료를 활용하여 추정한다.



서울시 실시간 교통정보 가공 처리 과정 (김은정 외, 2015: 23)


개인적으로는 이 보고서를 살펴보는 것만으로도, 첫인상이 매력적인 실시간 도로 소통 데이터의 민낯을 확인하는 데는 충분했다. 이 보고서의 지적과 결론이 TOPIS 운영에 반영되었는지 인터넷으로 확인할 수는 없었으나 짐작컨대 아직 안 된 것 같다. 내 눈에 띈 문제점의 요는, GPS 오차를 보정하는 과정에서 작지 않은 왜곡이 발생한다는 점, 속도의 산술평균이라는 계산이 적절치 않다는 점, 택시라는 프로브가 교통 흐름을 대표한다고 보기 어렵다는 점 등이다. 가령 한국에서 택시가 소통 정체구간이든 원활구간이든 여느 자동차보다 빠르게 주행한다는 것은 경험적으로 주지된 사실이다. 즉 대부분의 경우 이 속도 데이터는 실제보다 약간씩 과대추정되어 있는 셈이다. 만약 택시 주행이 전체 교통 흐름에 비해 어떤 차이를 보이는지 속도 구간별로 분석한 결과가 있다면 이를 보정계수로 활용할 여지도 있을 테지만, 아직 그런 연구는 없는 것 같다. 사실 GPS 오차에 비하면 택시의 특성에 따른 오차는 크지 않은 것도 같지만.

어쨌든 이런 문제들은 지금 내 선에서 해결할 수 없는 것들이므로, 해석의 한계에 유의하면서 작업을 진행하기로 했다.


실시간 도로 소통 정보는 data.seoul에서 open API 형태로 제공된다. 각 도로구간에 부여된 링크ID를 입력하면 xml로 요청 시간 기준 산출된 속도값을 소수점 첫째자리까지 반환해주는 식이다.


<TrafficInfo>
  <list_total_count>1</list_total_count>
  <RESULT>
    <CODE>INFO-000</CODE>
    <MESSAGE>정상 처리되었습니다</MESSAGE>
  </RESULT>
  <row>
    <link_id>1220003800</link_id>
    <prcs_spd>16</prcs_spd>
    <prcs_trv_time>675</prcs_trv_time>
  </row>
</TrafficInfo>

data.seoul을 비롯한 많은 공공 데이터 서비스가 공통적으로 보여주는 문제지만 이런 서비스 설계는 나처럼 데이터 전체를 얻고자 하는 초보자의 불편을 야기한다. 링크ID가 부여된 서울시의 도로구간은 2017년 현재 내가 뽑아낸 바 4797개다. 초보 코더인 나에게 이는 request를 4797번 연속으로 던져야 한다는 뜻이다. 물론 던지는 일은 내 손이 아니라 내 랩탑이 하지만. 만약 4797번의 request를 통해 응답이 완료되는 데 5분 이상 걸리는 경우 확보되는 데이터는 서로 다른 시간대에 걸쳐 들어오게 되어 순수성이 더 떨어진다.

또다른 불편함은, 사용자가 서울시내 모든 링크ID를 미리 확보해두고 request url에 포함해야만 데이터를 얻을 수 있게 해놓았다는 점이다. “속도를 알고 싶어? 그럼 알고 싶은 도로 이름을 대.”라는 말이다. 어찌 보면 당연한 듯싶지만, 정작 그 링크ID 목록은 data.seoul에서는 찾을 수 없다. 나는 이 목록을 구하기 위해 다시 TOPIS를 찾아가야 했다. 교통정보 자료실 '2017 표준링크 매핑정보’라는 제목의 파일을 열여보니 1열에 ‘서비스링크아이디’가 있었다.

나는 이 파일을 열어보고 새로운 사실을 알게 되었는데, 그것은 서울시가 사용하는 링크ID와 국토교통부가 사용하는 링크ID가 일치하지 않는다는 점이다. 이런 상황은 '전국 교통망에 대해 단일화된 ID체계를 적용한 표준교통망 DB을 구축’하겠다는 국가 표준노드/링크 체계의 근본 목적에 부합하지 않는다.

무슨 사정인지 나로서는 도저히 이해할 수 없지만, 역시 조금 지나자 ‘..그래도 매핑 정보를 제공하는 게 어디야’ 하는 안도감이 밀려오기 시작했다.


2017년 서울시의 서비스링크ID와 국토교통부 표준링크ID의 매핑. 고유번호 10자리 중 마지막 2자리는 도로구간에 새로운 노드(교차로 등)가 생겨 분기하는 등 변동사항이 발생하는 경우 01,02 등으로 더해질 수 있다. 그러나 그 앞자리 번호의 수정은 재개발이나 행정구역 개편과 같이 확연한 지역 변화에 따라 이루어지는 것으로 국토교통부의 관리대장과 차이를 둘 만큼 사소하거나 순간적인 수정사항이라 보기 힘들다. 왜 이런 걸까?


이런 차이 외에도, 서울시가 정보 구축을 위해 설정한 도로구간은 아무래도 국토교통부가 표준링크로 설정한 도로구간보다는 해상도가 낮다. 결과적으로 서울시의 4797개 서비스링크에 대응하는 표준링크의 수는 10,558개로 1:n 관계다. 아무튼, 이 파일의 1열에서 중복되는 행을 털어내고 4797개의 링크ID를 추출하여 입력값으로 사용하였다. 이번 작업의 경우 웹이 아니라 QGIS를 이용하여 작업할 생각이었기에, 파이썬으로 request를 던져 결과가 csv로 출력되도록 아래와 같이 작성하였다.


def seoul_traffic_trafficinfo():
    import requests
    import xml.etree.ElementTree as etree
    import csv
    import datetime

    urlbase = "http://openAPI.seoul.go.kr:8088"
    key = "000000000000000000000000000000" #할당받은 키
    datatype = "xml"
    subject = "TrafficInfo"
    reqrange = "1/1"
    with open('seoul_linkid.csv', 'r', newline='') as lid: #4797개 ID 목록
        reader = csv.reader(lid)
        lidList = [str(x[0]) for x in reader]
    tt = "{:%Y-%m-%d.%H.%M.%S}".format(datetime.datetime.now())
    result = open(f"seoul_trafficinfo_{tt}.csv", 'w', newline='')
    csvwriter = csv.writer(result, delimiter=',')
    csvwriter.writerow(['ID','LINK_ID','SPD','TRV_TIME'])
    i = 1
    for el in lidList:
        urljoined = "/".join([urlbase,key,datatype,subject,reqrange,el])
        r = requests.get(urljoined, stream=True)
        try:
            row = etree.fromstring(r.text)[2]
            link_id = row.find('link_id').text
            spd = row.find('prcs_spd').text
            trvt = row.find('prcs_trv_time').text
            csvwriter.writerow([i,link_id,spd,trvt])
            i += 1
        except Exception as err:
            print("LINK_ID ", str(el), "failed:", err)
            continue
    result.close()
    print(f"writing {i!s} rows to csv done")



'visualization' 카테고리의 다른 글

서울의 도로교통 패턴 #5: 서울로7017  (0) 2018.01.03
서울의 도로교통 패턴 #4  (0) 2017.12.12
서울의 도로교통 패턴 #3  (0) 2017.12.08
서울의 도로교통 패턴 #2  (0) 2017.12.03
prologue  (0) 2017.11.30
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday