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
서울시 스타벅스 및 이디야 입지 시각화
# 위치 파라미터 설정
loc = [37.5502, 126.982] # 위도(N), 경도(E)
data_size = len(df_seoul_starbucks)
data2_size = len(df_seoul_ediya)
# 지도 정의
map = folium.Map(location=loc,
tiles = 'Stamen Toner',
zoom_start=11)
# 포인트 마커 추가
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)
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)
map
점포 별 반경 100m 서클 시각화
# 위치 파라미터 설정
# 강남역 좌표
loc = [37.497895, 127.027565] # 위도(N), 경도(E)
data_size = len(df_seoul_starbucks)
data2_size = len(df_seoul_ediya)
# 지도 정의
map = folium.Map(location=loc,
tiles = 'Stamen Toner', # 'OpenStreetMap'
zoom_start=14)
# 포인트 서클 추가
for i in range(data_size):
folium.Circle(list(df_seoul_starbucks.iloc[i][['위도', '경도']]),
radius = 100,
popup = df_seoul_starbucks.iloc[i]['지점명'],
color = '#2c9147',fill_color = '#2c9147').add_to(map)
for i in range(data2_size):
folium.Circle(list(df_seoul_ediya.iloc[i][['위도', '경도']]),
radius = 100,
popup = df_seoul_ediya.iloc[i]['지점명'],
color = '#32408c',fill_color = '#32408c').add_to(map)
map
결론
점포 별 반경 100m 서클 시각화 결과는 강남역을 중심으로 확대한 지도를 보여주고 있습니다. 점포 마다 반경 100m 지역을 원으로 나타내고 있습니다. 반원을 점포의 직접적인 상권으로 가정하면, 초록색 원인 스타벅스와 파란색 원인 이디야 사이에 직접적인 상권이 겹치는 부분이 심심치 않게 보입니다. 또한, 두 브랜드 모두 특정 도로를 중심으로 분포하고 있는 모습을 확인할 수 있습니다. 시각화 결과만 놓고 보면 두 점포가 매우 가까이에 위치해 있는 것을 알 수 있습니다. 다만, 이는 두 브랜드를 비교한 결과이기때문에 스타벅스와 이디야만 근접해있다고 볼 수는 없다는 한계가 있습니다.
댓글남기기