중학교 수학 시간에 일차함수를 배운 기억이 있을 거에요. y = ax + b (a는 직선의 기울기) 형태로 나타내는 일차함수를 x, y축에 그래프로 나타내면 일차적인 선형 관계를 나타내는 직선으로 표시됩니다.

일차함수 관계식을 알고 있다면, x값에 어떤 수를 대입하여 y값이 얼마인지 계산할 수 있습니다. 다시 말하면, 우리가 x값과 관계식을 알고 있는 상태에서 y값을 예측하는 것이 가능하다는 뜻입니다.

그렇다면, 머신러닝은 무엇일까요? 머신러닝은 기계(machine)가 학습(learning)한다는 뜻입니다. 컴퓨터는 일차함수 관계식을 알지 못하는 상태에서, x값과 대응되는 y값을 학습해서 두 변수 x, y 사이의 관계식을 찾습니다. x 변수의 값과 일차함수 관계식의 계수 a, b 위치에 다양한 후보값들을 대입하여 y 변수의 예측값을 계산합니다. y 예측값과 원래 y값의 오차가 가장 작을 때의 a, b 값을 찾아서, 일차함수 관계식인 y = ax + b를 완성합니다.

이처럼, 설명변수(x)와 목표변수(y)에 해당하는 데이터셋이 주어졌을 때 두 변수 사이의 관계식을 찾는 과정을 머신러닝에서 훈련(training)이라고 말합니다. 머신러닝을 이용하여 관계식을 찾고 나면, 새로운 데이터(x)에 대해서 목표값(y)을 찾을 수 있는데, 이 과정을 예측(prediction)이라고 합니다.

한편, 딥러닝은 머신러닝에 속하는 하위개념입니다. 딥러닝은 인간의 신경망을 본뜬 알고리즘을 사용하여 관계식을 찾는 머신러닝 방법이라고 생각하면 됩니다. 따라서, 학습하고 예측하는 과정은 머신러닝과 차이가 없습니다.

일차함수 관계식을 찾는 간단한 실습 예제를 통해서 머신러닝 개념을 이해합니다. 먼저, 데이터셋을 준비하는 과정부터 살펴 봅니다.

 

 

1. 먼저, x값 데이터를 만들겠습니다. -10부터 9까지 20개의 정수 배열을 만들고, 변수 x에 저장합니다.

 

import 명령을 사용하여 nupmy 라이브러리를 불러옵니다. "as np"는 numpy를 np라는 약칭으로 사용한다는 뜻입니다. arange 함수는 (범위 시작, 범위 끝, 숫자 간격) 순으로 인수를 입력받는데, 예제에서는 -10부터 10 사이의 숫자를 1 간격으로 생성합니다. 범위의 끝인 10은 제외되는 점에 유의합니다.

>>> import numpy as np
>>> x = np.arange(-10, 10, 1)
>>> x

