Crawling
- Web상에 존재하는 Contents를 수집하는 작업 (프로그래밍으로 자동화 가능)
- Selenium등 브라우저를 프로그래밍으로 조작해서, 필요한 데이터만 추출하는 기법
- BeautifulSoup 라이브러리 활용
- HTML의 태그를 파싱해서 필요한 데이터만 추출하는 함수를 제공하는 라이브러리
- BeautifulSoup 라이브러리 페이지
- 설치 방법
- pip install bs4
- import requests
- import bs4 import BeautifulSoup
BeautifulSoup
- requests 라이브러리를 활용한 HTML페이지 요청
- res객체에 html데이터가 저장되고, res.content로 데이터를 추출할 수 있다.
res = requests.get('http://주소')
- html 페이지 파싱 BeautifulSoup(html데이터, 파싱방법)
- `soup = BeautifulSoup(res.content, 'html.parser')
- 필요한 데이터 검색
- title = soup.find('title')
- 필요한 데이터 추출
BeautifulSoup 사전작업
!pip install requests
!pip install BeautifulSoup4
# 나눔 한글 폰트 설치
!sudo apt-get install -y fonts-nanum
!sudo fc-cache -fv
!rm ~./cache/matplotlib -rf
로또번호 확인하기
import requests
from bs4 import BeautifulSoup as bs
res = requests.get('https://dhlottery.co.kr/common.do?method=main')
soup = bs(res.content, 'html.parser')
result = soup.select('.ball_645')
data = []
for num in result:
data.append(int(num.text))
data
import pandas as pd
df = pd.Series(data)
df
### 데이터타입 확인
df.dtypes
### 데이터 시각화
import matplotlib.pyplot as plt
plt.rc('font', family='NanumBarunGothic')
plt.bar(['1번','2번','3번','4번','5번','6번','보너스'], data)
plt.show()
plt.savefig('lotto.png')
뉴스 수집하기
!pip install newspaper3k
import newspaper as news
link = ‘https://n.news.naver.com/mnews/hotissue/article/031/0000754250?type=series&cid=1087780'
article = news.Article(link, language='ko')
article.download()
article.parse()
print(article.text)
import requests
from bs4 import BeautifulSoup as bs
url = 'https://n.news.naver.com/mnews/hotissue/article/031/0000754250?type=series&cid=1087780'
res = requests.get(url, headers={'User-Agent':'Mozilla/5.0'})
res.content
웹브라우저에서 User-Agent?
- 웹 사이트에 들어갔을 때 HTTP 패킷을 열어보면 HTTP 패킷을 열어보면 HTTP Header에 항상 존재하는 헤더 값으로 User-Agent란 값으로 어떤 사람이 어떤 디바이스로 방문했는지 알 수 있음
- User-Agent는 사용자를 대신해서 일을 수행하는 소프트웨어 에이전트를 의미함
- request.get(url, headers={'User-Agent':'Mozilla/5.0'})
import os
import requests
from bs4 import BeautifulSoup
url = "https://comic.naver.com/webtoon/detail.nhn?titleId=747961&no=2"
html = requests.get(url).text
soup = BeautifulSoup(html, 'html.parser')
if not(os.path.isdir("./webtoon")):
os.makedirs(os.path.join("./webtoon"))
i = 1
for tag in soup.select('.wt_viewer img'):
img_url = tag['src']
save_img = "./webtoon/" + str(i).zfill(3) + img_url[-4:]
i += 1
print(save_img + " : OK")
headers = {'Referer': img_url}
img_data = requests.get(img_url, headers=headers).content
with open(save_img, 'wb') as f:
f.write(img_data)
Seaborn
- matplotlib 기반의 시각화 라이브러리
- 그래픽을 그리기 위한 고급 인터페이스 제공
figure-level과 axes-level
- figure-level : matplotlib와 별개로 seaborn의 figure를 만들어서 plotting
- figure-level 함수를 사용한 경우에는 facetgrid(seaborn의 figure)를 통해 레이아웃을 변경
- axes-level : axes 수준에서 plotting을 하는 함수이며, plt.figure()와 같은 함수로 레이아웃을 변경.
- 교수님 왈 : matplot보다 조~금 더 고급지다. 배우고나면, matplot보다 많이 사용하게 될 것!
import seaborn as sns
막대 그래프
- countplot()
- 범주형 데이터를 입력하면, 항목별로 개수를 세어서 막대그래프를 그려준다.
- pandas의 value_counts()와 비교하면 이해하기 쉽다.
- 맵플롯립의 bar()함수와 다른 점을 이해한다.
- barplot()
- y축으로 설정된 값의 평균을 막대의 높이로 표현한다.
- estimator 인수 : y축에 표시될 값을 계산하는 방법을 지정한다.
import pandas as pd
tips = pd.read_csv('./datasets/tips.csv')
tips.head(10)
### countplot()
import matplotlib.pyplot as plt
import seaborn as sns
sns.countplot(data=tips, x='day')
plt.show()
### pd.values_counts() 함수
x = tips['day'].value_counts()
### hue인수 : 성별별 tip의 평균 계산
sns.countplot(data=tips, x='day', hue='smoker')
plt.show()
### 데이터 준비
import pandas as pd
tips = pd.read_csv('./tips.csv')
tips.head(10)
### barplot()
import matplotlib.pyplot as plt
import seaborn as sns
sns.barplot(x = tips['sex'], y = tips['tip'])
plt.show()
### 평균값 : 성별별 tip평균
x= tips.groupby(by='sex')['tip'].mean()
print(x)
### estimator 인수 : 막대 그래프의 y축의 값을 계산하는 함수를 설정
sns.barplot(x = tips['sex'], y = tips['tip'], estimator=np.median)
plt.show()
히스토그램
- histplot()함수로 그래프를 그린다.
- displot() 함수도 히스토그램을 그리지만, 좀 더 많은 기능을 제공한다.
import matplotlib.pyplot as plt
import seaborn as sns
sns.histplot(x='total_bill', data=tips)
plt.show()
### bins 파라미터 : 구간의 개수를 지정
sns.histplot(data=tips, x='total_bill', bins=10)
plt.show()
### kde : 데이터 분포를 확인할 수 있는 라인
sns.histplot(data=tips, x='total_bill', bins=10, kde=True)
plt.show()
### dedisplot()
sns.displot(data=tips, x='total_bill', kde=True)
plt.show()
### cols 파라미터 : col 인수를 사용해서 여러 개의 그래프를 동시에 그리는 기능
sns.displot(data=tips, x='total_bill', col=‘time')
plt.show()
박스플롯
import matplotlib.pyplot as plt
import seaborn as sns
sns.boxplot(x = tips[‘total_bill'])
plt.show()
### 그룹별 박스플롯 : x축에 범주형 데이터를 설정하면, 그룹별로 박스플롯
sns.boxplot(x=‘smoker', y='total_bill', data=tips)
plt.show()
바이올린 플롯
- 박스플롯과 비슷한 정보를 표현하지만, 그래프의 폭 넓이로 데이터의 분포를 확인할 수 있다.
- hue 인수 : 데이터를 그룹별로 묶어서 표시한다.
import matplotlib.pyplot as plt
import seaborn as sns
sns.violinplot(x='smoker', y='total_bill', data=tips)
plt.show()
### hue 인수 : 성별로 그룹을 묶어서 표시
sns.violinplot(x='smoker', y='total_bill', hue='sex', data=tips)
plt.show()
히트맵
- 2차원 행렬 데이터를 색상과 숫자로 표현
- camp인수 : 컬러맵을 설정
### 컬럼 선택 : 수치 데이터를 가지는 컬럼 추출
df = tips.select_dtypes(['number'])
df.head()
### 상관계수
x = df.corr()
x
### heatmap() : 상관계수의 2차원 데이터를 히트맵으로 표시
sns.heatmap(x, annot = True, cmap = 'viridis') # annot : 값 표기 유무
plt.show()
### 결측치 표시 : 결측치를 표시하는 특별한 형태의 그래프를 표현한다. 타이타닉 데이터 세트를 사용
titanic = pd.read_csv("./titanic.csv")
df = titanic[['Survived', 'Pclass', 'Sex', 'Age','Ticket', 'Fare', 'Cabin']]
sns.heatmap(df.isnull(), yticklabels=False, cbar=False, cmap='viridis')
패싯그리드(FacetGrid)
- cos인수와 row인수를 설정하여 하나의 그림에 그룹별로 여러 개의 그래프를 그린 것
### 산점도
g = sns.FacetGrid(tips, col="time", row="sex")
g.map(sns.scatterplot, "total_bill", "tip")
plt.show()
### 히스토그램
g = sns.FacetGrid(tips, col="time", row="sex")
g.map_dataframe(sns.histplot, x="total_bill")
plt.show()
페어플롯(Pair Plot)
- 그리드(grid) 형태로 각 컬럼의 조합에 대해 히스토그램과 분포도를 그린다.
- 수치형 컬럼에 대해서만 그래프를 그린다.
iris = sns.load_dataset('iris')
iris.head()
sns.set_style('white')
sns.pairplot(iris, hue='species')
plt.show()
데이터 시각화 - Seaborn
import seaborn as sns
titanic = sns.load_dataset('titanic')
print(titanic.head())
print('\n')
print(titanic.info())
- 회귀선이 있는 산점도 : regplot() 함수는 서로 다른 2개의 연속 변수 사이의 산점도를 그리고 선형회귀분석에 의한 회귀선을 함께 나타낸다. Fit_reg=False 옵션을 설정하면 회귀선을 안 보이게 할 수 있다.
import matplotlib.pyplot as plt
import seaborn as sns
### Seaborn 제공 데이터셋 가져오기
titanic=sns.load_dataset('titanic')
### 스타일테마설정(5가지:darkgrid,whitegrid,dark,white,ticks)
sns.set_style('darkgrid')
### 그래프객체생성(figure에2개의서브플롯을생성)
fig=plt.figure(figsize=(15,5))
ax1=fig.add_subplot(1,2,1)
ax2=fig.add_subplot(1,2,2)
### 그래프그리기-선형회귀선표시(fit_reg=True)
sns.regplot(x='age', # x축변수
y='fare', # y축변수
data=titanic, # 데이터
ax=ax1) # axe객체-1번째그래프
### 그래프그리기-선형회귀선미표시(fit_reg=False)
sns.regplot(x='age', # x축변수
y='fare', # y축변수
data=titanic, # 데이터
ax=ax2, fit_reg=False) # axe객체-2번째그래프 # 회귀선미표시
plt.show()
히스토그램/커널 밀도 그래프
- 하나의 변수(단변수) 데이터의 분포를 확인할 때 displot() 함수를 이용
- 기본 값으로 히스토그램과 커널 밀도 함수를 그래프로 출력
- 커널밀도함수는 그래프와 x축사이의 면적이 1이 되도록 그리는 밀도분포 함수
import matplotlib.pyplot as plt
import seaborn as sns
# seaborn 제공 데이터셋 가져오기
titanic = sns.load_dataset('titanic')
# 스타일 테마 설정 (darkgrid, whitegrid, dark, white, ticks)
sns.set_style('darkgrid')
# 그래프 객체 생성 (figure에 3개의 서브 플롯을 생성)
fig = plt.figure(figsize=(15,5))
ax1 = fig.add_subplot(1,3,1)
ax2 = fig.add_subplot(1,3,2)
ax3 = fig.add_subplot(1,3,3)
# displot
sns.distplot(titanic['fare'], ax=ax1) # ax는 어느 서브플롯에 그릴건지 지정하는 것
# kdeplot
sns.histplot(x='fare', data=titanic, ax=ax2)
# 차트제목 표시
ax1.set_title('titanic fare - displot')
ax2.set_title('titanic fare - kedplot')
ax3.set_title('titanic fare = histplot')
plt.show()
Folium
!pip install folium
import pandas as pd
import folium
seoul_univ = pd.read_excel('./서울지역대학교위치.xlsx')
seoul_univ
seoul_map = folium.Map(location=[37.4921263, 126.9261711], zoom_start=12, tiles='Stamen Terrain')
for name, lat, lng in zip(seoul_univ.index, seoul_univ.위도, seoul_univ.경도):
folium.CircleMarker([lat, lng]
, color='brown',
radius=10,
fill=True,
fill_color='coral',
fill_opacity=0.7,
popup=name).add_to(seoul_map)
#seoul_map.save('./seoul.html')
seoul_map
df = pd.read_csv('./서울교통공사_1_8호선 역사 좌표(위경도) 정보_20211231.csv', encoding='cp949')
seoul_map = folium.Map(location=[37.4921263, 126.9261711], tiles='Stamen Terrain',
zoom_state=12)
for name, lat, lng in zip(df.index, df.위도, df.경도):
folium.Marker([lat, lng], popup=name).add_to(seoul_map)
seoul_map