강남구의 분리수거함 위치를 알아보자

..·2024년 8월 13일

finder

목록 보기
11/23

데이터 분석에 대해 학습하면서, 조금 더 공부해 보고 싶어서 또 다른 주제와 그에 따른 데이터를 찾아보게 되었다.
프로젝트까지 가져갈 수 있다면 어떤 주제가 좋을까 생각하다가, 위치 데이터가 필요하지만 상용하는 지도 서비스에서 검색을 통해 얻을 수 없는 정보 중 폐건전지 수거함에 대해 떠올리게 되었다.

실제로 지도 서비스에서 건전지 수거함을 검색했을 때의 화면이다.
위치 정보가 필요하지만 지도 서비스에서는 찾아보기 어려운 정보였다.


주제 선정과 목표

항상 모든 프로젝트를 시작할 때, 단순한 CRUD를 구현하는 것보다 이러한 기능으로 활용할 수 있도록 뒷받침이 되는 데이터를 갖추는 것이 번거로워 매번 흐지부지했던 것이 생각났다. 그래서 프로젝트라기보단 원하는 결과를 얻기 위한 데이터 분석 과정에 대해 기록해 보려고 한다.

강남구에 존재하는 폐건전지 수거함의 위치를 지도 상에 나타내보자

데이터의 기준은 서울특별시의 강남구로 선정하였고, 공공 데이터 포털에서 CSV 파일을 사용했다.

목표

강남구에 존재하는 폐건전지/폐형광등 수거함의 위치를 지도 상에 표현해 보자!



데이터 확인하기

서울특별시 강남구 폐형광등/폐건전지 분리수거함 위치

데이터를 확인해 보니, 대체적으로 최소한의 정보만 제공하고 있었다.
가장 중요한 설치위치 데이터는 도로명 또는 지번 주소가 혼용되어 있었고, 경우에 따라 건물 내부 주소(본관 1층 로비 등)가 포함되어 있는 데이터도 있었다.

지도 상에 이러한 주소 정보를 나타내기 위해서는 좌표 정보가 필요했고, 가지고 있는 주소 정보를 좌표 정보로 변환할 수 있는 기능이 필요했다.



geopy를 이용한 주소-좌표 변환

python에서는 geopy라는 라이브러리를 이용하여 주소를 좌표로 변환할 수 있다는 것을 알게 되었다.

먼저, geopy를 설치했다.

pip install geopy

그리고 데이터 파일을 읽어서 주소를 좌표로 변환했다.

from geopy.geocoders import Nominatim
import pandas as pd

# 주소를 받으면 좌표로 변환
def geocoding(address):
    geoloader = Nominatim(user_agent = 'South Korea', timeout=None)
    geo = geoloader.geocode(address)
    if geo == None:
        crd = None
    else:
        crd = {"lat": str(geo.latitude), "lon": str(geo.longitude)}
    return crd

df = pd.read_csv("./서울특별시_강남구_폐형광등 폐건전지 분리수거함 위치.csv", encoding="cp949")
address = df['설치위치'].copy()

# 주소 데이터를 이용하여 좌표로 변환하도록 반복
for ad in address:
    crd = geocoding(ad)
    if crd == None:
        print(ad)
    else:
    	print(crd)

🚨 주소 검색 오류 발생

위치를 South Korea로 설정하고, 주소를 입력받으면 좌표로 변환하도록 작성했다.
주소를 좌표로 변환하는 과정에서 일부 데이터가 None으로 반환되는 것을 알게 되었다. 자세히 알아보니, 설치위치 데이터에 지번 또는 도로명 주소 이외의 정보가 포함되어 있어서 주소 검색 및 좌표 변환에 실패한다는 것을 알 수 있었다.
또한 일부 주소는 추가적인 주소 데이터가 없음에도 지번과 도로명 주소에 관계없이 주소 검색에 실패하여 좌표 변환 오류가 있음을 확인했다.

이러한 문제를 해결하기 위해서는 조금 더 정밀한 주소 검색이 필요하다고 판단해서 카카오 맵 API를 사용하는 방법을 선택했다.



kakaomap API 사용하기

카카오맵 API

1. 애플리케이션 등록하기


