본문 바로가기

[입문] 데이터 사이언스? 그게 뭔가요?

파이썬으로 데이터 주무르기 4장 코드에 주석을 달았다는 내용의 제목

04. Self Oil Station price-Copy1

원작자 : PinkWink

주석 작성자 멘트 : 코드 호환성 문제 등으로 수정하여 작성한 부분이 있습니다.

4장 셀프 주유소는 정말 저렴할까

작성 : PinkWink

4-1 Selenium 사용하기

In [1]:
from selenium import webdriver
  • 현재 최신 크롬드라이버의 명령 중 일부가 다른 버전과 다른듯 합니다. 본 Github에서 배포하는 driver를 사용하시기 바랍니다.
In [2]:
from bs4 import BeautifulSoup

4-2 서울시 구별 주유소 가격 정보 얻기

In [9]:
import time
from selenium.webdriver.support.ui import Select

driver = webdriver.Chrome('../driver/chromedriver.exe')
driver.get("http://www.opinet.co.kr")
driver.get("http://www.opinet.co.kr/searRgSelect.do")
# 한 번에 searRgSelect.do 페이지로 넘어가지 않는 경우
# http://www.opinet.co.kr 에서 들어가게 설정하면 해결됨
In [ ]:
area = driver.find_element_by_xpath('//*[@id="SIDO_NM0"]')
area.send_keys('서울')

# Selenium WebDriverException: unknown error: call function result missing 'value' while calling sendkeys method
# chromedriver 와 chrome browser 간 버전 호환 차이에 의한 에러.
# 참조 : https://stackoverflow.com/questions/49219594/selenium-webdriverexception-unknown-error-call-function-result-missing-value/49219750
# chromedriver 가 예전 버전이고, 본인 컴퓨터의 크롬이 최신버전인 경우 종종 발생.
# 크롬 브라우저와 chromedriver 를 둘 다 최신버전으로 사용하면 사라짐.
  • Opinet은 사용자가 접속한 지역에 따라 지역을 잡아주는 기능이 있습니다.
  • 이 기능을 배려하지 않고 코드가 짜여졌습니다.
  • 원본은 이 기능이 구현되어 있지 않아, 아래 코드로 구현완료

  • 지역에 서울이라고 나타나지 않으면 크롬 드라이버에서 손으로 서울로 잡아주세요.
In [10]:
# page_source 를 가져와 beautifulsoup 으로 엘리먼트 찾는 것으로 해결
html = driver.page_source
bs1 = BeautifulSoup(html)
bs2 = bs1.find('select', id = 'SIGUNGU_NM0')
bs3 = bs2.find_all('option')
gu_names = list(map(lambda val : val.text, bs3))[1:]
# lambda val : val.text 는 bs3 리스트에 들어있는 것들을 .text 하여 텍스트만 가져오기 위함
# map() 은 bs3 리스트를 람다 함수에 매핑하기 위함
# list() 는 매핑 한 결과를 리스트로 담아두기 위함
# [1:] 는 리스트의 0 번째 인덱스가 시/군/구 라는 이름이기 때문에 이를 제외하기 위함.
gu_names
Out[10]:
['강진군',
 '고흥군',
 '곡성군',
 '광양시',
 '구례군',
 '나주시',
 '담양군',
 '목포시',
 '무안군',
 '보성군',
 '순천시',
 '신안군',
 '여수시',
 '영광군',
 '영암군',
 '완도군',
 '장성군',
 '장흥군',
 '진도군',
 '함평군',
 '해남군',
 '화순군']
In [11]:
element = driver.find_element_by_id("SIGUNGU_NM0")
element.send_keys(gu_names[0])
In [12]:
xpath = """//*[@id="searRgSelect"]"""
element_sel_gu = driver.find_element_by_xpath(xpath).click()
In [13]:
xpath = """//*[@id="glopopd_excel"]"""
element_get_excel = driver.find_element_by_xpath(xpath).click()
In [14]:
import time
from tqdm import tqdm_notebook