array([-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

 

2. x값과 일차함수 관계를 갖는 y값 데이터를 만듭니다. (일차함수 y = 2x - 1 사용)

x는 원소 20개를 갖는 배열입니다. 배열에 연산기호(* , -)를 적용하면, 20개 원소 각각에 대하여 연산이 적용됩니다. x 배열의 원소에 2를 곱하고 1을 뺀 결과값의 배열을 순서대로 변수 y에 저장합니다.

>>> y = 2*x - 1
>>> y

array([-21, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9, 11, 13, 15, 17])

 

3. x 배열, y 배열 값을 가지고 그래프를 그립니다.

matplotlib 라이브러리의 pyplot 모듈을 불러오는데, "as plt"는 plt라는 약칭을 사용한다는 뜻입니다. plot 메소드에 x, y 값을 순서대로 입력합니다.

>>> import matplotlib.pyplot as plt
>>> plt.plot(x, y)

 

4. 순서대로 정렬되어 있는 x 배열 원소값들의 순서를 무작위로 바꾸는 작업을 합니다.

x.shape[0]은 x 배열의 크기(원소의 개수)를 나타내는데, 원소 개수는 20개입니다. 대신, len 함수를 사용하여 len(x)로 입력해도 같은 결과를 보입니다.

numpy의 arange 함수에 자연수(양의 정수)를 입력하면, 숫자 0부터 입력된 자연수 갯수만큼의 숫자 배열이 만들어집니다. 예제에서 x.shape[0]은 20이므로, idx 변수에는 0, 1, 2, ..., 19까지 20개의 정수 배열이 저장됩니다.

numpy의 random 모듈은 무작위 추출 작업을 하는데 이용합니다. shuffle 함수를 이용하여 배열의 인덱스(주소)를 나타내는 idx 배열의 순서를 랜덤하게 섞어 줍니다. idx 배열 자체의 순서가 변동되는 점에 유의합니다.

>>> print("x 배열의 원소 개수: ", x.shape[0])
>>> idx = np.arange(x.shape[0])
>>> print("기존 인덱스:", idx)
>>> np.random.shuffle(idx)
>>> print("섞인 인덱스:", idx)

x 배열의 원소 개수: 20
기존 인덱스: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
섞인 인덱스: [11 18 15 9 7 16 8 19 3 4 12 6 2 1 13 0 10 14 17 5]

x[idx]와 같이 x 배열에 새로운 인덱스 배열을 입력하면 x 배열의 순서가 변경됩니다. y 배열에도 같은 인덱스 배열을 입력하면 x 값에 매칭되는 y 값이 순서대로 위치를 찾게 됩니다.

>>> x = x[idx]
>>> print ("x: ", x)
>>> y = y[idx]
>>> print ("y: ", y)

x: [ -1 5 2 -9 -2 4 -6 9 3 -10 -3 -4 6 1 -5 7 8 -7 -8 0]
y: [ -3 9 3 -19 -5 7 -13 17 5 -21 -7 -9 11 1 -11 13 15 -15 -17 -1]

 

5. 1차원 형태의 x 배열을 2차원 형태로 변환합니다.

일반적으로, 머신러닝 알고리즘에서 x 변수의 데이터 값 배열은 가로 방향으로 긴 형태가 아니라 세로 방향으로 긴 형태로 만듭니다. 따라서, x 배열의 형태를 다음과 같이 세로 형태로 변환합니다. 2차원 배열에서 세로 방향의 각 열은 하나의 설명변수(x)에 속하는 데이터 값들의 모임이라고 볼 수 있습니다.

20개의 원소를 갖는 x 배열에 reshape 메소드를 적용하여 배열의 모양을 바꿀 수 있습니다. (-1, 1)에서 왼쪽의 숫자는 행의 개수를 나타내고, 오른쪽의 숫자는 열의 개수를 나타냅니다. 따라서, 열의 개수는 1개가 됩니다. 다만, -1은 정해진 개수를 나타내지 않고, 원래 배열의 개수인 20과 남은 차원(여기서는 열의 개수)인 1로 정해진다는 뜻입니다. 20개의 원소를 1개의 열에 넣으려면 행의 개수는 20개가 되어야 합니다. 결론적으로, 20개의 행과 1개의 열을 가진 2차원 구조로 변환됩니다.

>>> x_new = x.reshape(-1,1)
>>> x_new

array([[ -1],
[ 5],
[ 2],
[ -9],
[ -2],
[ 4],
[ -6],
[ 9],
[ 3],
[-10],
[ -3],
[ -4],
[ 6],
[ 1],
[ -5],
[ 7],
[ 8],
[ -7],
[ -8],
[ 0]])

이것으로 머신러닝(딥러닝) 알고리즘에 입력할 수 있는 데이터셋의 형태를 만들었습니다. 다음 게시글에서는 이 데이터셋을 이용하여 실제로 머신러닝 라이브러리를 통해 훈련-예측하는 과정을 살펴보겠습니다.

구글 코랩(Google Colaboratory)이란?

파이썬 딥러닝을 공부하려면 비싼 그래픽카드(GPU)가 탑재된 딥러닝 전용 PC와 여러가지 소프트웨어 등 높은 수준의 개발 환경이 필요합니다.

 

구글에서 제공하는 클라우드 환경에서 파이썬 프로그래밍을 하는 방법을 소개합니다. 파이썬을 데스크톱이나 노트북에 따로 설치하지 않아도 되고, 초보자들이 어려워하는 복잡한 소프트웨어 환경설정도 필요하지 않습니다.

구글 코랩(Google Colaboratory)는 웹브라우저에서 바로 실행 가능한 무료 코드 에디터입니다. 파이썬 사용자들에게 널리 알려진 Jupyter 노트북 환경을 기반으로 만들었고, 사용이 편리한 장점이 있습니다.

1. 구글 코랩은 설치가 필요 없습니다.

2. 인터넷이 접속되는 컴퓨터만 있으면 사용 가능합니다.

3. 무료입니다.

4. 파이썬, 머신러닝, 딥러닝에 필요한 툴이 지원됩니다. 

물론 단점(?)도 있습니다. 사용 시간이 12시간이 넘으면 세션이 종료됩니다. 그리고, 지원되는 메모리(RAM)과 저장 장치 디스크 용량에 제한이 있습니다. 하지만, 캐글이나 국내에서 진행되는 대부분의 데이터 분석 경진대회에서도 충분한 성능을 발휘하므로 걱정하실 필요는 없어요.

 

 

구글 코랩 실행 방법

1. 웹브라우저를 열고 구글 계정에 로그인합니다. 구글 검색창에 "Colab"이라고 검색어를 입력하면, 다음과 같이 Google Colab 페이지 링크가 보입니다.

 

2. Google Colab 링크를 클릭하면 코랩 사이트에 접속하고, 메인 페이지가 다음과 같이 나타납니다.

 

3. "Colabotory에 오신 것을 환영합니다" 링크를 클릭하면 코랩 소개 페이지가 실행됩니다. 대신에 오른쪽 아래 "새 노트"를 클릭하면 새로운 노트 파일이 만들어집니다.

 

이제 구글 코랩을 실행하는데 성공했습니다. 파이썬 주피터(Jupyter) 노트북 환경에 익숙한 분들은 따로 설명드리지 않아도 사용하는데 어려움이 없으실 거예요. 파이썬이 처음인 분들을 위한 설명은 다음 편에 계속 이어가겠습니다. 

위키피디아 한국어 페이지에서 "평화의 소녀상"을 검색하면 다음과 같은 화면이 나타난다. 해당 URL을 requests 모듈을 이용하여 접속하고, html 소스를 가져온다. 

 

위키피디아 검색 결과 페이지

 

BeautifulSoup 클래스의 find( ) 메소드에 HTML 요소의 태그 이름(‘img’)을 전달하면, 해당 태그 부분을 찾아서 객체로 return 해준다. find( ) 명령은 HTML 문서에서 가장 처음으로 만나는 태그를 한 개 찾는다. 앞의 위키피디아 화면에서 가장 먼저 나오는 사진(img 태그)은 "주한 일본 대사관 앞 평화비"라는 설명이 붙어 있는 사진이다. 

 

"평화의 소녀상, 속초"라는 설명이 있는 사진을 나타내는 ‘img’ 태그를 선택하려면, attrs 매개변수에 해당 태그에만 해당하는 고유의 속성을 추가해야 한다. 개발자 도구를 이용하여 해당 태그를 확인할 수 있는데, alt 속성 값으로 이미지 소스 URL 값을 갖는다. 이 속성을 find( ) 메소드의 attrs 매개변수에 입력하는 방식으로, 특정 태그를 선택할 수 있다. 

 

import requests
from bs4 import BeautifulSoup

url = "https://ko.wikipedia.org/wiki/%ED%8F%89%ED%99%94%EC%9D%98_%EC%86%8C%EB%85%80%EC%83%81"
resp = requests.get(url)
html_src = resp.text

soup = BeautifulSoup(html_src, 'html.parser')
                    
photo_first = soup.find(name='img')
print(photo_first)
print("\n")

photo_sockcho = soup.find(name='img', attrs={'src':'//upload.wikimedia.org/wikipedia/commons/thumb/1/16/%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg/220px-%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg'})
print(photo_sockcho)

 

 

실행 결과는 다음과 같다. 두 개의 img 태그를 찾아서 내용을 확인할 수 있다. 이처럼, find( ) 메소드는 특정한 태그를 하나만 찾는 경우에 사용되고, 메모리 관리 측면이나 실행 시간에서 유리하다는 장점을 갖는다. 

 

<img alt="" class="thumbimage" data-file-height="3000" data-file-width="4000" decoding="async" height="173" src="//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG/230px-Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG/345px-Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/3/36/Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG/460px-Japanese_Embassy_in_Seoul_and_watched_from_behind_a_bronze_statue_of_comfort_women.JPG 2x" width="230"/>

 

 

<img alt="" class="thumbimage" data-file-height="2268" data-file-width="4032" decoding="async" height="124" src="//upload.wikimedia.org/wikipedia/commons/thumb/1/16/%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg/220px-%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg" srcset="//upload.wikimedia.org/wikipedia/commons/thumb/1/16/%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg/330px-%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg 1.5x, //upload.wikimedia.org/wikipedia/commons/thumb/1/16/%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg/440px-%ED%8F%89%ED%99%94%EC%9D%98%EC%86%8C%EB%85%80%EC%83%81%28Statute_of_Peace%29.jpg 2x" width="220"/>

 

앞서, requests 모듈을 사용하여 웹 페이지를 요청하고, 응답 객체의 text 속성을 통해 HTML 소스코드를 얻는 과정을 살펴보았다.

 

2019/08/01 - [웹 스크래핑 (Web Scraping)] - [5] 파이썬 웹 스크래핑 - requests 모듈, HTML 소스코드 확인

 

 

HTML 태그와 같이 요소별로 구분하여 HTML 문서를 해석하는 작업을 파싱이라고 부른다. HMTL 소스코드를 파싱(parsing)하고 원하는 정보를 추출하기 위해 BeautifulSoup 라이브러리를 사용한다. 파이썬 클래스로 정의되어 있고, 윈도 명령 프롬프트 또는 터미널 창에서 “pip install beautifulsoup4”를 입력하여 설치한다. 

 

BeautifulSoup 클래스는 매개변수로 전달받은 HTML 소스코드를 해석하여 BeautifulSoup 객체를 생성한다. 이 때, HTML을 파싱(해석)하는 적절한 구문 해석기(파서, parser)를 함께 입력해야 한다. 파서에는 "html.parser", "lxml" 등이 자주 사용된다. (주: XML 구문 해석을 위해서는 "xml" 파서를 따로 설치해서 사용한다.)

 

1) requests 모듈로 html 소스코드 얻기

import requests
from bs4 import BeautifulSoup

url = "https://en.wikipedia.org/wiki/Main_Page"
resp = requests.get(url)
print(resp)
print("\n")

html = resp.text
print(html[:300])
print("\n")

 

requests 모듈의 get( ) 함수의 요청에 웹 서버가 정상 응답하는 경우 코드 200의 값을 갖는다. 응답 객체의 text 속성을 html 변수에 저장하고 일부를 출력하면 html 소스코드를 확인할 수 있다. 

 

<Response [200]>

 

 

<!DOCTYPE html>

<html class="client-nojs" lang="en" dir="ltr">

<head>

<meta charset="UTF-8"/>

<title>Wikipedia, the free encyclopedia</title>

<script>document.documentElement.className=document.documentElement.className.replace(/(^|\s)client-nojs(\s|$)/,"$1client-js$2");RLCONF={"wgCanonicalNamespace

 

 

 

2) html 소스코드를 BeautifulSoup 클래스 객체로 변환하기

soup = BeautifulSoup(html, 'html.parser')
print(type(soup))
print("\n")                 
print(soup.head)
print("\n")
print(soup.body)
print("\n")

 

다음에는 html 문자열을 BeautifulSoup 클래스 객체로 변환한다. type( ) 함수로 soup 객체를 확인하면, BeautifulSoup 클래스 객체라는 것을 알 수 있다. 여기서 soup 객체의 head 부분을 따로 지정할 수 있는데, 다음 실행결과와 같이 <head> 태그 부분이 출력된다. 마찬가지로 <body> 태그 부분을 따로 선택할 수도 있다. 

 

<class 'bs4.BeautifulSoup'>

 

 

<head>

<meta charset="utf-8"/>

<title>Wikipedia, the free encyclopedia</title>

<script>document.documentElement.className=document.documentElement.className.replace(/(^|\s)client-nojs(\s|$)/,"$1client-js$2");RLCONF={"wgCanonicalNamespace":"","wgC ... <중략>...

 

 

<body class="mediawiki ltr sitedir-ltr mw-hide-empty-elt ns-0 ns-subject page-Main_Page rootpage-Main_Page skin-vector action-view">

<div class="noprint" id="mw-page-base"></div>

<div class="noprint" id="mw-head-base"></div>

<div class="mw-body" id="content" role="main">

<a id="top"></a>

<div class="mw-body-content" id="siteNotice"><!-- CentralNotice --></div>

<div class="mw-indicators mw-body-content">

</div>  

<h1 class="firstHeading" id="firstHeading" lang="en">Main Page</h1>

<div class="mw-body-content" id="bodyContent">

<div class="noprint" id="siteSub">From Wikipedia, the free encyclopedia</div>

<div id="contentSub"></div>

<div id="jump-to-nav"></div>  ... <이하 생략>...

 

3) BeautifulSoup 클래스 속성 확인하기

print(soup.title)
print(soup.title.name)
print(soup.title.string)

 

<title> 태그를 먼저 선택해서 출력하면 태그의 문자열까지 전부 확인할 수 있다. 여기서 하위 속성인 name을 이용하면, 태그명을 선택할 수 있고, string 속성을 이용하면 문자열을 따로 추출할 수도 있다.

 

<title>Wikipedia, the free encyclopedia</title>

title

Wikipedia, the free encyclopedia

웹사이트에서 정보를 가져올 때, 기본적인 윤리규정과 저작권 등 법률적 이슈에 대하여 유의하여야 한다. 

 

위키피디아(https://ko.wikipedia.org/wiki/)는 로봇 배제 표준에 대하여 웹 사이트에 로봇이 접근하는 것을 방지하기 위한 규약으로, 일반적으로 접근 제한에 대한 설명을 robots.txt에 기술한다.” 라고 말한다. 무분별한 서버 접속은 서버의 안정성을 해치기도 하고, 대부분의 웹 사이트들은 로봇배제표준을 제정하여 게시하고 있다. 

 

 

권고안이기는 하지만 웹 페이지에 접근하기 전에 반드시 로봇 배제 표준을 확인하고 가이드라인을 준수할 필요가 있다.또한, 사이트에 반복적으로 접속하는 행위는 사이트를 공격하는 행위로 받아들여질 수 있기 때문에 서버에 부담을 주지 않는 선에서 제한하는 것이 필요하다. 

 

마지막으로취득한 데이터를 임의로 배포하거나 변경하는 등의 행위는 저작권을 침해할 가능성이 있기 때문에, 로봇배제표준 이외에 저작권 규정을 준수해야 한다. 

 

로봇배제표준을 확인하는 가장 간단한 방법은 웹브라우저 주소창에 "홈페이지 메인 주소/robots.txt"라고 입력하는 것이다.

 

네이버(www.naver.com)의 경우는 다음과 같다. 네이버는 기본적으로 스크래핑(크롤링) 봇의 접근을 금지하고 있다. 

다만, 루트 디렉터리(www.naver.com/)에 대해서는 허용하고 있는 것으로 볼 수 있다. $ 표시는 웹 주소의 마지막을 뜻하기 때문에, 루트 디렉터리의 경우 Allow하고 있다고 해석할 수 있다. 

 

로봇배제표준

로봇배제표준에 대한 상세 설명은 다음 위키피디아 링크를 참조하기 바란다. 

https://ko.wikipedia.org/wiki/%EB%A1%9C%EB%B4%87_%EB%B0%B0%EC%A0%9C_%ED%91%9C%EC%A4%80

+ Recent posts