새로운 애플리케이션을 등록한다.
애플리케이션을 등록하면, 추가적인 설정을 통해 API에 접근할 수 있게 된다.

2. 도메인 설정하기

[내 애플리케이션 > 앱 설정 > 플랫폼] 화면에서 Web 사이트 도메인을 등록한다.
나는 주피터 노트북으로 코드를 작성하면서 테스트하고 있었기 때문에 http://localhost:8888로 등록했다.

3. API 테스트

[내 애플리케이션 > 앱 설정 > 앱 키]에서 내 애플리케이션의 Key를 발급받을 수 있는데, 주소를 좌표로 변환하는 API를 사용할 때에는 REST API Key를 이용한다.
예제에서는 header에 KakaoAK [REST API Key]를 작성해서 사용한다.
query에는 좌표로 변환할 주소를 입력하고, API를 요청한다.

예시 코드

# python에서 HTTP를 사용하기 위한 라이브러리
import requests

url = 'https://dapi.kakao.com/v2/local/search/address.json'
headers = {'Authorization': 'KakaoAK [REST API Key]'}
query = {'query': '서울특별시 강남구 학동로 426, 2별관 3층 청소행정과'}
location = requests.get(url, headers=headers, data=query).json()
location

실행 결과

{
	'documents': [{
      'address': {
        'address_name': '서울 강남구 삼성동 111-44',
        'b_code': '1168010500',
        'h_code': '1168059000',
        'main_address_no': '111',
        'mountain_yn': 'N',
        'region_1depth_name': '서울',
        'region_2depth_name': '강남구',
        'region_3depth_h_name': '삼성2동',
        'region_3depth_name': '삼성동',
        'sub_address_no': '44',
        'x': '127.04687101523',
        'y': '37.5180970797244'
     },
     'address_name': '서울 강남구 학동로 426-2',
     'address_type': 'ROAD_ADDR',
     'road_address': {
       'address_name': '서울 강남구 학동로 426-2',
        'building_name': '가로판매대',
        'main_building_no': '426',
        'region_1depth_name': '서울',
        'region_2depth_name': '강남구',
        'region_3depth_name': '삼성동',
        'road_name': '학동로',
        'sub_building_no': '2',
        'underground_yn': 'N',
        'x': '127.04687101523',
        'y': '37.5180970797244',
        'zone_no': '06090'
      },
     'x': '127.04687101523',
     'y': '37.5180970797244'
  }],
 'meta': {'is_end': True, 'pageable_count': 1, 'total_count': 1}
}

kakaomap을 사용하기로 결정한 이유

지번 또는 도로명 주소 이외에 구체적인 장소에 대한 데이터가 포함되어 있어도 제대로 주소 검색이 이루어지면서 좌표를 얻을 수 있다는 것을 알게 되었다.
geopy를 이용할 때에는 주소 검색을 위해 데이터를 수정하는 과정이 필요했는데, 혹시나 하고 사용했던 kakaomap API에서는 데이터 수정 없이도 대체로 정확한 결과를 얻을 수 있어서 kakaomap API를 이대로 계속 사용하기로 결정했다.



🚨 사라진 주소 데이터 오류

lat = location['documents'][0]['y']
lon = location['documents'][0]['x']

{'documents': [], 'meta': {'is_end': True, 'pageable_count': 0, 'total_count': 0}}

주소를 검색해서 좌표 데이터를 얻을 때는 다음과 같이 접근했다. 그런데 요청 결과 중에서 documents가 빈 배열이거나, 응답 자체가 NoneType인 경우가 발생했다. 직접 해당 값을 검색해 보니, 현재 존재하지 않는 주소여서 검색 결과가 나타나지 않는 경우였다.
따라서 이러한 오류가 발생하는 값은 존재하지 않는 데이터라고 판단하여 예외로 처리하도록 했다.



Folium을 이용한 데이터 시각화

Folium 공식 문서

추출한 주소와 좌표 데이터를 보기 쉽게 나타내기 위해서는 지도가 필요했다.
Folium을 이용하면 지도 상에 데이터를 쉽게 표현할 수 있다.

import folium

map = folium.Map(location=[locations["lat"].mean(), locations["lon"].mean()], zoom_start=13)

