007. 데이터 취업 스쿨 스터디 노트_7주차_EDA, 웹크롤링, 파이썬 프로그래밍_2

Julia-jh·2024년 5월 25일
0

7주차

수강한 분량

EDA, 웹크롤링, 파이썬 프로그래밍의 일부분인 웹데이터, 유가분석을 정리했다.

각 강의별 학습한 핵심 내용 정리

웹 데이터 분석

cd DS_study/ds_study/WebData
conda activate ds_study
code .

ctrl + shfit + P

Beautiful Soup

  • tag로 이루어진 문서를 해석하는 python 라이브러리
  • from ba4 import BeautifulSoup
    - open()
    - 파일명과 함께 읽기(r) / 쓰기(w) 속성 지정
    - page = open("파일주소.html", 'r').read()
    - html.parser
    - Beutiful Soup의 html을 읽는 엔진 중 하나
    - soup = BeautifulSoup(page, "html.parser')
    - 들여쓰기가 잘 안되어있고, 읽기 불편함
    - prettify()
    - html 출력, 들여쓰기를 이쁘게 만들어 주는 기능
    - print(soup.prettify())

html 기초

    1. test_first.html 파일 활용하여 실습 진행
  • html 언어
    - 브라우저를 통해 예쁜 화면을 제공함
    - tag로 이루어져 있음
    - html
    - 웹 페이지를 표현
    - head
    - 눈에 보이지 않지만 문서에 필요한 헤더 정보 보관
    - body
    - 눈에 보이는 정보를 보관
    - div
    -
    - p
    - 문단
    - class
    - 구분 속성
    - id
    - 구분 속성
    - a
    -
    - href
    - 주소창
    - target
    - _blink
    - 새창
    - b
    - 굵게
    - i
    - 기울여서
  • 특정 태그가 보고 싶을 때
    - soup.body
    - soup['body']
    - soup.find('p')
    - 1개만 찾아줌
    - soup.find_all('p')
    - 지정된 태그 모두를 찾아 리스트 형태로 반환
    - 조건을 좁히는 방법으로 class, id를 태그와 함께 추가할 수 있다
    - soup.find_all(class_='클래스명')
    - soup.find_all({'class' : '클래스명'})
    - 특정 클래스를 찾는 방법
    - soup.find_all(id_='아이디명')
    - 특정 id로 찾는 방법
    - 담아져 있는 내용 출력
    - soup.find('p').text
    - 출력문자가 나옴
    - 공백을 지우기 위해 끝에 .strip()을 붙이면 됨
    - soup.find('p').string
    - soup.find_all('p').get_test()
    - p로 쌓여있는 실제 출력 글자 가져오는 함수
    - soup.find_all('a')[0].get('href')
    - a태그의 첫 번째 요소의 주소값을 가져오기
  • a 태그
    - 링크
    - <a href = "주소" id = "아이디값">출력글자</a>
    - soup.find_all('a').['href'].string
    - a 태그의 href 속성의 글자를 가져오는 방법
    - 출력 글자가 나옴

크롬 개발자 도구

  • 웹데이터 검출하고 싶은데 html을 잘 모를 때 활용하는 도구
  • 크롬 설정 > 도구 더보기 > 개발자 도구
    - 필요 데이터 부분 선택하면, 어느 부분인지 태그가 보임
    - <span class='value>를 기억해야 한다
  • 웹 주소에 접근할 때 필요한 라이브러리
    - from urllib.request import urlopen
    - urlopen('url주소')를 beautifulsoup으로 해석하기
    - ulropen('url주소').status
    - 응답 상황을 알 수 있다, http 상태코드 반환
    - 200
    - 정상
  • 프롬프트에서 특정 라이브러리 잘 인스톨되었는지 확인
    - pip list | findstr 라이브러리명
  • requests 라이브러리 깔았는데 임포트되지 않아 오류 내용을 보니 chardet이 없다고 해서 깔고 마저 하니 되었다.
  • requests 라이브러리와 urllib.requests.Request는 비슷한 역할을 한다
    - requests.get()
    - requests.post()
  • 무언가를 찾는 함수
    - find 와 비슷한 것 select one
    - find_all 와 비슷한 것 select
    - select, select one 의 문법
    - ~~.select("#아이디명 > li")
    - class면 . 을 활용
    - id 면 # 을 활용
    - 만약 띄어쓰기가 존재하면 속성이 여러 개, .으로 이어주기
    - 상, 하위 이동이 간결함

위키백과 문서 정보 가져오기

  • 한글로만 이루어진 페이지, 여명의 눈동자 위키백과 웹페이지 활용
  • 한글로 되어있는 웹페이지 주소는 옮길 경우 문자의 나열이 바뀐다.
import urllib
from urllib.request import urlopen, Request

html = 'http://ko.wikipedia.org/wiki/{search_words}'
req = Request(html.format(search_words = urllib.parse.quote('여명의_눈동자'))) # 글자를 URL로 인코딩

response = urlopen(req)

soup = BeautifulSoup(response, 'html.parser')

soup.find_all('ul')[15],text.strip().replace('\xa0', '').replace('\n', '')
# 바꾸고 싶은 문자를 찾아 replace함수에 넣고
# 찾고 싶은 부분의 순서를 찾아 15 자리에 넣는다.

list 데이터형

  • 리스트 변수를 선언할 때 생긴 메모리를 가리키는 주소가 복사됨
  • 반복문, 조건문에 적용하는 것이 편함
  • 리스트 내부에 리스트를 가질 수 있다
  • isinstance(변수명, list)
    - 자료형이 list인지 확인 가능

시카고 맛집 분석

시카고 맛집 메인페이지 분석

from bs4 import BeautifulSoup

from urllib.request import Request, urlopen

# 메인페이지와 서브페이지 분석을 따로 해야할 수 있기 때문에 주소를 두 개로 분리
url_base = 'https://www.chicagomag.com'
url_sub = '/Chicago-Magazine/November-2012/Best-Sandwiches-Chicago/'
url = url_base + url_sub

# http 403은 서버에서 유저가 문제가 있다고 하는 것
# 
req = Request(url, headers = {'User-Agent': 'Chrome'})
html = urlopen(req).read()
soup = BeautifulSoup(html, 'html.parser')

soup.prettify()

soup.find_all('div', _class = 'sammy'), len(soup.find_all('div', class_ = 'sammy')) # 갯수확인
# select로도 가능
soup.select(".sammy"), len(soup.select(".sammy"))

# 전체 코드 긁어오기 위한 샘플 코드 테스트 중...
tmp_one = soup.find_all('div', 'sammy')[0]
type(tmp_one)
# 위 값이 bs4.element.Tag 이면 bs4 요소이므로 bs4 함수를 적용할 수 있다

tmp_one.find(class_ = 'sammyRank').get_text()
tmp_one.find('div', {'class' : 'sammyRank'}).get_text()
tmp_one.select_one('.sammylisiting').text()
tmp_one.find("a")['href']
tmp_one.select_one("a").get('href')
  • 크롬 개발자 도구 내 network 탭을 살펴보면 요청과 그에 상응하는 응답이 기록된다
    - Request Headers 토글을 열어보면 user-agent 정보가 있다. 그곳에 나온 정보를 활용하는게 정석이나, 간략하게 Chrome 정도로 사용해도 좋다.
    - req.status 를 보면 200은 응답을 제대로 받았다, 403번은 별로인 상태
  • fake-useragent 라이브러리
    - from fake_useragent import UserAgent
    - UserAgent().ie
    - user-agent에 들어갈 값을 랜덤으로 만들어준다
  • type(찾은 요소) = bs4.element.Tag 이면, find 명령을 또 활용할 수 있다는 의미
  • 연결되는 홈페이지 주소가 상대경로이기 때문에, 주소를 상위 페이지와 하위 페이지로 구분해 분석하는 것이 용이하다
  • re 모듈
import re

# \n 혹은 \r\n이 보이면 분리해라
re.split(()'\n|\r\n'), 문자열)
from urllib.parse import urljoin

