folium을 이용한 서울시 스타벅스 이디야 입지 시각화
“왜 스타벅스 옆에는 항상 토종 커피 브랜드 ‘이디야’가 있을까?”와 같은 뉴스 기사를 보면 이디야는 스타벅스와 같이 장사가 잘 되는 점포 인근에 위치해 있다고 합니다. 실제로 Folium 라이브러리르 활용해 파이썬으로 스타벅스와 이디야 점포들의 위치를 서울시 지도 위에 시각화하여 직관적으로 확인해보도록 하겠습니다.
더 많은 파이썬 라이브러리 관련 정보
folium 설치
터미널을 실행하여 다음 명령어를 통해 folium
을 설치합니다.
> pip install folium
라이브러리 임포트하기
아래와 같이 기본적인 파이썬 라이브러리들을 임포트합니다.
import folium
import json
import glob
import os
import pandas as pd
import numpy as np
스타벅스 및 이디야 데이터 가져오기
지도 상에 스타벅스, 이디야 점포들을 시각화하기 위해서는 각각의 점포들의 위치 정보를 알아야 합니다. 소상공인시장진흥공단
에서 제공하는 상권정보 데이터에는 스타벅스, 이디야 뿐 아니라 전국의 다양한 업종의 상가업소 정보가 담겨있습니다. 이 데이터는 현재 공공데이터포털에서 다운로드 받을 수 있습니다. Open API로 데이터를 불러오는 방법도 있지만 이번 포스팅에서는 CSV 파일을 직접 다운로드 받아 시각화하도록 하겠습니다.
공공데이터포털 - 상가(상권)정보에 접속합니다. 19년 10월 현재 기준 가장 최근 데이터인소상공인시장진흥공단_상가업소정보_201906.zip
을 다운로드합니다.
다운로드 받은 zip
파일을 파이썬 분석 환경 내 Data/
폴더에 다음과 같이 풀어줍니다.
(Data 폴더 내에 CSV 파일들이 위치하도록 합니다.)
데이터 불러오기
다운로드 받은 CSV 파일을 불러오겠습니다. 4개 파일을 불러와 하나의 데이터프레임인 df
로 할당합니다.
path = 'Data/'
allFiles = glob.glob(os.path.join(path+"*.csv"))
df = pd.DataFrame()
for file in allFiles:
print(file)
temp = pd.read_csv(file, engine='python', encoding='utf-8')
df = pd.concat([df, temp])
Data\소상공인시장진흥공단_상가업소정보_201906_01.csv
Data\소상공인시장진흥공단_상가업소정보_201906_02.csv
Data\소상공인시장진흥공단_상가업소정보_201906_03.csv
Data\소상공인시장진흥공단_상가업소정보_201906_04.csv
데이터 컬럼 확인하기
print('컬럼 항목 수 :', len(df.columns))
list(df.columns)
컬럼 항목 수 : 39
['상가업소번호',
'상호명',
'지점명',
'상권업종대분류코드',
'상권업종대분류명',
'상권업종중분류코드',
'상권업종중분류명',
'상권업종소분류코드',
'상권업종소분류명',
'표준산업분류코드',
'표준산업분류명',
'시도코드',
'시도명',
'시군구코드',
'시군구명',
'행정동코드',
'행정동명',
'법정동코드',
'법정동명',
'지번코드',
'대지구분코드',
'대지구분명',
'지번본번지',
'지번부번지',
'지번주소',
'도로명코드',
'도로명',
'건물본번지',
'건물부번지',
'건물관리번호',
'건물명',
'도로명주소',
'구우편번호',
'신우편번호',
'동정보',
'층정보',
'호정보',
'경도',
'위도']
상권업종 간단하게 확인하기
print('='*70)
print('상권업종대분류명', set(df['상권업종대분류명']))
print('='*70)
print('상권업종중분류명', set(df['상권업종중분류명']))
print('='*70)
======================================================================
상권업종대분류명 {'음식', '생활서비스', '의료', '관광/여가/오락', '소매', '부동산', '숙박', '스포츠', '학문/교육'}
======================================================================
상권업종중분류명 {'가전제품소매', '경마/경륜/성인오락', '학원-음악미술무용', '철물/난방/건설자재소매', '사진', '유아용품', '애견/애완/동물', '패스트푸드', '학원-컴퓨터', '건강/미용식품', '유흥주점', '운동/경기용품소매', '일식/수산물', '양식', '종교용품판매', '학원-보습교습입시', '부동산중개', 'PC/오락/당구/볼링등', '세탁/가사서비스', '의료관련서비스업', '유아교육', '음식배달서비스', '놀이/여가/취미', '닭/오리요리', '유사의료업', '학원기타', '운영관리시설', '취미/오락관련소매', '사무/문구/컴퓨터', '약국/한약방', '대행업', '분양', '가정/주방/인테리어', '운송/배달/택배', '중고품소매/교환', '기타판매업', '주유소/충전소', '주택수리', '물품기기대여', '시계/귀금속소매', '법무세무회계', '인력/고용/용역알선', '의복의류', '부동산관련서비스', '이/미용/건강', '장례/묘지', '예술품/골동품/수석/분재', '부페', '광고/인쇄', '캠프/별장/펜션', '예식/의례/관혼상제', '모텔/여관/여인숙', '가구소매', '평가/개발/관리', '자동차/자동차용품', '스포츠/운동', '학문교육기타', '호텔/콘도', '화장품소매', '가방/신발/액세서리', '요가/단전/마사지', '실내운동시설', '도서관/독서실', '실외운동시설', '기타음식업', '무도/유흥/가무', '한식', '학원-자격/국가고시', '제과제빵떡케익', '사진/광학/정밀기기소매', '자동차/이륜차', '기타서비스업', '분식', '학원-어학', '대중목욕탕/휴게', '음/식료품소매', '수의업', '행사/이벤트', '종합소매점', '의약/의료품소매', '민박/하숙', '책/서적/도서', '커피점/카페', '유스호스텔', '학원-예능취미체육', '개인/가정용품수리', '학원-창업취업취미', '페인트/유리제품소매', '연극/영화/극장', '개인서비스', '별식/퓨전요리', '중식', '병원', '선물/팬시/기념품'}
======================================================================
데이터프레임의 컬럼 항목은 총 39개나 됩니다.
그러나 여기서 관심있는 부분은 스타벅스, 이디야와 같은 커피전문점의 위치정보입니다.
따라서 불필요한 컬럼은 제외하고, 관심있는 컬럼만 따로 떼어 dataset
을 새로 만들겠습니다.
관련 정보만 추출
dataset = df[['상호명','지점명',
'상권업종대분류명', '상권업종중분류명',
'시도명', '시군구명', '행정동명',
'위도', '경도']]
dataset.head()
상호명 | 지점명 | 상권업종대분류명 | 상권업종중분류명 | 시도명 | 시군구명 | 행정동명 | 위도 | 경도 | |
---|---|---|---|---|---|---|---|---|---|
0 | 커피빈코리아선릉로93길점 | 코리아선릉로93길점 | 음식 | 커피점/카페 | 서울특별시 | 강남구 | 역삼1동 | 37.505675 | 127.047883 |
1 | 프로포즈 | NaN | 음식 | 유흥주점 | 서울특별시 | 금천구 | 독산3동 | 37.471711 | 126.899220 |
2 | 싱싱커피&토스트 | NaN | 음식 | 패스트푸드 | 부산광역시 | 사상구 | 괘법동 | 35.159774 | 128.980455 |
3 | 와라와라호프 | NaN | 음식 | 유흥주점 | 서울특별시 | 강남구 | 대치1동 | 37.493922 | 127.061026 |
4 | 가락사우나내스낵 | NaN | 생활서비스 | 대중목욕탕/휴게 | 서울특별시 | 송파구 | 석촌동 | 37.500249 | 127.104071 |
커피 전문점 데이터 추출
여러 상권업소 중 서울시 내 커피 전문점 업소만 추출해 df_coffee
를 정의합니다.
즉, 시도명
이 서울특별시
이면서, 상권업종중분류명
이 커피점/카페
인 경우를 뜻합니다.
df_coffee = dataset[(dataset['상권업종중분류명']=='커피점/카페')&(dataset['시도명']=='서울특별시')]
df_coffee.index = range(len(df_coffee))
print('서울시 내 커피 전문점 점포 수 :', len(df_coffee))
df_coffee.head()
서울시 내 커피 전문점 점포 수 : 18651
상호명 | 지점명 | 상권업종대분류명 | 상권업종중분류명 | 시도명 | 시군구명 | 행정동명 | 위도 | 경도 | |
---|---|---|---|---|---|---|---|---|---|
0 | 커피빈코리아선릉로93길점 | 코리아선릉로93길점 | 음식 | 커피점/카페 | 서울특별시 | 강남구 | 역삼1동 | 37.505675 | 127.047883 |
1 | 스완카페트 | NaN | 음식 | 커피점/카페 | 서울특별시 | 영등포구 | 대림3동 | 37.503693 | 126.897710 |
2 | 왕실 | NaN | 음식 | 커피점/카페 | 서울특별시 | 중구 | 명동 | 37.562274 | 126.982419 |
3 | 커피빈 | 코리아교대점 | 음식 | 커피점/카페 | 서울특별시 | 서초구 | 서초1동 | 37.492388 | 127.014217 |
4 | 고려대학교교육관쎄리오점 | NaN | 음식 | 커피점/카페 | 서울특별시 | 성북구 | 안암동 | 37.588485 | 127.031702 |
스타벅스 데이터 추출
먼저 서울시 내 커피 전문점 18,651개 업소 중 스타벅스 점포에 대한 데이터프레임을 만들어보겠습니다.
df_seoul_starbucks = df_coffee[df_coffee['상호명'].str.contains('스타벅스')]
df_seoul_starbucks.index = range(len(df_seoul_starbucks))
print('서울시 내 스타벅스 점포 수 :', len(df_seoul_starbucks))
df_seoul_starbucks.head()
서울시 내 스타벅스 점포 수 : 499
상호명 | 지점명 | 상권업종대분류명 | 상권업종중분류명 | 시도명 | 시군구명 | 행정동명 | 위도 | 경도 | |
---|---|---|---|---|---|---|---|---|---|
0 | 스타벅스 | 이태원점 | 음식 | 커피점/카페 | 서울특별시 | 용산구 | 이태원1동 | 37.534303 | 126.994781 |
1 | 스타벅스종로3가점 | 종로3가점 | 음식 | 커피점/카페 | 서울특별시 | 종로구 | 종로1.2.3.4가동 | 37.570585 | 126.990207 |
2 | 스타벅스 | 신사2점 | 음식 | 커피점/카페 | 서울특별시 | 서초구 | 잠원동 | 37.513663 | 127.019763 |
3 | 스타벅스커피여의도IFC1F | NaN | 음식 | 커피점/카페 | 서울특별시 | 영등포구 | 여의동 | 37.525172 | 126.924863 |
4 | 스타벅스 | 삼성역점 | 음식 | 커피점/카페 | 서울특별시 | 강남구 | 삼성1동 | 37.510038 | 127.063878 |
이디야 데이터 추출
이번엔 서울시 내 커피 전문점 18,651개 업소 중 이디야 점포에 대한 데이터프레임을 만들어보겠습니다.
df_seoul_ediya = df_coffee[df_coffee['상호명'].str.contains('이디야')]
df_seoul_ediya.index = range(len(df_seoul_ediya))
print('서울시 내 이디야 점포 수 :', len(df_seoul_ediya))
df_seoul_ediya.head()
서울시 내 이디야 점포 수 : 489
상호명 | 지점명 | 상권업종대분류명 | 상권업종중분류명 | 시도명 | 시군구명 | 행정동명 | 위도 | 경도 | |
---|---|---|---|---|---|---|---|---|---|
0 | 이디야커피 | 신길역점 | 음식 | 커피점/카페 | 서울특별시 | 영등포구 | 신길1동 | 37.515118 | 126.918062 |
1 | 이디야커피 | 이마트구로점 | 음식 | 커피점/카페 | 서울특별시 | 구로구 | 구로3동 | 37.484385 | 126.897870 |
2 | 이디야커피 | 중계롯데우성점 | 음식 | 커피점/카페 | 서울특별시 | 노원구 | 중계1동 | 37.646364 | 127.072754 |
3 | 이디야커피 | 금호역점 | 음식 | 커피점/카페 | 서울특별시 | 성동구 | 금호2.3가동 | 37.548427 | 127.017791 |
4 | 이디야커피 | NaN | 음식 | 커피점/카페 | 서울특별시 | 강남구 | 대치2동 | 37.508585 | 127.064790 |
서울시 구 별 스타벅스 수
서울시 구 별 스타벅스 점포의 수를 구해보겠습니다.
starbucks_gu = df_seoul_starbucks.groupby('시군구명')['상호명'].count().to_frame().sort_values(by='상호명', ascending=False)
starbucks_gu = starbucks_gu.reset_index()
starbucks_gu = starbucks_gu.set_index('시군구명')
starbucks_gu
상호명 | |
---|---|
시군구명 | |
강남구 | 84 |
중구 | 55 |
서초구 | 47 |
종로구 | 33 |
영등포구 | 30 |
마포구 | 30 |
송파구 | 28 |
용산구 | 20 |
서대문구 | 19 |
강서구 | 17 |
광진구 | 14 |
강동구 | 13 |
금천구 | 13 |
성북구 | 13 |
구로구 | 11 |
은평구 | 10 |
양천구 | 10 |
노원구 | 9 |
관악구 | 9 |
동대문구 | 8 |
동작구 | 8 |
성동구 | 6 |
중랑구 | 6 |
강북구 | 5 |
도봉구 | 1 |
서울시 구 별 이디야 수
서울시 구 별 이디야 점포의 수를 구해보겠습니다.
ediya_gu = df_seoul_ediya.groupby('시군구명')['상호명'].count().to_frame().sort_values(by='상호명', ascending=False)
ediya_gu = ediya_gu.reset_index()
ediya_gu = ediya_gu.set_index('시군구명')
ediya_gu
상호명 | |
---|---|
시군구명 | |
강남구 | 42 |
강서구 | 39 |
노원구 | 33 |
영등포구 | 27 |
송파구 | 27 |
중구 | 24 |
관악구 | 23 |
성북구 | 22 |
은평구 | 21 |
마포구 | 21 |
구로구 | 20 |
동대문구 | 19 |
서초구 | 17 |
성동구 | 17 |
양천구 | 17 |
광진구 | 16 |
종로구 | 16 |
서대문구 | 13 |
강동구 | 12 |
동작구 | 11 |
금천구 | 11 |
용산구 | 11 |
강북구 | 11 |
중랑구 | 11 |
도봉구 | 8 |
서울특별시 폴리곤 JSON 파일 불러오기
folium을 통해 서울시 지도 위에 점포들을 시각화하기 위해서는 지리 정보를 담고 있는 폴리곤 json 파일이 필요합니다.
PinkWink(github)에 접속 후 02.%20skorea_municipalities_geo_simple.json
을 Data/
폴더에 다운로드하여 불러옵니다.
간편 다운로드 방법
skorea_municipalities_geo_simple.json 링크를 우클릭하여 다른 이름으로 링크 저장
합니다.
(출처:PinkWink(github))
geo_path = 'Data/02. skorea_municipalities_geo_simple.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))
서울시 구 별 스타벅스 분포도 시각화
# 위치 파라미터 설정
loc = [37.5502, 126.982] # 위도(N), 경도(E)
data_size = len(df_seoul_starbucks)
# 지도 정의
map_starbucks = folium.Map(location=loc, zoom_start=12)
map_starbucks.choropleth(geo_data=geo_str,
data = starbucks_gu['상호명'],
columns=[starbucks_gu.index, starbucks_gu['상호명']],
fill_color='PuRd',
key_on='feature.id')
# 포인트 마커 추가
for i in range(data_size):
folium.Marker(list(df_seoul_starbucks.iloc[i][['위도', '경도']]),
popup=df_seoul_starbucks.iloc[i][['지점명']],
icon=folium.Icon(color='green')).add_to(map_starbucks)
map_starbucks
서울시 구 별 이디야 분포도 시각화
# 위치 파라미터 설정
loc = [37.5502, 126.982] # 위도(N), 경도(E)
data2_size = len(df_seoul_ediya)
# 지도 정의
map_ediya = folium.Map(location=loc, zoom_start=12)
map_ediya.choropleth(geo_data=geo_str,
data = ediya_gu['상호명'],
columns=[ediya_gu.index, ediya_gu['상호명']],
fill_color='PuRd',
key_on='feature.id')
# 포인트 마커 추가
for i in range(data2_size):
folium.Marker(list(df_seoul_ediya.iloc[i][['위도', '경도']]),
popup=df_seoul_ediya.iloc[i][['지점명']],
icon=folium.Icon(color='blue')).add_to(map_ediya)
map_ediya