# tqdm_notebook은 진행 상태 바를 나타내기 위한 용도.
# for 문 iteration 수행시 마다 진행 상태가 표기됨.
# tqdm_notebook(gu_names)은 iteration 마다 yield로 gu_names 안의 정보를 반환하는 제너레이터이다.
# gu_names 변수는 지역구의 이름들이 들어있는 리스트이고
# 반복문 수행시 gu 라는 변수에 할당됨
for gu in tqdm_notebook(gu_names):
    element = driver.find_element_by_id("SIGUNGU_NM0")
    element.send_keys(gu)
    # 드롭다운 메뉴에서 구 이름을 선택한다.
    time.sleep(2)
    # time.sleep 이 있는 이유는 HTML 을 전부 불러오기 전에
    # 코드가 실행된다면 대상 element 를 찾을 수 없는 에러가 종종 발생하기 때문.
    
    xpath = """//*[@id="searRgSelect"]"""
    element_sel_gu = driver.find_element_by_xpath(xpath).click()
    
    time.sleep(1)
    
    xpath = """//*[@id="glopopd_excel"]"""
    element_get_excel = driver.find_element_by_xpath(xpath).click()
    # 해당 구의 모든 주유소 정보를 다운로드하는 링크를 클릭한다.
    
    time.sleep(1)

In [15]:
driver.close()

4-5. 구별 주유 가격에 대한 데이터의 정리

In [16]:
import pandas as pd
from glob import glob
In [19]:
glob('../data/지역_위치별(주유소)*xls')
# 작성자는 애플 os 로 한글을 작성하였는데, 자음과 모음이 분리되는 특색이 있다.
# 지운 후, 다시 지역_위치별(주유소) 로 대상 파일명을 바꿔준다.
# glob 모듈은 해당 경로에 위치한 파일/폴더를 리스트로 뽑아주는 기능이 있다.
# glob 에서 * 은 아무거나 좋다는 의미이고 모든 파일을 선택하고자 한다면 *.* 을 넣어준다.
# glob 에서 만약 확장자가 .csv 라는 파일만 전부 읽고자 한다면 *.csv 를 넣어주면 된다.
# 지금같은 경우에는 (주유소) 와 xls 사이에 * 을 붙여 주었는데 중간에 아무거나 와도 상관없는 조건이다.
Out[19]:
['../data\\지역_위치별(주유소) (1).xls',
 '../data\\지역_위치별(주유소) (10).xls',
 '../data\\지역_위치별(주유소) (11).xls',
 '../data\\지역_위치별(주유소) (12).xls',
 '../data\\지역_위치별(주유소) (13).xls',
 '../data\\지역_위치별(주유소) (14).xls',
 '../data\\지역_위치별(주유소) (15).xls',
 '../data\\지역_위치별(주유소) (16).xls',
 '../data\\지역_위치별(주유소) (17).xls',
 '../data\\지역_위치별(주유소) (18).xls',
 '../data\\지역_위치별(주유소) (19).xls',
 '../data\\지역_위치별(주유소) (2).xls',
 '../data\\지역_위치별(주유소) (20).xls',
 '../data\\지역_위치별(주유소) (21).xls',
 '../data\\지역_위치별(주유소) (22).xls',
 '../data\\지역_위치별(주유소) (23).xls',
 '../data\\지역_위치별(주유소) (24).xls',
 '../data\\지역_위치별(주유소) (3).xls',
 '../data\\지역_위치별(주유소) (4).xls',
 '../data\\지역_위치별(주유소) (5).xls',
 '../data\\지역_위치별(주유소) (6).xls',
 '../data\\지역_위치별(주유소) (7).xls',
 '../data\\지역_위치별(주유소) (8).xls',
 '../data\\지역_위치별(주유소) (9).xls',
 '../data\\지역_위치별(주유소).xls']