# locations: 주소를 통해 얻은 좌표 값이 존재하는 Dataframe
for n in locations.index:
    address = locations.loc[n, "address"]
    popup = f"{address}"
    location = [locations.loc[n, "lat"], locations.loc[n, "lon"]]
    folium.Marker(
        location = location,
        popup = popup,
    ).add_to(map)
map

먼저, 구한 좌표의 경도와 위도 평균 위치를 구하여 해당 위치가 보이도록 지도를 생성한다.
그리고 좌표 값을 이용하여 생성한 지도에 마커를 추가한다.
마커를 클릭하면 해당 위치의 주소를 보여주는 팝업을 추가했다.



강남구의 분리수거함 위치를 나타낸 지도

사진은 존재하지 않는 주소를 제외한 강남구의 모든 폐건전지 분리수거함 위치를 지도에 나타낸 결과이다.
파일 데이터에서 주소 데이터를 추출하고, kakaomap API를 통해 좌표 값을 구했다.
마지막으로는 folium Map을 통해 강남구의 폐건전지 분리수거함 위치를 시각화할 수 있었다.

지도 상에 존재하는 마커를 클릭하면, 해당 마커의 주소를 팝업으로 보여준다.



개선 방향성

이번에는 임시로 간단하게 정보를 알아보기 위해 데이터와 API를 사용했지만, 여러 데이터를 이용하여 반복적으로 API를 호출하는 과정에서 많은 시간이 소요되었다. 따라서 이를 실제로 서비스로 제공한다면 어떤 점을 개선할 수 있을지 생각해 보았다.

데이터베이스에 적재

위치 정보를 제공하기 위해서는 매번 모든 데이터를 읽어서 제공하는 것보다, 데이터베이스에 적재하고 필요한 구간의 데이터만 제공하는 방법으로 효율적으로 사용할 수 있을 것이다.

좌표 컬럼 추가

현재는 주소 데이터를 읽은 후, 좌표 변환 API를 통해 데이터를 하나씩 변환하면서 결과 제공까지 시간이 오래 걸리고 효율이 떨어지는 방식을 사용하고 있다. 만약 주소 데이터를 데이터베이스에 적재하여 관리하게 된다면, 좌표 컬럼을 함께 추가하여 사용할 수 있다. 데이터를 적재하는 과정에서 한 번의 좌표 변환 과정을 거치고 좌표 컬럼에 데이터를 저장하면 이후에는 데이터베이스 접근을 통해 효율적으로 사용할 수 있을 것이다.

지도 API 활용하기

이번에는 간단하게 folium 지도를 사용했다.
한국의 지도 상태를 가장 효과적으로 나타내고 변경된 사항을 빠르게 반영하는 네이버 지도 또는 카카오 맵 API를 활용하여 시각화하는 것도 편리한 사용을 도울 수 있을 것이라고 생각한다.



마무리

기록하기 위해 이번 주의 학습 내용을 톺아보다가, 갑작스럽게 최근에 공부하고 있는 데이터 분석을 활용하여 나만의 결과를 얻어보고 싶다는 생각을 했다.
거창한 결과를 낸 것은 아니지만, 데이터를 직접 다루면서 원하는 결과를 내는 것에 대한 즐거움을 또 한 번 상기시킬 수 있는 좋은 경험이었다.
그리고 작은 요소들 하나를 다루더라도 어떤 이유로 어떤 결정을 고민하는 것에 대한 중요성과 필요성을 느꼈다.

만약 geopy만을 이용해서 결과를 내려고 했다면, 데이터를 하나씩 수정하거나 이에 대응하는 예외 처리로 인해 코드가 복잡해졌을 것이다. 하지만 여기서 또 다른 아이디어인 kakaomap API를 사용하는 방법을 선택함으로써 빠르고 효율적으로 다음 단계로 나아갈 수 있었다.

파이썬에서 데이터 분석을 위한 요소들을 다루는 것이 능숙하지 않아서 시간이 더 걸린 것 같지만, 계속 코드를 수정하고 내가 작성한 코드에 대해 이해하면서 나아가며 원하는 결과까지 도출할 수 있어서 뿌듯했다.

0개의 댓글