공공데이터로 파이썬 데이터 분석 시작하기 - 인프런 | 강의
이디야는 스타벅스 근처에 입점한다는 설이 있었습니다. 과연 이디야와 스타벅스의 매장입지는 얼마나 차이가 날까요? 2013년부터 2019년까지 부동산 가격 변동 추세가 아파트 분양가에도 반영될
www.inflearn.com
소상공인시장진흥공단 상가업소정보로 프랜차이즈 입점분석 (1)
[python] 소상공인시장진흥공단 상가업소정보로 프랜차이즈 입점분석 (1)
상가업소정보로 프랜차이즈 입점분석 배스킨라빈스 & 던킨도너츠 프랜차이즈 매장의 밀집도를 지도를 통해 표시하고, 이를 위해 데이터 전처리 과정을 진행한다. 다루는 내용 데이터 요약하기
imstatdust.tistory.com
배스킨라빈스, 던킨도너츠 위치 분석
1. 특정 상호만 가져오기
- 배스킨라빈스와 던킨도너츠 상호를 가져오기
- 상호명에서 브랜드명을 추출
- 대소문자가 섞여 있을 수도 있기에 대소문자를 변환
- 배스킨라빈스의 영문명은 baskinrobbins, 던킨도너츠는 dunkindonuts
# 문자열의 소문자로 변경하는 메소드 - lower()
# "상호명_소문자" 컬럼 생성
df_seoul["상호명_소문자"] = df_seoul["상호명"].str.lower()
# baskinrobbins 를 "상호명_소문자" 컬럼으로 가져옵니다.
# 띄어쓰기 등의 다를 수 있기 때문에 앞글자 baskin 만 따서 가져오도록 합니다.
# '상호명_소문자'컬럼으로 '배스킨라빈스|baskin' 를 가져와 갯수를 세어봅니다.
# loc[행]
# loc[행, 열]
df_seoul[df_seoul["상호명_소문자"].str.contains("베스킨라빈스|배스킨라빈스|baskinrobbins")]
상호명 | 상권업종대분류명 | 상권업종중분류명 | 상권업종소분류명 | 시도명 | 시군구명 | 행정동명 | 법정동명 | 도로명주소 | 경도 | 위도 | 상호명_소문자 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
76 | 배스킨라빈스 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 관악구 | 청룡동 | 봉천동 | 서울특별시 관악구 관악로 161 | 126.952166 | 37.479599 | 배스킨라빈스 |
2164 | 베스킨라빈스 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 마포구 | 서교동 | 서교동 | 서울특별시 마포구 와우산로 88 | 126.923809 | 37.552104 | 베스킨라빈스 |
11060 | 베스킨라빈스은행나무점 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 금천구 | 시흥5동 | 시흥동 | 서울특별시 금천구 금하로 726-1 | 126.910405 | 37.450433 | 베스킨라빈스은행나무점 |
13953 | 배스킨라빈스 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 강남구 | 역삼1동 | 역삼동 | 서울특별시 강남구 강남대로 390 | 127.028565 | 37.497832 | 배스킨라빈스 |
14201 | 베스킨라빈스 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 광진구 | 광장동 | 광장동 | 서울특별시 광진구 아차산로 494 | 127.096667 | 37.541145 | 베스킨라빈스 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
557464 | 배스킨라빈스31 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 은평구 | 진관동 | 진관동 | 서울특별시 은평구 진관2로 77 | 126.926589 | 37.634321 | 배스킨라빈스31 |
557822 | 배스킨라빈스31 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 서초구 | 방배4동 | 방배동 | 서울특별시 서초구 방배로 200 | 126.991649 | 37.491305 | 배스킨라빈스31 |
558006 | 배스킨라빈스31 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 동작구 | 대방동 | 대방동 | 서울특별시 동작구 알마타길 6 | 126.924959 | 37.509801 | 배스킨라빈스31 |
561929 | 배스킨라빈스31 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 송파구 | 문정2동 | 문정동 | 서울특별시 송파구 송파대로 111 | 127.124872 | 37.479617 | 배스킨라빈스31 |
561930 | 배스킨라빈스31 | 음식 | 패스트푸드 | 아이스크림판매 | 서울특별시 | 강동구 | 강일동 | 강일동 | 서울특별시 강동구 아리수로 427 | 127.174586 | 37.564954 | 배스킨라빈스31 |
466 rows × 12 columns
#str.contains에서 (베|배)스킨라빈스를 입력한다면 경고 메세지가 뜨기 때문에 다음과 같은 방식 활용 가능.
#그러나 이름 전체로 contains 코드를 작성해주면 경고 메세지는 사라짐.
df_seoul["상호명_소문자"].str.extract("(베|배)스킨라빈스|baskinrobbins")[0].value_counts()
배 347
베 117
Name: 0, dtype: int64
# 상호명에서 던킨도너츠만 가져오기
# 상호명은 소문자로 변경해 준 컬럼을 사용한다.
# 던킨|dunkin 의 "상호명_소문자"로 갯수를 센다.
df_seoul.loc[df_seoul["상호명_소문자"].str.contains("던킨|dunkin"), "상호명_소문자"]
1167 던킨도너츠
1819 던킨도너츠테크노마트점
2305 던킨도너츠창동하나로
2342 던킨도너츠용산민자역사2호
3007 던킨도너츠
...
553907 던킨도너츠
554211 던킨도너츠
558894 dunkindoonuts
560984 던킨도너츠
569825 던킨도너츠
Name: 상호명_소문자, Length: 191, dtype: object
# '상호명_소문자'컬럼으로 '배스킨|베스킨|baskin|던킨|dunkin'를 가져와 df_31 변수에 담는다.
df_31 = df_seoul[df_seoul["상호명_소문자"].str.contains('배스킨라빈스|베스킨라빈스|baskinrobbins|던킨|dunkin')].copy()
df_31.shape
(657, 12)
# ~ = not
# 나타난 결측치를 던킨도너츠로 채운다.
df_31.loc[df_31["상호명_소문자"].str.contains("배스킨라빈스|베스킨라빈스|baskinrobbins"), "브랜드명"] = "배스킨라빈스"
df_31[["상호명", "브랜드명"]].head()
상호명 | 브랜드명 | |
---|---|---|
76 | 배스킨라빈스 | 배스킨라빈스 |
1167 | 던킨도너츠 | NaN |
1819 | 던킨도너츠테크노마트점 | NaN |
2164 | 베스킨라빈스 | 배스킨라빈스 |
2305 | 던킨도너츠창동하나로 | NaN |
#브랜드명 결측치에 "던킨도너츠"로 채우기
df_31["브랜드명"] = df_31["브랜드명"].fillna("던킨도너츠")
df_31["브랜드명"]
76 배스킨라빈스
1167 던킨도너츠
1819 던킨도너츠
2164 배스킨라빈스
2305 던킨도너츠
...
558894 던킨도너츠
560984 던킨도너츠
561929 배스킨라빈스
561930 배스킨라빈스
569825 던킨도너츠
Name: 브랜드명, Length: 657, dtype: object
# 데이터가 제대로 모아졌는지 확인
# "상권업종대분류명"을 value_counts 를 통해 빈도수 계산
df_31["상권업종대분류명"].value_counts()
음식 655
소매 1
생활서비스 1
Name: 상권업종대분류명, dtype: int64
# 위의 결과에서 소매와 생활서비스 관련 데이터가 있는 것을 확인
# "상권업종대분류명"컬럼에서 isin 기능을 사용해 "소매", "생활서비스" 인 데이터만 가져온다.
df_31[df_31["상권업종대분류명"].isin(["소매", "생활서비스"])]
상호명 | 상권업종대분류명 | 상권업종중분류명 | 상권업종소분류명 | 시도명 | 시군구명 | 행정동명 | 법정동명 | 도로명주소 | 경도 | 위도 | 상호명_소문자 | 브랜드명 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
358699 | 배스킨라빈스 | 소매 | 종합소매점 | 할인점 | 서울특별시 | 강남구 | 압구정동 | 신사동 | 서울특별시 강남구 압구정로 204 | 127.029381 | 37.527375 | 배스킨라빈스 | 배스킨라빈스 |
556592 | baskinrobbins | 생활서비스 | 광고/인쇄 | 인쇄종합 | 서울특별시 | 강남구 | 역삼1동 | 역삼동 | 서울특별시 강남구 강남대로 396 | 127.028289 | 37.498154 | baskinrobbins | 배스킨라빈스 |
# "상권업종대분류명"에서 "소매", "생활서비스"는 제외.
df_31 = df_31[~df_31["상권업종대분류명"].isin(["소매", "생활서비스"])].copy()
df_31.shape
(655, 13)
2. 범주형 값으로 countplot 그리기
# value_counts 로 "브랜드명"의 빈도수 구하기
brand_count= df_31["브랜드명"].value_counts()
# normalize=True 로 빈도수의 비율 구하기
df_31["브랜드명"].value_counts(normalize=True)
배스킨라빈스 0.708397
던킨도너츠 0.291603
Name: 브랜드명, dtype: float64
df_31["브랜드명"].value_counts(normalize=True).plot.barh()
<AxesSubplot:>
# countplot
g = sns.countplot(data=df_31, x="브랜드명")
for i, val in enumerate(brand_count.index):
g.text(x=0, y=brand_count[0], s=brand_count[0])
g.text(x=1, y=brand_count[1], s=brand_count[1])
#brand_count에서 1번째 행이 baskin, 2번째행이 dunkin이므로 각 0, 1로 표현
# 시군구명으로 빈도수를 세고 브랜드명으로 색상을 다르게 표현하는 countplot 그리기
plt.figure(figsize=(15, 4))
g = sns.countplot(data=df_31, x="시군구명", hue="브랜드명")
3. scatterplot 그리기
# Pandas 의 plot 으로 scatterplot 을 그린다.
df_31[["위도", "경도"]].plot.scatter(x="경도", y="위도")
<AxesSubplot:xlabel='경도', ylabel='위도'>
# seaborn의 scatterplot 으로 hue에 브랜드명을 지정해서 시각화
sns.scatterplot(data=df_31, x="경도", y="위도", hue="브랜드명")
<AxesSubplot:xlabel='경도', ylabel='위도'>
# 위에서 그렸던 그래프를 jointplot 그리기
#jointplot은 히스토그램과 산점도 모두 나타내주는 차트
sns.jointplot(data=df_31, x="경도", y="위도")
<seaborn.axisgrid.JointGrid at 0x29ee0533fa0>
# kind="hex" 추가한 jointplot 그래프
sns.jointplot(data=df_31, x="경도", y="위도", kind="hex")
<seaborn.axisgrid.JointGrid at 0x29ee05b0eb0>
4. Folium 으로 지도 활용하기
서울의 배스킨라빈스와 던킨도너츠 매장 분포
- 배스킨라빈스와 던킨도너츠 매장을 지도에 표현
# 지도 시각화를 위한 라이브러리
import folium
# 지도의 중심을 지정하기 위해 위도와 경도의 평균을 구한다.
lat = df_31["위도"].mean()
long = df_31["경도"].mean()
# 데이터프레임의 인덱스만 출력하기
df_31.index
Int64Index([ 76, 1167, 1819, 2164, 2305, 2342, 3007, 11060,
13042, 13925,
...
554896, 555145, 557464, 557822, 558006, 558894, 560984, 561929,
561930, 569825],
dtype='int64', length=655)
4-1. 기본 마커로 표현하기
# icon=folium.Icon(color=icon_color) 로 아이콘 컬러를 변경
m = folium.Map([lat, long], zoom_start = 12)
for i in df_31.index:
sub_lat = df_31.loc[i, "위도"]
sub_long = df_31.loc[i, "경도"]
title = df_31.loc[i, "상호명"] + " - " + df_31.loc[i, "도로명주소"]
icon_color = "blue"
if df_31.loc[i, "브랜드명"] == "던킨도너츠":
icon_color = "red"
folium.Marker([sub_lat, sub_long],
icon=folium.Icon(color=icon_color),
popup=f'<i>{title}</i>',
tooltip=title).add_to(m)
m.save("index.html")
m
4-2. MarkerCluster 로 표현하기
from folium.plugins import MarkerCluster
m = folium.Map([lat, long], zoom_start = 12)
marker_cluster = MarkerCluster().add_to(m)
for i in df_31.index:
sub_lat = df_31.loc[i, "위도"]
sub_long = df_31.loc[i, "경도"]
title = df_31.loc[i, "상호명"] + " - " + df_31.loc[i, "도로명주소"]
icon_color = "blue"
if df_31.loc[i, "브랜드명"] == "던킨도너츠":
icon_color = "red"
folium.Marker([sub_lat, sub_long],
icon=folium.Icon(color=icon_color),
popup=f'<i>{title}</i>',
tooltip=title).add_to(marker_cluster)
m.save("index.html")
m
4-3. Marker 로 위치를 찍어보기
m = folium.Map([lat, long], zoom_start=12, tiles="stamen toner")
for i in df_31.index:
sub_lat = df_31.loc[i, "위도"]
sub_long = df_31.loc[i, "경도"]
title = df_31.loc[i, "상호명"] + " - " + df_31.loc[i, "도로명주소"]
icon_color = "purple"
if df_31.loc[i, "브랜드명"] == "던킨도너츠":
icon_color = "pink"
folium.CircleMarker(
[sub_lat,sub_long ],
radius=3,
color=icon_color,
popup=f'<i>{title}</i>',
tooltip=title).add_to(m)
m.save('index.html')
m
4-4. Heatmap 으로 그리기
#heatmap이란?
#heatmap = heat(열) + map(지도) , 데이터들의 배열을 색상으로 표현해주는 그래프
#heatmap을 사용하는 이유?
#heatmap을 사용하면 두 가지의 카테고리 값에 대한 변화를 알기 쉽다.
#대용량 데이터를 적은 이미지 수로 표현 가능하다.
#heat맵의 장점?
#히트맵은 방문자들이 페이지 내 컨텐츠를 소비하는 방식에 대한 보다 포괄적인 데이터를 제공
#대용량 데이터를 분석하는데 익숙하지 않은 사람들은 이를 더욱 쉽게 엑세스할 수 있다.
# [출처]
# https://ko.wikipedia.org/wiki/%ED%9E%88%ED%8A%B8_%EB%A7%B5
# https://www.thedigitalmkt.com/heatmap/
# https://dsbook.tistory.com/51
#데이터 2차원 배열 만들기
heat = df_31[["위도", "경도", "브랜드명"]].copy()
heat["브랜드명"] = heat["브랜드명"].str.strip()
heat["브랜드명"] = heat["브랜드명"].replace("배스킨라빈스", 1).replace("던킨도너츠", 1)
heat = heat.values
heat[:5]
array([[ 37.47959928, 126.95216562, 1. ],
[ 37.55926336, 126.94536912, 1. ],
[ 37.53571341, 127.09568067, 1. ],
[ 37.55210376, 126.92380859, 1. ],
[ 37.65510084, 127.05081759, 1. ]])
# HeatMap 그리기
from folium.plugins import HeatMap
m = folium.Map([lat, long], tiles='stamentoner', zoom_start=12)
for i in df_31.index:
sub_lat = df_31.loc[i, "위도"]
sub_long = df_31.loc[i, "경도"]
title = df_31.loc[i, "상호명"] + " - " + df_31.loc[i, "도로명주소"]
icon_color = "purple"
if df_31.loc[i, "브랜드명"] == "던킨도너츠":
icon_color = "pink"
folium.CircleMarker(
[sub_lat,sub_long ],
radius=3,
color=icon_color,
popup=f'<i>{title}</i>',
tooltip=title).add_to(m)
HeatMap(heat).add_to(m)
m.save('Heatmap.html')
m
'Data Analysis > python' 카테고리의 다른 글
[python] 100 pandas puzzles (0) | 2023.01.27 |
---|---|
[python] jupyter notebook에서 생성한 folium map 티스토리로 불러오기 (2) | 2023.01.26 |
[python] 소상공인시장진흥공단 상가업소정보로 프랜차이즈 입점분석 (1) (0) | 2023.01.25 |
[python] 데이터 전처리 ② (0) | 2023.01.14 |
[python] 데이터 전처리 ① : 변수 추출 (0) | 2023.01.12 |
댓글