In [21]:
stations_files = glob('../data/지역_위치별*xls')
# 그렇게 불러온 파일명을 리스트로 저장해 stations_files 변수에 할당한다.
stations_files
Out[21]:
['../data\\지역_위치별(주유소) (1).xls',
 '../data\\지역_위치별(주유소) (10).xls',
 '../data\\지역_위치별(주유소) (11).xls',
 '../data\\지역_위치별(주유소) (12).xls',
 '../data\\지역_위치별(주유소) (13).xls',
 '../data\\지역_위치별(주유소) (14).xls',
 '../data\\지역_위치별(주유소) (15).xls',
 '../data\\지역_위치별(주유소) (16).xls',
 '../data\\지역_위치별(주유소) (17).xls',
 '../data\\지역_위치별(주유소) (18).xls',
 '../data\\지역_위치별(주유소) (19).xls',
 '../data\\지역_위치별(주유소) (2).xls',
 '../data\\지역_위치별(주유소) (20).xls',
 '../data\\지역_위치별(주유소) (21).xls',
 '../data\\지역_위치별(주유소) (22).xls',
 '../data\\지역_위치별(주유소) (23).xls',
 '../data\\지역_위치별(주유소) (24).xls',
 '../data\\지역_위치별(주유소) (3).xls',
 '../data\\지역_위치별(주유소) (4).xls',
 '../data\\지역_위치별(주유소) (5).xls',
 '../data\\지역_위치별(주유소) (6).xls',
 '../data\\지역_위치별(주유소) (7).xls',
 '../data\\지역_위치별(주유소) (8).xls',
 '../data\\지역_위치별(주유소) (9).xls',
 '../data\\지역_위치별(주유소).xls']
In [49]:
tmp_raw = []
# 이 파일은 3번째 row 가 컬럼명이고 데이터는 4번째 row 부터 시작이기 때문에
# pd.read_excel 수행시 header=2 옵션을 준다.(3번째 row 는 인덱싱 기준 2 이므로)
for file_name in stations_files:
    tmp = pd.read_excel(file_name, header=2)
    tmp_raw.append(tmp)
    
# 이렇게 불러온 엑셀파일을 일괄 리스트로 넣어준 이후
# pd.concat 을 이용하여 열 단위로 붙여준다(컬럼이 같으므로 아래로 이어붙인다.)
station_raw = pd.concat(tmp_raw)
In [50]:
station_raw.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 537 entries, 0 to 45
Data columns (total 10 columns):
지역       537 non-null object
상호       537 non-null object
주소       537 non-null object
상표       537 non-null object
전화번호     537 non-null object
셀프여부     537 non-null object
고급휘발유    537 non-null object
휘발유      537 non-null object
경유       537 non-null object
실내등유     537 non-null object
dtypes: object(10)
memory usage: 46.1+ KB
In [51]:
station_raw.head()
Out[51]:
지역 상호 주소 상표 전화번호 셀프여부 고급휘발유 휘발유 경유 실내등유
0 서울특별시 오렌지주유소 서울 강동구 성안로 102 (성내동) SK에너지 02-484-6165 N - 1554 1354 997
1 서울특별시 구천면주유소 서울 강동구 구천면로 357 (암사동) 현대오일뱅크 02-441-0536 N - 1556 1355 -
2 서울특별시 GS칼텍스㈜직영 신월주유소 서울 강동구 양재대로 1323 (성내동) GS칼텍스 02-475-2600 N 1855 1559 1349 1000
3 서울특별시 광성주유소 서울 강동구 올림픽로 673 (천호동) S-OIL 02-470-5133 N - 1578 1388 1100
4 서울특별시 (주)소모에너지엔테크놀러지성내주유소 서울 강동구 올림픽로 578 (성내동) GS칼텍스 02-479-3838 Y - 1588 1388 -
In [52]:
# station_raw 에는 지역, 상호, 주소, 상표, 전화번호, 셀프여부, 고급휘발유, 휘발유, 경유, 실내등유가 컬럼으로 존재.
# 여기에서 상호, 주소, 휘발유, 셀프여부, 상표 정보만 잘라내어 stations 변수에 넣고자 한다.
stations = pd.DataFrame({'Oil_store':station_raw['상호'], 
                                       '주소':station_raw['주소'],
                                       '가격':station_raw['휘발유'],
                                       '셀프':station_raw['셀프여부'],
                                       '상표':station_raw['상표']  })
