사람마다 여행 스타일이 다르고 목적지마다 여행 컨셉이 다르다. 도쿄에 여행을 가면 어디를 주로 공략해야 할까? 신주쿠? 시부야? 긴자? 여행 책자를 뒤져보는 것도 좋고, 카페나 지식인에 물어보는 것도 좋지만 실제 데이터를 들여다보면 어떨까? 일본 자유여행은 구글 지도와 함께 하는 것이 진리인 만큼 구글의 장소 데이터를 사용하면 맛집이나 카페, 미술관이 어디에 많은지 도쿄에 직접 가보지 않아도 알 수 있다!

아래에 구글 소프트웨어 캠프에서 데이터를 수집하고 분석했던 과정을 정리했다.

1. 데이터 수집

Google Places API를 사용해서 구글 지도에 등장하는 장소 데이터를 DB에 쌓았다. API에서 제공하는 여러 검색기능 중 nearbysearch를 사용하였다. Query point의 위도와 경도, 반경을 기준으로 검색하며, 장소 카테고리를 제한하여 검색할 수도 있다. 제공되는 정보는 장소명, 장소유형, 평점, 가격수준 등이 있다. 총 96개의 장소유형 중 restaurant, bakery, shopping_mall 등 여행자가 관심을 가지는 유형의 장소 데이터만 수집했다 (bank, fire_station, movie_rental과 같이 여행과 관련도가 낮은 유형은 제외하였다).

만약 Google Place API를 사용하고 싶다면 아래 사항들을 명심하자. 1번과 2번은 API문서에 명시되어 있지만 3번은 나의 삽질과 스택 오버플로 검색 결과를 통해 알게되었다.

  1. API에서 과부하를 막기 위해 24시간동안 1,000번의 요청까지만 허용한다. 즉, 1,001번째 요청부터는 OVER_QUERY_LIMIT라는 할당량 초과 오류 메시지가 뜨며 검색 결과가 표시되지 않는다.
    • 해결: 결제카드를 등록하면 150,000개로 가능한 요청 개수을 늘릴 수 있다. 만약 그마저도 넘어가면 과금된다 (근데 싸다).
  2. 장소 검색 요청당 최대 20개 장소 결과만 반환된다. 만약 검색 결과가 20개를 넘어가면 응답 JSON 내 next_page_token라는 문자열을 사용하여 추가 결과를 가져올 수 있다. 표시할 추가 결과가 없는 경우 next_page_token이 반환되지 않는다. 최대 60개의 결과가 반환될 수 있다.
    • 이 제약조건 때문에 검색반경 설정에 애먹었다. 검색반경을 크게 설정하면 요청수를 줄일수는 있지만 수집되지 못한 장소가 많아진다. 검색반경을 작게 설정하면 거의 모든 장소의 데이터를 수집할 수 있지만 요청수가 제한 개수를 넘어갈 수 있다.
    • 고민 끝에, 최초 반경은 크게 설정하되, 검색 결과가 60개가 넘어가면 검색 영역을 4등분하여 4번 검색하는 과정을 반복하는 재귀적 방법으로 처리했다.
  3. 요청과 요청 사이에 시간차를 둬야 한다. 스택오버플로에서는 2초라고 말하는데, 경험상 시간차가 없어도 잘 작동하는 경우도 많았다.
    • 개인적으로 이것때문에 엄청 애먹었다. 할당량 한계치를 넘지도 않았는데 OVER_QUERY_LIMIT 메시지가 자꾸 뜨니 어찌나 당황스럽던지…

2. 데이터 전처리

총 150,000+개의 장소를 수집하였다. 근데 너무 많다. 여행자가 방문하는 장소는 그 중 일부일테니, 중요도가 낮은 장소를 삭제하기로 결정했다. 평점이 없거나 3점 미만인 장소, 리뷰 개수가 2개 이하인 장소를 삭제 (리뷰 개수가 적으면 평점 신뢰도가 낮다고 판단)하였으며 약 38,000개의 장소가 남았다. 그 외 장소 오분류가 되어있거나 불필요하게 수집된 장소(정육점 등)도 수기로 삭제했다. 수 십 개의 장소유형도 데이터를 살펴보고 재정의하여 14개로 줄였다.

아래는 전처리 후 데이터 요약 표이다.

preprocessed_data

데이터를 살펴보면서 일본 특유의 카페가 많은 것을 알 수 있었다. 한국 카페는 대부분 프랜차이즈인데, 일본의 카페는 메이드 카페나 아이돌 카페는 기본이요, 부엉이 카페와 같은 동물 카페, 꽃집과 겸업하는 카페도 많았다.

3. 장소유형 별 밀도함수 추정

밀도함수를 추정하기 위해 Kernel density estimation (KDE)을 주로 사용했다. 쉽게 말하면 부드럽게 이어진 히스토그램을 그려보는 거고, 빨간색에 가까울수록 상점이나 카페와 같은 장소가 많이 몰려있다는 뜻이다.

아래는 모든 장소에 대한 밀도함수 추정 결과이다. 검정색 작은 점들은 기차역이나 지하철역이다. 도쿄역과 긴자 근처, 신주쿠 근처에 장소가 밀집되어 있음을 확인할 수 있다.

all_places

장소유형 별로 살펴보자. 아래는 8개 장소유형에 대한 밀도함수 추정 결과이다. 아무래도 restaurant이 가장 많다보니 모든 장소와 restaurant 유형에 대한 밀도함수 추정 결과가 상당히 유사하다. 몇 가지 신기한 결과도 나왔다. museum 유형의 장소는 ueno에 많고, bar 유형의 장소는 shinjuku에 많다. 도시 전체적으로 park 유형의 장소가 비교적 고르게 분포하는 것을 볼 수 있는데, 데이터를 살펴보니 도쿄 내에는 크고 작은 공원이 매우 많음을 알 수 있었다.

by_cat1 by_cat2

도쿄는 대중교통이 발달하여 역이 조밀하게 분포하므로 역 기준으로 주요 구역을 선정하기로 했다. 아래는 역마다 밀도함수값을 계산하여 가장 높은 밀도함수값을 가지는 유형으로 색을 입힌 산점도이다. 원의 크기가 클수록 밀도값(점수)가 크다. 뭔가 특징이 보이는가?

scatterplot_original

비슷한 유형의 인접한 큰 원들을 묶어보았다. 총 6개의 주요 지역을 선택하여 아래에 표시하였다.

scatterplot_description

여기에는 표시하지 않았지만, 묶인 지역 안에서도 구역마다 특성이 나뉘었다. 예를 들어, ‘도쿄역/긴자/신바시’에서 도쿄역으로 갈수록 베이커리가 많았고, 긴자쪽으로 갈수록 카페나 레스토랑이 많았다. 신바시에는 레스토랑이나 바, 숙소가 많았다.

[별첨] 웹 어플리케이션 구현

페이스북에서 제공하는 자바스크립트 라이브러리 React를 사용하여 장소 데이터와 분석 결과를 보여주는 웹 어플리케이션 데모를 구현했다. 주요 구역을 지도에 표시하고, 장소유형마다 현재 지도 위치에 상위 장소들을 보여주고, 장소 마커를 클릭하면 세부정보를 보여주는 것이 주 기능이다. 이 몹쓸 React (+Redux) 때문에 팀원들이 정말 많이 고생했다…ㅠㅠ

근데 진짜 예쁘게 구현됐다! 실제 Google maps 개발자에게 neat하다고 칭찬도 받았다!

app_main

app_cluster