유가 데이터 분석

eunbi kim·2024년 3월 19일
0
post-custom-banner
  1. 데이터 확보하기
  2. 주유소 정보 정리하기
  3. 주유 가격 정보 시각화

Q. 셀프 주유소의 가격, 정말 저렴한가???

Opinet에서 지역별 주유소의 가격 정보를 확인할 수 있다.
https://www.opinet.co.kr/searRgSelect.do

이 사이트에서 서울시 구마다의 주유소 가격, 브랜드, 셀프 주유 여부 등의 데이터를 가져와
다양한 시각화 작업을 하는 프로젝트이다.

1. 데이터 확보하기

지역을 선택하면 그 지역에 있는 모든 주유소의 정보들을 담은 엑셀 파일을 다운받을 수 있다.
"지역 선택->엑셀 파일 다운로드 버튼 클릭" 과정을 자동화할 것이다.

from selenium import webdriver
from selenium.webdriver.common.by import By

url = 'https://www.opinet.co.kr/searRgSelect.do'
driver = webdriver.Chrome()
driver.get(url)

태그를 분석해보면
#SIDO_NM0 (지역-시) 태그 안에, option이라는 태그로 값들(서울, 부산, 대구..)이 있는 것 같다.

sido_list_raw = driver.find_element(By.CSS_SELECTOR, "#SIDO_NM0")

-> 18

18개의 지역 정보를 가져왔다.

get_attribute로 옵션 태그 안에 value 속성값을 가져온다.

sido_list[1].get_attribute("value")

-> '서울특별시'

서울특별시 안의 구는, #SIGUNGU_NM0 에서 구를 선택하고 option으로 25개의 구를 선택할 수 있다.

for문을 사용해서 25개의 구 정보를 수집할 수 있다.

gu_list_raw = driver.find_element(By.CSS_SELECTOR, "#SIGUNGU_NM0")
gu_list = driver.find_elements(By.CSS_SELECTOR, "#SIGUNGU_NM0 > option")

gu_names = [option.get_attribute("value") for option in gu_list]
gu_names = gu_names[1:]
gu_names

gu_names라는 리스트에 25개의 구들이 잘 들어왔고,

이제 25개의 구를 리스트에서 반복문으로 받아와 각각 검색->엑셀 다운받기 버튼 클릭하는 과정이다.

tqdm_notebook으로 진행이 잘 되고 있는지 눈으로 확인할 수 있다.

import time
from tqdm import tqdm_notebook

for gu in tqdm_notebook(gu_names):
    element = driver.find_element(By.CSS_SELECTOR, "#SIGUNGU_NM0")
    element.send_keys(gu)
    time.sleep(3)
    
    element_get_excel = driver.find_element(By.CSS_SELECTOR, "#glopopd_excel").click()
    time.sleep(3)

이런 식으로 25개 파일을 다 받아왔다.


2. 주유소 정보 정리하기

파일 목록 한 번에 가져오기 - glob에서 파일 경로를 지정!

import pandas as pd
from glob import glob

glob("../data/지역_*.xls")

파일명 저장

stations_files = glob("../data/지역_*.xls")

컬럼명이 이상했기에 header=2로 가져왔음...

이제 모든 구의 주유소 정보를 이어 붙일 수 있다.
빈 리스트를 만들어준 후 for문을 이용해서 경로를 다 가져와 하나씩 다 읽어들이고, 빈 리스트에 더해준다.

tmp_raw = []

for file_name in stations_files:
    tmp = pd.read_excel(file_name, header=2)
    tmp_raw.append(tmp)  

형식이 동일한 데이터프레임을 연달아 붙이기만 하면 될 때는 concat함수를 사용한다! (추가, 추가, 추가..하는 방식)

stations_raw = pd.concat(tmp_raw)
stations_raw

가져오고 싶은 컬럼만 딕셔너리 형태로 추려 데이터프레임으로 만들었다.