# 위 방법보다 더 쉬운 길이 있다.
# 컬럼 이름만 변경하지 않는다면 2 줄짜리 코드로 쉽게 구현 가능함.
'''
interested = ['상호', '주소', '휘발유', '셀프여부', '상표']
new_col_name = ['Oil_store', '주소', '가격', '셀프', '상표']
stations = station_raw[interested]
stations.columns = new_col_name
'''
stations.head()
Out[52]:
Oil_store 주소 가격 셀프 상표
0 오렌지주유소 서울 강동구 성안로 102 (성내동) 1554 N SK에너지
1 구천면주유소 서울 강동구 구천면로 357 (암사동) 1556 N 현대오일뱅크
2 GS칼텍스㈜직영 신월주유소 서울 강동구 양재대로 1323 (성내동) 1559 N GS칼텍스
3 광성주유소 서울 강동구 올림픽로 673 (천호동) 1578 N S-OIL
4 (주)소모에너지엔테크놀러지성내주유소 서울 강동구 올림픽로 578 (성내동) 1588 Y GS칼텍스
In [53]:
# 리스트 컴프리헨션이 사용되었다.
# .split 으로 띄어쓰기 기준 문자열을 잘라내고 [1] 인덱싱을 이용하여 1번째 인덱스인 구 정보만 추출
stations['구'] = [eachAddress.split()[1] for eachAddress in stations['주소']]
stations.head()
Out[53]:
Oil_store 주소 가격 셀프 상표
0 오렌지주유소 서울 강동구 성안로 102 (성내동) 1554 N SK에너지 강동구
1 구천면주유소 서울 강동구 구천면로 357 (암사동) 1556 N 현대오일뱅크 강동구
2 GS칼텍스㈜직영 신월주유소 서울 강동구 양재대로 1323 (성내동) 1559 N GS칼텍스 강동구
3 광성주유소 서울 강동구 올림픽로 673 (천호동) 1578 N S-OIL 강동구
4 (주)소모에너지엔테크놀러지성내주유소 서울 강동구 올림픽로 578 (성내동) 1588 Y GS칼텍스 강동구
In [54]:
# 구를 선별하기 위해 띄어쓰기 기반으로 일괄 처리하였으나 예외가 있어 서울특별시, 특별시와 같은 정보도 들어가버렸다.
stations['구'].unique()
Out[54]:
array(['강동구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '서울특별시', '성북구',
       '송파구', '양천구', '영등포구', '강북구', '용산구', '은평구', '종로구', '중구', '중랑구',
       '강서구', '관악구', '광진구', '구로구', '금천구', '노원구', '도봉구', '특별시', '강남구'],
      dtype=object)
In [55]:
# 구 컬럼의 값이 서울특별시인 경우를 보아 성동구임을 확인하였다.
stations[stations['구']=='서울특별시']
Out[55]:
Oil_store 주소 가격 셀프 상표
12 SK네트웍스(주)효진주유소 1 서울특별시 성동구 동일로 129 (성수동2가) 1654 N SK에너지 서울특별시
In [56]:
# 구 컬럼의 값이 서울특별시인 경우를 성동구로 직접 전처리 해 집어넣었다.
stations.loc[stations['구']=='서울특별시', '구'] = '성동구'
stations['구'].unique()
Out[56]:
array(['강동구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '성북구', '송파구',
       '양천구', '영등포구', '강북구', '용산구', '은평구', '종로구', '중구', '중랑구', '강서구',
       '관악구', '광진구', '구로구', '금천구', '노원구', '도봉구', '특별시', '강남구'],
      dtype=object)
In [57]:
# 구 컬럼의 값이 특별시인 경우를 보아 도봉구임을 확인하였다.
stations[stations['구']=='특별시']
Out[57]:
Oil_store 주소 가격 셀프 상표
10 서현주유소 서울 특별시 도봉구 방학로 142 (방학동) 1524 Y S-OIL 특별시
In [58]:
# 구 컬럼의 값이 특별시인 경우를 도봉구로 직접 전처리 해 집어넣었다.
stations.loc[stations['구']=='특별시', '구'] = '도봉구'
stations['구'].unique()
Out[58]:
array(['강동구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '성북구', '송파구',
       '양천구', '영등포구', '강북구', '용산구', '은평구', '종로구', '중구', '중랑구', '강서구',
       '관악구', '광진구', '구로구', '금천구', '노원구', '도봉구', '강남구'], dtype=object)