url_base = 'https://www.chicagomag.com'

rank = []
main_menu = []
cafe_name []
url_add = []

list_soup = soup.find_all('div', 'sammy')

for item in list_soup:
	rank.append(item.find(class_= 'sammyRank').get_text())
	tmp_string = item.find(class_= 'sammyListing').get_text()
	main_menu.append(re.split(('\n|\r\n'), tmp_string)[0])
	cafe_menu.append(re.split(('\n|\r\n'), tmp_string)[1])
	url_add.append(urljoin(url_base, item.find('a')['href']))
	# 두 번째 인자(주소)가 절대 주소라면 그냥 사용하고, 상대 주소라면 첫 번째 인자(주소)를 붙여서 사용하라

# 확인용
len(rank), len(main_manu), len(cafe_name), len(url_add)
rank[:5], ...

# 데이터 정리

data = {
	"Rank": rank,
	"Menu": main_menu,
	"Cafe": cafe_name,
	"URL": url_add
}

df = pd.DataFrame(data)

df = pd.Dataframe(data, columns = ['Rank', 'Cafe', 'Menu', 'URL])
df.to_csv("주소/이름.csv", sep = ",", encoding = 'utf-8')

시카고 맛집 하위 페이지 분석

  • Regular Expession_기초
    - .x
    - 임의의 한 문자를 표현
    - x+
    - x가 1번 이상 반복
    - x?
    - x가 존재하거나 존재하지 않는다
    - x*
    - x가 0번 이상 반복
    - x|y
    - x또는 y를 찾는다
from bs4 import BeautifulSoup
from urllib.request import urlopen

import pandas as pd

df = pd.read_csv('주소/이.csv', index_col = 0)

df['URL'][0]

req = Request(df["URL"][0], headers = {'User-Agent': 'Chrome'})
html = urlopen(req).read()

soup_tmp = BeautifulSoup(html, 'html.parser')

print(soup_tmp.find('p', 'addy'))
# 가격과 주소가 하나의 태그에 들어있다...!

price_tmp = soup_tmp.find('p', 'addy').get_text()

price_tmp = re.split(".,", price_tmp)[0]

# 끝에 .group()을 해주어야 값만 나온다
tmp = re.search("\$\d+\.(\d+)?", price_tmp).group()
# $가 반드시 있어야 하고, 숫자가 여러 개 있을 수 있고, .이 반드시 와야 하고, (숫자 여러개)의 것이 있을 수도 있고, 없을 수도 있다.

# 가격과 띄어쓰기 포함한 것의 길이 다음은 주소가 나타남
price_tmp[len(tmp) + 2:]
price = []
address = []

# 코드 작동 유무 확인 위해 세 번만 돌리기
for n in df.index[:3]:
	# html = urlopen(df['URL'][n])
	
	req = request(df['URL'][n], headers = {"User-Agent": "Mozilla/5.0"})
	html = urlopen(req).read()
	
	soup_tmp = BeautifulSoup(html, 'lxml')
	
	gettings = soup_tml.find('p', 'addy').get_text()
	
	price_tmp = re.split('.,', gettings)[0]
	tmp = re.search("\$\d+\.(\d+)?", price_tmp).group()
	
	price.append(tmp)
	address.append(price_tmp[len(tmp) + 2 :])
	
	print(n)
  • python스러운 문법
    - list를 고대로 사용하기
    - 여러 컬럼을 for문 안에서 사용하기 어려움
    - iterrows() 함수를 활용
for idx, row in df.iterrows():
	print(row['URL'])
  • TQDM
    - 라이브러리
    - 코드 실행 중에 프로그래스 바가 보여짐
    - 오류 없이 제대로 모두 적용되었는지 확인하는데 활용하는 것
from tqdm import tqdm
price = []
address = []

# 코드 작동 유무 확인 위해 세 번만 돌리기
for idx, row in tqdm(df.index[:3].iterrows()):
	# html = urlopen(df['URL'][n])
	
	req = request(row['URL'], headers = {"User-Agent": "Mozilla/5.0"})
	html = urlopen(req).read()
	# 홈페이지 수정중에 html parser로 불가능할 수 있음
	# conda 환경 사용 중에 lxml 환경이 없는 경우가 있다. 깔아주면 됨
	soup_tmp = BeautifulSoup(html, 'lxml')
	
	gettings = soup_tml.find('p', 'addy').get_text()
	
	price_tmp = re.split('.,', gettings)[0]
	tmp = re.search("\$\d+\.(\d+)?", price_tmp).group()
	
	price.append(tmp)
	address.append(price_tmp[len(tmp) + 2 :])
	
	print(n)
df['Price'] = price
df['Address'] = address

# price, address를 위해 link 데이터가 필요했던 것이므로 최종적으로는 삭제
df = df.loc[:, ['Rank', 'Cafe', 'Menu', 'Price', 'Address']]
df.set_index('Rank', inplace = True)

df.to_csv('', sep = ',', encoding = 'utf-8')

pd.read_csv('', index_col = 0)

시카고 맛집 데이터 지도 시각화

import folium
import pandas as pd
import googlemaps
import numpy as np
from tqdm import tqdm

# 주소 체크
df_ pd.read_csv('', index_col = 0)

gmaps_key = "geocoding api key geocoding api key"
gmaps = googlemaps.Client(key = gmaps_key)

lat = []
lng = []

for idx, row in tqdm(df.iterrows()):
	if not row["Address"] == "Multiple location":
		target_name = row["Address"] + ", " + "Chicago"
		gmaps_output = gmaps.geocode(target_name)
		location_output = gmaps_output[0].get('geometry')
		lat.append(location_output["location"]["lat"])
		lng.append(location_output["location"]["lng"])
	
	else:
		lat.append(np.nan)
		lng.append(np.nan)

df["lat"] = lat
df["lng"] = lng

df.head()

mapping = folium.Map(location = [41.8781136, -87.6297982], zoom_start = 11)

mapping

for idx, row in df.iterrows():
	if not row["Address"] == "Multiple location":
		folium.Marker([row["lat"],
		row["lng"]],
		popup = row["Cafe"],
		tooltip = row["Menu"],
		icon = folium.Icon(
			Icon = "coffee",
			prefix = "fa"
			)
		).add_to(mapping)

mapping

유가 분석

selenium

설치

  • 최근 버전의 셀레니움은 크롬드라이버를 다운로드 받으실 필요가 없게 바뀌었습니다! 크롬드라이버는 받지 마시고, 코드 작성시driver = webdriver.Chrome()
  • Beautiful Soup으로만 해결할 수 없는 것
    - 접근할 웹 주소를 알 수 없을 때
    - 자바스크립트를 사용하는 웹페이지
    - 웹 브라우저로 접근하지 않으면 안될 때
  • 웹 브라우저를 원격 조작하는 도구
  • 자동으로 URL을 열고 클릭 등이 가능
  • 스크롤, 문자의 입력, 화면 캡처 등
  • Python 모듈 설치, 크롬드라이버 설치
from selenium import webdriver

# 더이상 드라이버를 다운받지 않아도 됨
driver = webdriver.Chrome()

# 적은 주소의 새 창 키기
driver.get("https://www.naver.com")

# 꺼짐
driver.quit()

기초

from selenium import webdriver
from selenium import By

# 더이상 드라이버를 다운받지 않아도 됨
driver = webdriver.Chrome()

# 적은 주소의 새 창 키기
driver.get("https://www.pinkwink.kr/")

# 스크롤 가능한 높이 가져오기
last_height = driver.execute_script("return document.body.scrollHeight")
last_height

# 화면 스크롤 하단 이동
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);"))

# Xpath 카피해온 곳 까지 스크롤
from selenium.webdriver import ActionChains

some_tag = driver.find_element(By.XPATH, '//*[@id="paging"]/ul')

action = ActionChains(driver)
action.move_to_element(some_tag).perform()

# id로 찾아 입력 창에 글자 넣기
some_tag = driver.find_element(By.ID, 'gsc-i-idl')
some_tag.send_keys('data science')

# 버튼 클릭하는 코드 실행
xpath = '''//*[@id="___gcse_0"]/div/form/table/tbody/tr/td2/buttion'''
some_tag = driiver.find_element(By.XPATH, xpath).clink()

# 현재 화면 html 코드가져오기
from bs4 import BeutifulSoup

req = driver.page_source
soup = BeautifulSoup(req, 'html.parser')

result = soup.find_all('div', 'gsc-webResult gsc-result')
result[0]
기본 동작
  • get() 함수
    - 접근하고 싶은 주소 지정
  • execute_script('')
    - 자바스크립트 코드를 실행
  • 화면 페이지를 지정히는 지점의 xpath를 찾기
    - Copy > Copy Xpath
  • 보이는 화면에 내가 원하는 데이터가 있어야 에러가 안남
    - 한 화면에 많은 정보가 담겨있는 것이 좋음
  • 화면 최대 크기 설정
    - driver.maximize_window()
  • 화면 최소 크기 설정
    - driver.minimize_window()
  • 화면 크기 설정
    - driver.set_window_size(600, 600)
  • 새로 고침
    - driver.refresh()
  • 뒤로가기
    - driver.back()
  • 앞으로가기
    - driver.forward()
  • 요소 찾기
    - from selenium.webdriver.common.by import By
    - driver.find_element(by=BY.NAME, value="태그값")
  • 클릭
    - driver.find_element(BY.CSS_SELECTOR, 'css값 복사해오기')
  • CSS
    - #
    - id
    - >
    - 하위
    - .~~~
    - class 이름
    - (n)
    - n번째 요소
  • 새로운 탭 생성
    - driver.execute_script('window.open("주소")')
    - 공란이면 about:blank 창이 뜸
  • 탭 이동
    - driver.switch_to.window(driver.window_handles[1])
    - n번째 창으로 이동
  • 탭 닫기
    - driver.close()
    - 드라이버가 가리키고 있는 것이 이미 닫혀있을 경우 에러
  • 전체 종료
    - driver.quit()
화면 스크롤 & 검색어 입력
  • 스크롤 가능한 높이(길이)
    - driver.execte_script('return document.body.scrollHeight')
  • 화면 스크롤 하단 이동
    - driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
  • 현재 보이는 화면 스크린샷 저장
    - driver.save_screenshot('./파일이름.확장자')
    - ./
    - 현재 위치
    - 저장위치/파일이름.확장자
  • 화면 스크롤 상단 이동
    - driver.execute_script('window.scrollTo(0, 0);')
  • 특정 태그 지점까지 스크롤 이동
from selenium.webdriver import ActionChains

some_tag = driver.find_element(By.CSS_SELEECTOR, '태그 이름')
action = ActionChans(driver)
action.move_to_element(some_tag).perform()
검색어 입력(1)
  • XPATH
    - //
    - 최상위
    - *
    - 자손 태그
    - 내 아래에 있는 모든 자손
    - /
    - 자식 태그
    - 내 바로 아래 있는 자식
    - div[n]
    - div 태그 중에서 n번째 태그
    - Xpath를 감싸는 것은 작은 따옴표로 하는 것이 내부의 큰 따옴표와 겹치지 않아 에러 방지에 좋다
from selenium import webdriver
from selenium.webdriver.common.by import By

# 더이상 드라이버를 다운받지 않아도 됨
driver = webdriver.Chrome()

# 적은 주소의 새 창 키기
driver.get("https://www.naver.com/")

# css_selector
# 검색어 입력
keyword = driver.find_element(By.CSS_SELECTOR, '#query')
keyword.send_keys('파이썬')

# 버튼 클릭
search_btn = driver.find_element(by.CSS_SELECTOR, '#search_btn')
search_btn.click()

# 검색어 지우기
keyword = driver.find_element(By.CSS_SELECTOR, '#query')
keyword.clear()
keyword.send_keys('딥러닝')

# XPATH
# 검색어 입력
keyword = driver.find_element(By.XPATH, '//*[@id="query"]')
keyword.send_keys('파이썬')

# 버튼 클릭
search_btn = driver.find_element(by.XPATH, '//*[@id="search_btn"]')
search_btn.click()

# 검색어 지우기
keyword = driver.find_element(By.XPATH, '//*[@id="query"]')
keyword.clear()
keyword.send_keys('딥러닝')
검색어 입력(2)
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.chrome()
driver.get('http://pinkwink.kr')

# 돋보기 버튼 선택
driver.find_element(BY.CSS_SELECTOR, '#header > div.search').click()
# 처음부터 선택이 잘 안되고, 직접 눌러야 search on이라는 이름으로 바뀜

# 아래의 내용으로 진행
from selenium.webdriver import ActionChains

search_tag = driver.find_element(By.CSS_SELECTOR, '.search')
action = ActionChains(driver)
action.click(search_tag)
action.perform()

# 검색어 입력
driver.find_element(BY.CSS_SELECTOR, '#header > div.search > input[type=text]').send_keys('딥러닝')

# 검색 버튼 클릭
driver.find_element(BY.CSS_SELECTOR, '#header > div.search.on > button').click()
Selenium과 BeautifulSoup 함께 사용하기
# 현재 화면 html 코드 가져오기
driver.page_source

from bs4 import Beautifulopti

req = driver.page_source
soup = BeautifulSoup(req, 'html.parser')

soup.select('.post-item')

contents = soup.select('.post-item')
len(contents)

주유소 가격

데이터 얻어오기

  • 대한민국 주유 가격을 알아보는 사이트: https://www.opinet.co.kr/user/main/mainView.dos
    - 싼 주유소 찾기 > 지역별
    - https://www.opinet.co.kr/searRgSelect.do
    - 사이트 구조 확인하기
    - 지역 정보를 선택
    - 웹페이지 주소도 안 바뀌고, HTML 소스에서 원하는 정보를 얻기도 쉽지 않다
    - 검색한 내용의 하단에 엑셀 저장이 바로 존재함
    - 목표 데이터
    - 브랜드
    - 가격
    - 셀프 주요 여부
    - 위치

  • 문제 발생
    1. 해당 URL로 한 번에 접근이 안 됨
    2. 메인 페이지로 접속이 되고, 팝업창이 하나 나옴
    3. 창 전환 시 에러가 남
    - time.sleep(n) 으로 n초가 쉬어가면 selenium이 잘 따라감

from selenium impor webdriver

url = 'http://www.opinet.co.kr/searRgSlect.do'
driver = webdriver.Chrome()
driver.get(url)
time.sleep(3)

# 팝업창 뜸
# 팝업창으로 전환 후 닫아줌
driver.switch_to_window(driver.window_handles[-1])
driver.close()
time.sleep(3)

# 메인 화면 창으로 전환
driver.switch_to_window(driver.window_handles[-1])
driver.get(url)

# 새로 정리하기
import time

def main_get():
from selenium impor webdriver

# 페이지 접근
url = 'http://www.opinet.co.kr/searRgSlect.do'
driver = webdriver.Chrome()
driver.get(url)
time.sleep(3)

# 팝업창으로 전환
driver.switch_to_window(driver.window_handles[-1])
# 팝업창 닫기
driver.close()
time.sleep(3)

# 메인 화면 창으로 전환
driver.switch_to_window(driver.window_handles[-1])
# 접근 URL 다시 요청
driver.get(url)

main_get()
  • 시도, 구 정보 가져오기
# 지역: 시/도
sido_list_raw = driver.find_element(BY.ID, 'SIDO_MNO')
sido_list_raw

sido_list = sido_list_raw.find_elements(BY.TAG_NAME, 'option')
sido_list

sido_names = [option.get_attribute('value') for option in sido_list]
sido_names.remove("")
sido_names

sido_list_raw.send_keys(sido_names[1])

gu_list_raw = driver.find_element(BY.ID, 'SIGUNGU_NM0')
gu_list = gu_list_raw.find_elements(BY.TAG_NAME, 'option')

gu_names = [opion.get_attribute('value') for option in gu_list]
gu_names.remove("")
gu_names

element_get_excel = driver.find_element(BY.ID, 'glopopd_excel').click()

import time
from tqdom import tqdm_notebook

for gu in tqdm_notebook(gu_names):
	element = driver.find_element(BY.ID , 'SIGUNGU_NM0')
	element.send_keys(gu)
	time.sleep(2)

	element_get_excel = driver.find_element(BY.ID, 'glopopd_excel').click()
	time.sleep(1)

driver.close()

주유소 가격 정보 정리하기

  • 파일 목록을 한 번에 가져오기
    - glob 라이브러리를 활용
  • DF 형식이 동일하고 연달아 붙이기만 하면 될 때
    - pd.concat()
import pandas as pd
from glob import glob

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

tmp_raw = []

for file_name in stations_files:
	tmp = pd.read_excel(file_name, hedaer = 2)
	tmp_raw.append(tmp)
	
station_raw = pd.concat(tmp_raw)
station_raw.info()
station_raw.head()

stations = pd.DataFrame(
	{
		"상호": station_raw["상호"],
		"주소": station_raw["주소"],
		"가격": station_raw["휘발유"],
		"셀프": station_raw["셀프여부"],
		"상표": station_raw["상표"],
	}
)
stations['구'] = [eachAddress.split()[1] for eachAddress in stations['주소']]

len(stations['구'].unique())

stations[stations['구'] == '서울특별시', '구'] = '성동구'
stations[stations['구'] == '특별시', '구'] = '도봉구'

len(stations['구'].unique())

stations['가격'] = stations['가격'].astype('float')
# 가격이 없어서 -로 표시된 부분 버리기
stations = stations[stations['가격'] != '-']
stations['가격'] = stations['가격'].astype('float')

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

stations.head()

주유가격 시각화

  • Box Plot
    - Median 중심으로 아래 위 상자가 각각 전체 데이터의 25%씩 총 50%를 가짐
    - 상자 전체 길이, IQR(Inter Quatile Range)
    - IQR의 1.5배를 벗어나면 점으로 별도 표기, outlier
    - 가운데 십자 표시, Mean
import matplotlib.pyplot as plt
import seaborn as sns

# pandas의 boxplot
stations.boxplot(column = '가격', by = '셀프', figsize = (12, 8));

# seaborn의 boxplot
plt.figure(figsize = (12, 8))
sns.boxplot(x = '셀프', y = '가격', data = stations, palette = 'Set3')
plt.grid()
plt.show()

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


# 지도 시각화
import json
immport folium
import warnings

Warnings.simplefilter(acction = 'ignore', category = futrueWarning)

stations.sort_values(by = '가격', asceding = False).head(10)
stations.sort_values(by = '가격', asceding = True).head(10)

import numpy as np

gu_data = pd.pivot_table(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],
	zom_start = 10.5,
	tiles = 'Stamen Toner')

my_map.choropleth(
	geo_data = geo_str,
	data = gu_data,
	columns = [gu_data.index, '가격'],
	fill_color = 'PuRd',
	key_on = 'feature.id'
)
my_map

느낀점

사용하던 노트북에 문제가 있어서 새 노트북을 사는데 시간이 좀 걸렸다. 나는 빨리 구매했지만, 그 분이 삼 주에 걸쳐서 우리 집으로 오심.. 그 과정에서 마음이 지치고, 와중에 웹데이터를 이용하는 내용도 어렵고. 언제나 생각하지만 교육 자체보다는 외적인 것에 더 흔들릴 수 있음을 잊지말아야겠다. 교육은 쉬지 않고 진행되는데, 내가 이걸 끝까지 해내는 것이 목표라면 내가 좀 잘 못하는 순간도 괜찮다 생각하고 넘길 줄 알아야겠다.

이 글은 제로베이스 데이터 취업 스쿨의 강의 자료 일부를 발췌하여 작성되었습니다.

profile
데이터 직무로 먹고 살고 싶은 사람

0개의 댓글