stations = pd.DataFrame({
    "상호": stations_raw["상호"],
    "주소": stations_raw["주소"],
    "가격": stations_raw["휘발유"],
    "셀프": stations_raw["셀프여부"],
    "상표": stations_raw["상표"]
})

stations.tail()

구 별로 검색하기 위해서는,
주소를 보고 어느 구에 해당되는지를 분류해주는 컬럼이 필요하다.

주소는 '서울특별시 강동구 천호대로 1246' 이런 형식으로 생겼다.

-> for문으로 주소를 띄어쓰기 기준으로 split해주고, 그 값들의 두번째 값(index 1)만 추려오면 된다.

for eachAddress in stations["주소"]:
    eachAddress.split()[1]

"구" 라는 컬럼을 만들어 for문으로 얻은 값들을 넣어주는 코드:

stations["구"] = [eachAddress.split()[1] for eachAddress in stations["주소"]]
stations

그리고
분석을 위해 가격 데이터타입을 object에서 float로 변환해야 한다.
-> ValueError -> 가격 정보가 빈 곳이 있었고 bar(-)형태로 채워져 있어서였음
-> 가격 정보가 있는 주유소 데이터만 사용하자!

stations = stations[stations["가격"] != "-"]

나머지 가격 정보들의 데이터타입을 바꿔주었다.

stations["가격"] = stations["가격"].astype("float")

인덱스 재정렬, 명목상인 index컬럼 없애기...

stations.reset_index(inplace=True)
del stations["index"]

이렇게 필요한 정보를 담은 데이터프레임을 완성했다.


3. 주유 가격 정보 시각화

import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib import font_manager, rc

plt.rcParams["axes.unicode_minus"] = False
font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
rc('font', family=font_name)
%matplotlib inline

시각화를 위한 모듈과 한글 대응 코드 등등을 불러오고,

다양한 방면으로 시각화를 해보자.

셀프 여부(y/n)에 따른 가격 비교:

plt.figure(figsize=(12, 8))
sns.boxplot(x="셀프", y="가격", data=stations, palette="Set3")
sns.set_style("darkgrid")
plt.show()

-> ㅇㅇ 셀프 주유소가 싼편이다

상표별 가격 boxplot - 셀프 구분을 hue로:

import matplotlib.pyplot as plt
plt.rcParams['font.family'] ='Malgun Gothic'
plt.rcParams['axes.unicode_minus'] =False

plt.figure(figsize=(12, 8))
sns.boxplot(x="상표", y="가격", hue="셀프", data=stations, palette="Set3")
plt.show()

지역별 정보를 가져왔으니 표로 살펴보자!

import json
import folium
import warnings
warnings.simplefilter(action="ignore", category=FutureWarning)

가장 비싼 주유소 10개:

stations.sort_values(by="가격", ascending=False).head(10)

진짜 비싸네...ㄷㄷ

가장 싼 주유소 10개:

stations.sort_values(by="가격", ascending=True).head(10)

구마다의 평균 가격을 보고 싶어 -> 피벗테이블!!

import numpy as np

gu_data = pd.pivot_table(data=stations, index="구", values="가격", aggfunc=np.mean)
gu_data.head()

지도 시각화도 할 수 있다.

저번시간에 다운받은 우리나라 좌표값 데이터를 가져와서, 서울시 지역별 평균 유가 시각화를 하자

geo_path = "../data/02. skorea_municipalities_geo_simple.json"
geo_str = json.load(open(geo_path, encoding="utf-8"))

my_map = folium.Map(
    location=[37.5502, 126.982],
    zoom_start=11
)

folium.Choropleth(
    geo_data=geo_str,
    data=gu_data,
    columns=[gu_data.index, "가격"], 
    key_on="feature.id",
    fill_color="PuRd",
    fill_opacity=0.7,
    line_opacity=0.2
).add_to(my_map)

my_map

용산구, 중구, 종로구, 강남구가 비싸고,
서울 바깥쪽으로 갈수록 가격이 낮아지는 경향인 것 같다.

post-custom-banner

0개의 댓글