In [59]:
# 가격이 나와있지 않은 경우를 제외하기 위해 가격을 - 로 하는 row 를 확인하였다.
stations[stations['가격']=='-']
Out[59]:
Oil_store 주소 가격 셀프 상표
18 명진석유(주)동서울주유소 서울특별시 강동구 천호대로 1456 (상일동) - Y GS칼텍스 강동구
33 하나주유소 서울특별시 영등포구 도림로 236 (신길동) - N S-OIL 영등포구
12 (주)에이앤이청담주유소 서울특별시 강북구 도봉로 155 (미아동) - Y SK에너지 강북구
13 송정주유소 서울특별시 강북구 인수봉로 185 (수유동) - N 자가상표 강북구
In [60]:
# 가격이 - 가 아닌 row 만 선별하여 stations 변수를 업데이트 하였다.
stations = stations[stations['가격'] != '-']
stations.head()
Out[60]:
Oil_store 주소 가격 셀프 상표
0 오렌지주유소 서울 강동구 성안로 102 (성내동) 1554 N SK에너지 강동구
1 구천면주유소 서울 강동구 구천면로 357 (암사동) 1556 N 현대오일뱅크 강동구
2 GS칼텍스㈜직영 신월주유소 서울 강동구 양재대로 1323 (성내동) 1559 N GS칼텍스 강동구
3 광성주유소 서울 강동구 올림픽로 673 (천호동) 1578 N S-OIL 강동구
4 (주)소모에너지엔테크놀러지성내주유소 서울 강동구 올림픽로 578 (성내동) 1588 Y GS칼텍스 강동구
In [34]:
# 가격이 현재 int 로 되어 있거나 mixed-type 일 수 있기 때문에 일괄 float 캐스팅하여 가격 컬럼을 업데이트하였다.
stations['가격'] = [float(value) for value in stations['가격']]
In [63]:
# 위에서 row를 지우는 작업을 하였기 때문에 index를 재설정하기 위한 코드 
stations.reset_index(inplace=True)
del stations['index']
In [36]:
stations.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 533 entries, 0 to 532
Data columns (total 6 columns):
Oil_store    533 non-null object
주소           533 non-null object
가격           533 non-null float64
셀프           533 non-null object
상표           533 non-null object
구            533 non-null object
dtypes: float64(1), object(5)
memory usage: 25.1+ KB
In [37]:
stations.head()
Out[37]:
Oil_store 주소 가격 셀프 상표
0 오렌지주유소 서울 강동구 성안로 102 (성내동) 1554.0 N SK에너지 강동구
1 구천면주유소 서울 강동구 구천면로 357 (암사동) 1556.0 N 현대오일뱅크 강동구
2 GS칼텍스㈜직영 신월주유소 서울 강동구 양재대로 1323 (성내동) 1559.0 N GS칼텍스 강동구
3 광성주유소 서울 강동구 올림픽로 673 (천호동) 1578.0 N S-OIL 강동구
4 (주)소모에너지엔테크놀러지성내주유소 서울 강동구 올림픽로 578 (성내동) 1588.0 Y GS칼텍스 강동구

4-4 셀프 주유소는 정말 저렴한지 boxplot으로 확인하기

In [38]:
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

import platform

path = "c:/Windows/Fonts/malgun.ttf"
from matplotlib import font_manager, rc
if platform.system() == 'Darwin':
    rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
    font_name = font_manager.FontProperties(fname=path).get_name()
    rc('font', family=font_name)
else:
    print('Unknown system... sorry~~~~') 
In [39]:
# 가격 컬럼에 대하여 셀프 여부에 따라 boxplot 을 그리는 코드
# 판다스에서 기본 지원되는 boxplot 메소드를 사용한다.
stations.boxplot(column='가격', by='셀프', figsize=(12,8));
In [40]:
# 위의 경우와는 다르게 이번에는 seaborn의 boxplot 메소드를 사용한다.
# seaborn 에서는 x, y, hue 를 사용하는데 hue 는 seaborn 에서만 있는 파라미터이다.
plt.figure(figsize=(12,8))
sns.boxplot(x="상표", y="가격", hue="셀프", data=stations, palette="Set3")
plt.show()
In [41]:
plt.figure(figsize=(12,8))
sns.boxplot(x="상표", y="가격", data=stations, palette="Set3")
sns.swarmplot(x="상표", y="가격", data=stations, color=".6")
plt.show()

4-5 서울시 구별 주유 가격 확인하기

