본문 바로가기
프로그램/SKT FLY AI

SKT FLY AI : 2일차 - 끄적이는 글(1) - Crawling, Seaborn, folium

by hsloth 2023. 6. 27.

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')
  • 필요한 데이터 추출
    • print(title.get_text())

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