In [42]:
import json
import folium
import googlemaps
import warnings
warnings.simplefilter(action = "ignore", category = FutureWarning)
In [43]:
# 서울 구별 휘발유값이 높은 주유소만 보기 위한 코드
stations.sort_values(by='가격', ascending=False).head(10)
Out[43]:
Oil_store 주소 가격 셀프 상표
325 서남주유소 서울 중구 통일로 30 (봉래동1가) 2132.0 N SK에너지 중구
324 장충주유소 서울 중구 장충단로 202 (장충동1가) 2130.0 N SK에너지 중구
124 양재주유소 서울 서초구 바우뫼로 178 (양재동) 2128.0 N SK에너지 서초구
532 뉴서울(강남) 서울 강남구 언주로 716 (논현동) 2120.0 N SK에너지 강남구
531 오천주유소 서울 강남구 봉은사로 503 (삼성동) 2107.0 N SK에너지 강남구
313 재동주유소 서울특별시 종로구 율곡로 58 (경운동) 2106.0 N SK에너지 종로구
285 청파주유소 서울특별시 용산구 청파로 311 (청파동1가) 2106.0 N SK에너지 용산구
284 갈월동주유소 서울특별시 용산구 한강대로 322 (갈월동) 2106.0 N SK에너지 용산구
283 강변주유소 서울특별시 용산구 원효로 9 (청암동) 2106.0 N SK에너지 용산구
323 통일주유소 서울 중구 동호로 296 (장충동2가) 2106.0 N SK에너지 중구
In [44]:
# 서울 구별 휘발유값이 낮은 주유소만 보기 위한 코드
stations.sort_values(by='가격', ascending=True).head(10)
Out[44]:
Oil_store 주소 가격 셀프 상표
83 만남의광장주유소 서울 서초구 양재대로12길 73-71 (원지동) 1490.0 N 알뜰(ex) 서초구
344 강서오곡셀프주유소 서울특별시 강서구 벌말로 254 (오곡동) 1497.0 Y SK에너지 강서구
451 태릉솔밭주유소 서울특별시 노원구 노원로 49 (공릉동) 1497.0 Y S-OIL 노원구
258 수유동주유소 서울특별시 강북구 도봉로 395 (수유동) 1498.0 Y GS칼텍스 강북구
227 (주)강서오일 서울 영등포구 도신로 151 (도림동) 1499.0 N 현대오일뱅크 영등포구
225 도림주유소 서울 영등포구 도림로 343 (도림동) 1499.0 Y 알뜰주유소 영등포구
226 (주)대청에너지 대청주유소 서울 영등포구 가마산로 328 (대림동) 1499.0 N GS칼텍스 영등포구
415 풀페이주유소 서울특별시 구로구 경인로 41 (온수동) 1499.0 N SK에너지 구로구
326 신일셀프주유소 서울 중랑구 상봉로 58 (망우동) 1499.0 Y SK에너지 중랑구
40 서경주유소 서울 동작구 대림로 46 (신대방동) 1499.0 N 현대오일뱅크 동작구
In [45]:
# pivot_table 을 이용해 구를 기준으로 인덱스를 잡고 가격을 np.mean 이용하여 평균값으로 계산.
import numpy as np

gu_data = pd.pivot_table(stations, index=["구"], values=["가격"], 
                         aggfunc=np.mean)
gu_data.head()
Out[45]:
가격
강남구 1791.000000
강동구 1656.722222
강북구 1534.333333
강서구 1576.428571
관악구 1603.055556
In [46]:
geo_path = '../data/02. skorea_municipalities_geo_simple.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))
# 한국의 geo_json 지역정보를 불러오기 위한 코드.

map = folium.Map(location=[37.5502, 126.982], zoom_start=10.5, 
                 tiles='Stamen Toner')

# folium data 항목에 gu_data 를 넣어주면 gu_data의 index인 구 이름을
# folium 내부에서 key 로 인식하여 해당 지역의 영역에 gu_data의 값을 전달한다.
# fill_color 에 설정한 옵션에 따라 gu_data로부터 전달받은 값이 반영되어 색깔로 보여지게 된다.
map.choropleth(geo_data = geo_str,
               data = gu_data,
               columns=[gu_data.index, '가격'],
               fill_color='PuRd', #PuRd, YlGnBu
               key_on='feature.id')
map
Out[46]:
In [ ]: