지도 머신 러닝 알고리즘 탐색
게시 됨: 2022-03-11이 읽기의 주요 목표는 Python의 scikit-learn 라이브러리에 있는 기계 학습 알고리즘을 활용할 수 있는 충분한 통계적 방법론을 이해한 다음 이 지식을 적용하여 고전적인 기계 학습 문제를 해결하는 것입니다.
여정의 첫 번째 중지는 기계 학습의 간략한 역사를 통해 안내할 것입니다. 그런 다음 다양한 알고리즘에 대해 알아보겠습니다. 마지막 정류장에서 우리는 타이타닉 생존율 예측 문제를 해결하기 위해 배운 것을 사용할 것입니다.
일부 면책 조항:
- 저는 머신러닝 알고리즘 전문가가 아니라 풀스택 소프트웨어 엔지니어입니다.
- 나는 당신이 기본적인 파이썬을 알고 있다고 가정합니다.
- 이것은 탐색적이므로 모든 세부 사항이 튜토리얼처럼 설명되지는 않습니다.
그 점을 지적하고 뛰어 들어 봅시다!
기계 학습 알고리즘에 대한 간략한 소개
이 분야에 뛰어들자마자 기계 학습이 생각보다 덜 낭만적이라는 것을 깨닫게 됩니다. 처음에 나는 더 많은 것을 배운 후에 하루 종일 소프트웨어를 코딩하고 돈을 벌면서 나만의 Jarvis AI를 구축할 수 있다는 희망으로 가득 차 있었습니다. 그래서 하루 종일 야외에서 책을 읽고, 오토바이를 운전하고, 내 개인 Jarvis가 내 주머니를 더 깊게 만드는 동안 무모한 라이프 스타일을 즐기고 있습니다. 그러나 곧 기계 학습 알고리즘의 기초가 통계라는 것을 깨달았습니다. 통계는 개인적으로 지루하고 흥미롭지 않습니다. 다행히도 "둔한" 통계에는 몇 가지 매우 매력적인 응용 프로그램이 있다는 것이 밝혀졌습니다.
이러한 매력적인 응용 프로그램을 사용하려면 통계를 매우 잘 이해해야 한다는 사실을 곧 알게 될 것입니다. 기계 학습 알고리즘의 목표 중 하나는 제공된 데이터에서 통계적 종속성을 찾는 것입니다.
제공된 데이터는 연령에 따른 혈압 측정부터 다양한 픽셀의 색상을 기반으로 한 손글씨 텍스트 찾기에 이르기까지 무엇이든 될 수 있습니다.
즉, 기계 학습 알고리즘을 사용하여 암호화 해시 함수(SHA, MD5 등)에서 종속성을 찾을 수 있는지 알고 싶었습니다. 의존성을 제거하고 상당히 예측하기 어려운 출력을 생성합니다. 무한한 시간이 주어지면 기계 학습 알고리즘이 모든 암호화 모델을 해독할 수 있다고 믿습니다.
불행히도 시간이 많지 않기 때문에 암호화폐를 효율적으로 채굴할 수 있는 다른 방법을 찾아야 합니다. 우리는 지금까지 얼마나 올랐습니까?
기계 학습 알고리즘의 간략한 역사
기계 학습 알고리즘의 뿌리는 18세기에 살았던 영국의 통계학자인 Thomas Bayes에서 비롯되었습니다. 그의 논문 An Essay Toward Solving the Problem in the Doctrine of Chance 는 통계 분야에서 널리 적용되는 Bayes의 정리를 뒷받침합니다.
19세기에 Pierre-Simon Laplace는 Theorie analytique des probabilites 를 출판하여 Bayes의 작업을 확장하고 오늘날 우리가 Bayes' Theorem으로 알고 있는 것을 정의했습니다. 그 직전에 Adrien-Marie Legendre는 지도 학습에서도 오늘날 널리 사용되는 "최소 제곱" 방법을 설명했습니다.
20세기는 공개적으로 알려진 대부분의 발견이 이 분야에서 이루어진 시대입니다. Andrey Markov는 Markov 사슬을 발명하여 시를 분석하는 데 사용했습니다. Alan Turing은 기본적으로 유전 알고리즘을 예고하는 인공 지능이 될 수 있는 학습 기계를 제안했습니다. Frank Rosenblatt는 퍼셉트론 을 발명하여 미디어에서 엄청난 흥분과 큰 관심을 불러일으켰습니다.
그러나 1970년대에는 AI에 대한 아이디어에 대해 많은 비관론이 있었고 따라서 자금이 감소했습니다. 그래서 이 시기를 AI 겨울 이라고 합니다. 1980년대 역전파(backpropagation)의 재발견은 기계 학습 연구의 부활을 일으켰습니다. 그리고 오늘 다시 한번 화제가 되었습니다.
늦은 Leo Breiman은 데이터 모델링과 알고리즘 모델링이라는 두 가지 통계 모델링 패러다임을 구분했습니다. "알고리즘 모델링"은 랜덤 포레스트 와 같은 기계 학습 알고리즘을 의미합니다.
머신 러닝과 통계는 밀접하게 관련된 분야입니다. 마이클 I. 조던(Michael I. Jordan)에 따르면 방법론적 원리에서 이론적 도구에 이르기까지 기계 학습의 아이디어는 통계에서 오랜 역사를 가지고 있습니다. 그는 또한 머신 러닝 전문가와 통계학자가 암묵적으로 작업하고 있는 전반적인 문제에 대한 자리 표시자 용어로 데이터 과학 을 제안했습니다.
기계 학습 알고리즘의 범주
머신 러닝 분야는 지도 학습( supervised learning )과 비지도 학습( unsupervised learning )이라는 두 가지 주요 기둥을 기반으로 합니다. 어떤 사람들은 또한 새로운 연구 분야인 딥 러닝 을 지도 학습 대 비지도 학습의 문제와 별개로 생각합니다.
지도 학습 은 컴퓨터에 입력 및 원하는 출력의 예가 표시되는 경우입니다. 컴퓨터의 목표는 입력을 출력으로 매핑하는 일반 공식을 배우는 것입니다. 이것은 다음과 같이 더 세분화될 수 있습니다.
- 컴퓨터에 일부 출력이 누락된 불완전한 훈련 세트가 제공되는 반 지도 학습
- 컴퓨터가 매우 제한된 인스턴스 집합에 대해서만 훈련 레이블을 얻을 수 있는 활성 학습 입니다. 대화식으로 사용하면 교육 세트가 레이블링을 위해 사용자에게 표시될 수 있습니다.
- 차량을 운전하거나 상대방과 게임을 하는 것과 같은 역동적인 환경에서 훈련 데이터가 프로그램의 동작에 대한 피드백으로만 제공되는 경우 강화 학습
대조적으로 비지도 학습 은 레이블이 전혀 주어지지 않고 입력에서 구조를 찾는 것은 알고리즘에 달려 있습니다. 비지도 학습은 숨겨진 패턴을 발견하기만 하면 되는 경우 그 자체로 목표가 될 수 있습니다.
딥 러닝 은 인간의 뇌 구조와 기능에서 영감을 받아 통계적 개념이 아닌 인공 신경망을 기반으로 하는 새로운 연구 분야입니다. 딥 러닝은 지도 및 비지도 접근 방식 모두에서 사용할 수 있습니다.
이 기사에서는 더 간단한 지도 머신 러닝 알고리즘 중 일부만 살펴보고 이를 사용하여 비극적인 타이타닉 침몰에서 개인의 생존 가능성을 계산할 것입니다. 그러나 일반적으로 어떤 알고리즘을 사용해야 할지 잘 모르겠다면 scikit-learn의 기계 학습 알고리즘 치트 시트를 시작하는 것이 좋습니다.
기본 지도 머신 러닝 모델
아마도 가장 쉬운 알고리즘은 선형 회귀일 것입니다. 때로는 이것을 직선으로 그래픽으로 나타낼 수 있지만 이름에도 불구하고 다항식 가설이 있는 경우 이 선은 대신 곡선이 될 수 있습니다. 어느 쪽이든 스칼라 종속 변수 $y$와 $x$로 표시된 하나 이상의 설명 값 간의 관계를 모델링합니다.
일반인의 관점에서 이것은 선형 회귀가 각각의 알려진 $x$와 $y$ 사이의 종속성을 학습하는 알고리즘임을 의미하므로 나중에 $x$의 알려지지 않은 샘플에 대해 $y$를 예측하는 데 사용할 수 있습니다.
첫 번째 지도 학습 예제에서 우리는 기본 선형 회귀 모델을 사용하여 나이가 주어진 사람의 혈압을 예측할 것입니다. 이것은 나이와 혈압이라는 두 가지 의미 있는 기능이 있는 매우 간단한 데이터세트입니다.
위에서 이미 언급했듯이 대부분의 기계 학습 알고리즘은 제공된 데이터에서 통계적 종속성을 찾는 방식으로 작동합니다. 이 종속성을 가설 이라고 하며 일반적으로 $h(\theta)$로 표시됩니다.
가설을 파악하기 위해 먼저 데이터를 로드하고 탐색해 보겠습니다.
import matplotlib.pyplot as plt from pandas import read_csv import os # Load data data_path = os.path.join(os.getcwd(), "data/blood-pressure.txt") dataset = read_csv(data_path, delim_whitespace=True) # We have 30 entries in our dataset and four features. The first feature is the ID of the entry. # The second feature is always 1. The third feature is the age and the last feature is the blood pressure. # We will now drop the ID and One feature for now, as this is not important. dataset = dataset.drop(['ID', 'One'], axis=1) # And we will display this graph %matplotlib inline dataset.plot.scatter(x='Age', y='Pressure') # Now, we will assume that we already know the hypothesis and it looks like a straight line h = lambda x: 84 + 1.24 * x # Let's add this line on the chart now ages = range(18, 85) estimated = [] for i in ages: estimated.append(h(i)) plt.plot(ages, estimated, 'b')
[<matplotlib.lines.Line2D at 0x11424b828>]
위의 차트에서 모든 파란색 점은 데이터 샘플을 나타내고 파란색 선은 알고리즘이 학습해야 하는 가설입니다. 그렇다면 이 가설은 정확히 무엇입니까?
이 문제를 해결하기 위해 $y = f(x)$로 표시되는 $x$와 $y$ 간의 종속성을 학습해야 합니다. 따라서 $f(x)$는 이상적인 대상 함수입니다. 기계 학습 알고리즘은 미지의 $f(x)$에 가장 가까운 근사값인 가설 함수 $h(x)$를 추측하려고 시도합니다.
선형 회귀 문제에 대한 가장 단순한 형태의 가설은 $h_\theta(x) = \theta_0 + \theta_1 * x$와 같습니다. 단일 스칼라 변수 $y$를 출력하는 단일 입력 스칼라 변수 $x$가 있습니다. 여기서 $\theta_0$ 및 $\theta_1$는 학습해야 하는 매개변수입니다. 이 파란색 선을 데이터에 맞추는 과정을 선형 회귀라고 합니다. 입력 매개변수 $x_1$가 하나만 있음을 이해하는 것이 중요합니다. 그러나 많은 가설 함수에는 편향 단위($x_0$)도 포함됩니다. 따라서 우리의 결과 가설은 $h_\theta(x) = \theta_0 * x_0 + \theta_1 * x_1$의 형식을 갖습니다. 그러나 $x_0$는 거의 항상 1과 같기 때문에 작성을 피할 수 있습니다.
파란색 라인으로 돌아갑니다. 우리의 가설은 $h(x) = 84 + 1.24x$처럼 보입니다. 즉, $\theta_0 = 84$이고 $\theta_1 = 1.24$입니다. 이러한 $\ta$ 값을 어떻게 자동으로 유도할 수 있습니까?
비용 함수 를 정의해야 합니다. 기본적으로 비용 함수가 하는 일은 모델 예측과 실제 출력 사이의 평균 제곱근 오차를 계산하는 것입니다.
\[J(\theta) = \frac{1}{2m}\sum_{i=1}^m(h_\theta(x^{(i)}) - y^{(i)})^2\ ]예를 들어, 우리의 가설은 48세인 사람의 혈압이 $h(48) = 84 + 1.24 * 48 = 143mmHg$여야 한다고 예측합니다. 그러나 훈련 샘플에는 $130 mmHg$의 값이 있습니다. 따라서 오류는 $(143 - 130)^2 = 169$입니다. 이제 훈련 데이터 세트의 모든 단일 항목에 대해 이 오류를 계산한 다음 함께 합산해야 합니다. ($\sum_{i=1}^m(h_\theta(x^{(i)}) - y^{(i )})^2$)에서 평균값을 빼냅니다.
이것은 우리에게 함수의 비용을 나타내는 단일 스칼라 숫자를 제공합니다. 우리의 목표는 비용 함수가 가장 낮도록 $\theta$ 값을 찾는 것입니다. 즉, 비용 함수를 최소화하려고 합니다. 이것은 직관적으로 보일 것입니다. 비용 함수 값이 작으면 예측 오류도 작음을 의미합니다.
import numpy as np # Let's calculate the cost for the hypothesis above h = lambda x, theta_0, theta_1: theta_0 + theta_1 * x def cost(X, y, t0, t1): m = len(X) # the number of the training samples c = np.power(np.subtract(h(X, t0, t1), y), 2) return (1 / (2 * m)) * sum(c) X = dataset.values[:, 0] y = dataset.values[:, 1] print('J(Theta) = %2.2f' % cost(X, y, 84, 1.24))
J(Theta) = 1901.95
이제 비용 함수 값이 최소가 되도록 $\theta$ 값을 찾아야 합니다. 하지만 어떻게 합니까?
\[minJ(\theta) = \frac{1}{2m}\sum_{i=1}^m(h_\theta(x^{(i)}) - y^{(i)})^2\ ]몇 가지 가능한 알고리즘이 있지만 가장 인기 있는 알고리즘은 경사하강법 입니다. 경사하강법의 이면에 있는 직관을 이해하기 위해 먼저 그래프에 플로팅해 보겠습니다. 단순화를 위해 더 간단한 가설 $h(\theta) = \theta_1 * x$를 가정합니다. 다음으로 $x$가 $\theta$의 값이고 $y$가 이 시점에서 비용 함수인 간단한 2D 차트를 플로팅합니다.
import matplotlib.pyplot as plt fig = plt.figure() # Generate the data theta_1 = np.arange(-10, 14, 0.1) J_cost = [] for t1 in theta_1: J_cost += [ cost(X, y, 0, t1) ] plt.plot(theta_1, J_cost) plt.xlabel(r'$\theta_1$') plt.ylabel(r'$J(\theta)$') plt.show()
비용 함수는 볼록하므로 $[a, b]$ 구간에는 최소값이 하나만 있습니다. 다시 말하지만 가장 좋은 $\theta$ 매개변수는 비용 함수가 최소인 지점에 있습니다.
기본적으로 경사하강법은 함수를 최소화하는 매개변수 집합을 찾는 알고리즘입니다. 초기 매개변수 세트로 시작하여 함수 기울기의 음의 방향으로 반복적으로 단계를 수행합니다.
특정 지점에서 가설 함수의 도함수를 계산하면 해당 지점에서 곡선에 대한 접선의 기울기를 얻을 수 있습니다. 이것은 그래프의 모든 단일 점에서 기울기를 계산할 수 있음을 의미합니다.
알고리즘이 작동하는 방식은 다음과 같습니다.
- 무작위 시작점(무작위 $\theta$)을 선택합니다.
- 이 시점에서 비용 함수의 미분을 계산합니다.
- $\theta_j := \theta_j - \lambda * \frac{\partial}{\partial \theta_j} * J(\theta)$ 기울기를 향해 작은 걸음을 내딛으세요.
- 수렴할 때까지 2-3단계를 반복합니다.
이제 수렴 조건은 알고리즘의 구현에 따라 다릅니다. 우리는 50단계 후, 어떤 임계값 이후 또는 다른 무엇이든 이후에 멈출 수 있습니다.
import math # Example of the simple gradient descent algorithm taken from Wikipedia cur_x = 2.5 # The algorithm starts at point x gamma = 0.005 # Step size multiplier precision = 0.00001 previous_step_size = cur_x df = lambda x: 2 * x * math.cos(x) # Remember the learning curve and plot it while previous_step_size > precision: prev_x = cur_x cur_x += -gamma * df(prev_x) previous_step_size = abs(cur_x - prev_x) print("The local minimum occurs at %f" % cur_x)
The local minimum occurs at 4.712194
이 기사에서는 이러한 알고리즘을 구현하지 않습니다. 대신에 널리 채택된 scikit-learn
, 오픈 소스 Python 기계 학습 라이브러리를 활용할 것입니다. 다양한 데이터 마이닝 및 기계 학습 문제에 대해 매우 유용한 API를 많이 제공합니다.
from sklearn.linear_model import LinearRegression # LinearRegression uses the gradient descent method # Our data X = dataset[['Age']] y = dataset[['Pressure']] regr = LinearRegression() regr.fit(X, y) # Plot outputs plt.xlabel('Age') plt.ylabel('Blood pressure') plt.scatter(X, y, color='black') plt.plot(X, regr.predict(X), color='blue') plt.show() plt.gcf().clear()
<matplotlib.figure.Figure at 0x120fae1d0>
print( 'Predicted blood pressure at 25 yo = ', regr.predict(25) ) print( 'Predicted blood pressure at 45 yo = ', regr.predict(45) ) print( 'Predicted blood pressure at 27 yo = ', regr.predict(27) ) print( 'Predicted blood pressure at 34.5 yo = ', regr.predict(34.5) ) print( 'Predicted blood pressure at 78 yo = ', regr.predict(78) )
Predicted blood pressure at 25 yo = [[ 122.98647692]] Predicted blood pressure at 45 yo = [[ 142.40388395]] Predicted blood pressure at 27 yo = [[ 124.92821763]] Predicted blood pressure at 34.5 yo = [[ 132.20974526]] Predicted blood pressure at 78 yo = [[ 174.44260555]]
통계 데이터의 유형
머신 러닝 문제에 대한 데이터로 작업할 때 다양한 유형의 데이터를 인식하는 것이 중요합니다. 숫자(연속 또는 이산), 범주 또는 순서 데이터가 있을 수 있습니다.
수치 데이터 는 측정의 의미가 있습니다. 예를 들어, 나이, 체중, 개인이 소유한 비트코인 수 또는 한 달에 작성할 수 있는 기사 수. 수치 데이터는 불연속형과 연속형으로 더 세분화할 수 있습니다.
- 이산 데이터는 정수로 셀 수 있는 데이터를 나타냅니다(예: 아파트의 방 수 또는 동전 던지기 횟수).
- 연속 데이터는 반드시 정수로 나타낼 수 없습니다. 예를 들어 점프할 수 있는 거리를 측정하는 경우 2미터 또는 1.5미터 또는 1.652245미터가 될 수 있습니다.
범주형 데이터 는 개인의 성별, 결혼 여부, 국가 등과 같은 값을 나타냅니다. 이 데이터는 숫자 값을 가질 수 있지만 이러한 숫자는 수학적 의미가 없습니다. 함께 추가할 수 없습니다.
서수 데이터 는 수학적으로 의미 있는 방식으로 범주에 번호가 매겨질 수 있다는 점에서 다른 두 가지 유형을 혼합할 수 있습니다. 일반적인 예는 등급입니다. 종종 우리는 1에서 10까지의 척도로 사물을 평가해야 하며 정수만 허용됩니다. 이를 수치적으로 사용할 수 있지만(예: 무언가에 대한 평균 등급을 찾기 위해) 기계 학습 방법을 적용할 때 데이터를 범주형인 것처럼 취급하는 경우가 많습니다.
로지스틱 회귀
선형 회귀는 숫자 값, 예를 들어 특정 크기와 방 수를 가진 집의 가격을 예측하는 데 도움이 되는 멋진 알고리즘입니다. 그러나 때로는 다음과 같은 질문에 대한 답을 얻기 위해 범주형 데이터를 예측할 수도 있습니다.
- 이것은 개입니까 고양이입니까?
- 이 종양은 악성입니까 양성입니까?
- 이 와인은 좋은가 나쁜가?
- 이 이메일은 스팸인가요?
또는:
- 사진에 있는 숫자는?
- 이 이메일은 어떤 카테고리에 속합니까?
이 모든 질문은 분류 문제 에만 해당됩니다. 그리고 가장 간단한 분류 알고리즘은 로지스틱 회귀( logistic regression )라고 하며, 이는 가설이 다르다는 점을 제외하고는 결국 선형 회귀와 동일합니다.
우선, 동일한 선형 가설 $h_\theta(x) = \theta^TX$를 재사용할 수 있습니다(이는 벡터화된 형태임). 선형 회귀가 $[a, b]$ 구간에서 임의의 숫자를 출력할 수 있는 반면, 로지스틱 회귀는 $[−1, 1]$의 값만 출력할 수 있습니다. 이는 개체가 주어진 범주에 속할 확률입니다.
시그모이드 함수 를 사용하여 모든 숫자 값을 $[−1, 1]$ 구간의 값을 나타내도록 변환할 수 있습니다.
\[f(x) = \frac{1}{1 + e^x}\]이제 $x$ 대신 기존 가설을 통과해야 하므로 다음을 얻습니다.
\[f(x) = \frac{1}{1 + e^{\theta_0 + \theta_1 * x_1 + ... + \theta_n * x_n}}\]그 후 가설이 0보다 크면 참 값이고 그렇지 않으면 거짓이라는 간단한 임계값을 적용할 수 있습니다.
\[h_\theta(x) = \begin{cases} 1 & \mbox{if } \theta^TX > 0 \\ 0 & \mbox{else} \end{cases}\]이는 동일한 비용 함수 와 동일한 경사 하강법을 사용하여 로지스틱 회귀에 대한 가설을 학습할 수 있음을 의미합니다.
다음 머신 러닝 알고리즘 예제에서는 자동 또는 수동 착륙 제어를 사용해야 하는지 여부를 우주 왕복선의 조종사에게 조언할 것입니다. 6개의 기능과 정답 으로 구성된 15개의 샘플로 구성된 매우 작은 데이터 세트가 있습니다.
기계 학습 알고리즘에서 "실제 정보" 라는 용어는 지도 학습 기술에 대한 훈련 세트의 분류 정확도를 나타냅니다.
데이터 세트가 완전합니다. 즉, 누락된 기능이 없습니다. 그러나 일부 기능에는 범주 대신 "*"이 있으므로 이 기능은 중요하지 않습니다. 이러한 별표는 모두 0으로 바꿉니다.
from sklearn.linear_model import LogisticRegression # Data data_path = os.path.join(os.getcwd(), "data/shuttle-landing-control.csv") dataset = read_csv(data_path, header=None, names=['Auto', 'Stability', 'Error', 'Sign', 'Wind', 'Magnitude', 'Visibility'], na_values='*').fillna(0) # Prepare features X = dataset[['Stability', 'Error', 'Sign', 'Wind', 'Magnitude', 'Visibility']] y = dataset[['Auto']].values.reshape(1, -1)[0] model = LogisticRegression() model.fit(X, y) # For now, we're missing one important concept. We don't know how well our model # works, and because of that, we cannot really improve the performance of our hypothesis. # There are a lot of useful metrics, but for now, we will validate how well # our algorithm performs on the dataset it learned from. "Score of our model is %2.2f%%" % (model.score(X, y) * 100)
Score of our model is 73.33%
확인?
이전 예에서 학습 데이터를 사용하여 모델의 성능을 검증했습니다. 그러나 우리 알고리즘이 데이터에 과소적합되거나 과대적합될 수 있다는 점을 고려할 때 이것이 이제 좋은 선택입니까? 집의 크기를 나타내는 특성과 가격을 나타내는 특성이 있는 더 간단한 예를 살펴보겠습니다.
from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression from sklearn.model_selection import cross_val_score # Ground truth function ground_truth = lambda X: np.cos(15 + np.pi * X) # Generate random observations around the ground truth function n_samples = 15 degrees = [1, 4, 30] X = np.linspace(-1, 1, n_samples) y = ground_truth(X) + np.random.randn(n_samples) * 0.1 plt.figure(figsize=(14, 5)) models = {} # Plot all machine learning algorithm models for idx, degree in enumerate(degrees): ax = plt.subplot(1, len(degrees), idx + 1) plt.setp(ax, xticks=(), yticks=()) # Define the model polynomial_features = PolynomialFeatures(degree=degree) model = make_pipeline(polynomial_features, LinearRegression()) models[degree] = model # Train the model model.fit(X[:, np.newaxis], y) # Evaluate the model using cross-validation scores = cross_val_score(model, X[:, np.newaxis], y) X_test = X plt.plot(X_test, model.predict(X_test[:, np.newaxis]), label="Model") plt.scatter(X, y, edgecolor='b', s=20, label="Observations") plt.xlabel("x") plt.ylabel("y") plt.ylim((-2, 2)) plt.title("Degree {}\nMSE = {:.2e}".format( degree, -scores.mean())) plt.show()
머신 러닝 알고리즘 모델은 훈련 데이터도 새로운 관찰도 일반화할 수 없는 경우 과소적합 입니다. 위의 예에서는 실제 훈련 데이터 세트를 실제로 나타내지 않고 성능이 매우 떨어지는 단순한 선형 가설을 사용합니다. 일반적으로 underfitting은 좋은 메트릭이 주어지면 쉽게 감지할 수 있으므로 논의되지 않습니다.
알고리즘이 표시된 모든 단일 관찰을 기억한다면 훈련 데이터 세트 외부의 새로운 관찰에 대한 성능이 저하됩니다. 이것을 과적합 이라고 합니다. 예를 들어, 30차 다항식 모델은 대부분의 점을 통과하고 훈련 세트에서 매우 좋은 점수를 받지만, 그 밖의 모든 것은 나쁜 성능을 보입니다.
우리의 데이터 세트는 하나의 기능으로 구성되며 2D 공간에 간단하게 표시할 수 있습니다. 그러나 실생활에서는 수백 개의 기능이 있는 데이터 세트가 있을 수 있으므로 유클리드 공간에서 시각적으로 플롯할 수 없습니다. 모델이 과소적합되는지 과대적합되는지 확인하기 위해 어떤 다른 옵션이 있습니까?
학습 곡선 의 개념을 소개할 시간입니다. 이것은 훈련 샘플 수에 대한 평균 제곱 오차를 표시하는 간단한 그래프입니다.

학습 자료에서 일반적으로 다음과 유사한 그래프를 볼 수 있습니다.
그러나 실제 생활에서는 그렇게 완벽한 사진을 얻지 못할 수도 있습니다. 각 모델에 대한 학습 곡선을 그려 보겠습니다.
from sklearn.model_selection import learning_curve, ShuffleSplit # Plot learning curves plt.figure(figsize=(20, 5)) for idx, degree in enumerate(models): ax = plt.subplot(1, len(degrees), idx + 1) plt.title("Degree {}".format(degree)) plt.grid() plt.xlabel("Training examples") plt.ylabel("Score") train_sizes = np.linspace(.6, 1.0, 6) # Cross-validation with 100 iterations to get a smoother mean test and training # score curves, each time with 20% of the data randomly selected as a validation set. cv = ShuffleSplit(n_splits=100, test_size=0.2, random_state=0) model = models[degree] train_sizes, train_scores, test_scores = learning_curve( model, X[:, np.newaxis], y, cv=cv, train_sizes=train_sizes, n_jobs=4) train_scores_mean = np.mean(train_scores, axis=1) test_scores_mean = np.mean(test_scores, axis=1) plt.plot(train_sizes, train_scores_mean, 'o-', color="r", label="Training score") plt.plot(train_sizes, test_scores_mean, 'o-', color="g", label="Test score") plt.legend(loc = "best") plt.show()
시뮬레이션된 시나리오에서 훈련 점수를 나타내는 파란색 선은 직선처럼 보입니다. 실제로는 여전히 약간 감소합니다. 실제로 이를 1차 다항식 그래프에서 볼 수 있지만 다른 그래프에서는 이 해상도로 구분하기에는 너무 미묘합니다. 우리는 적어도 "높은 편향" 시나리오에서 훈련과 테스트 관찰을 위한 학습 곡선 사이에 큰 격차가 있음을 분명히 알 수 있습니다.
중간에 있는 "보통" 학습률 그래프에서 훈련 점수와 시험 점수 선이 어떻게 합쳐지는지 볼 수 있습니다.
그리고 "높은 분산" 그래프에서 샘플 수가 적으면 테스트 점수와 훈련 점수가 매우 유사하다는 것을 알 수 있습니다. 그러나 샘플 수를 늘리면 테스트 점수가 멀어지는 동안 훈련 점수가 거의 완벽하게 유지됩니다.
비선형 가설, 예를 들어 더 많은 다항식 특징이 있는 가설을 사용하는 경우 과소적합 모델( 높은 편향 이 있는 모델이라고도 함)을 수정할 수 있습니다.
우리의 과적합 모델( 높은 분산 )은 표시된 모든 단일 예를 통과합니다. 그러나 테스트 데이터를 도입하면 학습 곡선 사이의 간격이 넓어집니다. 정규화, 교차 검증 및 더 많은 데이터 샘플을 사용하여 과적합 모델을 수정할 수 있습니다.
교차 검증
과적합을 피하는 일반적인 방법 중 하나는 사용 가능한 데이터의 일부를 유지하고 이를 테스트 세트로 사용하는 것입니다. 그러나 다항식 기능의 수와 같은 다양한 모델 설정을 평가할 때 최적의 추정기 성능을 달성하기 위해 매개변수를 조정할 수 있기 때문에 테스트 세트에 대한 우리의 지식이 과대적합될 위험이 있습니다. 모델에 누출. 이 문제를 해결하려면 "검증 세트"라고 하는 데이터 세트의 일부를 더 잡아야 합니다. 훈련은 훈련 세트에 대해 진행되며 최적의 모델 성능을 달성했다고 생각되면 검증 세트를 활용하여 최종 평가를 할 수 있습니다.
그러나 사용 가능한 데이터를 3개의 세트로 분할하여 모델 훈련에 사용할 수 있는 샘플 수를 크게 줄이고 결과는 훈련-검증 세트 쌍에 대한 특정 무작위 선택에 따라 달라질 수 있습니다.
이 문제에 대한 한 가지 솔루션은 교차 검증이라는 절차입니다. 표준 $k$-fold 교차 검증에서는 데이터를 fold라고 하는 $k$ 하위 집합으로 분할합니다. 그런 다음 나머지 폴드를 테스트 세트로 사용하면서 $k-1$ 폴드에 대해 알고리즘을 반복적으로 훈련합니다("홀드아웃 폴드"라고 함).
교차 검증을 사용하면 원래 훈련 세트로만 매개변수를 조정할 수 있습니다. 이를 통해 최종 모델을 선택하기 위해 테스트 세트를 실제로 보이지 않는 데이터 세트로 유지할 수 있습니다.
Leave P out , stratified $k$-fold , shuffle 및 split 등과 같은 교차 검증 기술이 훨씬 더 많지만 이 기사의 범위를 벗어납니다.
정규화
이것은 모델 과적합 문제를 해결하는 데 도움이 될 수 있는 또 다른 기술입니다. 대부분의 데이터 세트에는 패턴과 약간의 노이즈가 있습니다. 정규화의 목표는 모델에 대한 노이즈의 영향을 줄이는 것입니다.
세 가지 주요 정규화 기술이 있습니다: Lasso, Tikhonov 및 Elastic Net.
L1 정규화 (또는 올가미 정규화 )는 일부 기능을 선택하여 0으로 축소하여 최종 모델에서 어떤 역할도 하지 않습니다. L1은 중요한 기능을 선택하는 방법이라고 볼 수 있습니다.
L2 정규화 (또는 Tikhonov 정규화 )는 모든 기능을 상대적으로 작게 만들어 모델에 미치는 영향을 줄입니다.
탄성망 은 L1과 L2의 조합입니다.
정규화(특징 스케일링)
피쳐 스케일링은 데이터를 전처리하는 동안에도 중요한 단계입니다. 우리의 데이터 세트에는 $[-\infty, \infty]$ 값을 가진 기능과 다른 척도를 가진 다른 기능이 있을 수 있습니다. 독립된 값의 범위를 표준화하는 방법입니다.
Feature scaling은 학습 모델의 성능을 향상시키는 중요한 프로세스이기도 합니다. 우선 모든 기능이 동일한 표준으로 확장되면 경사하강법이 훨씬 빠르게 수렴됩니다. 또한 많은 알고리즘(예: SVM(Support Vector Machine))은 두 점 사이의 거리를 계산하여 작동하며 기능 중 하나의 값이 넓은 경우 거리는 이 기능의 영향을 크게 받습니다.
서포트 벡터 머신
SVM은 분류 및 회귀 문제에 사용할 수 있는 또 다른 널리 사용되는 기계 학습 알고리즘입니다. SVM에서 우리는 각 관찰을 $n$ 차원 공간의 한 점으로 플로팅합니다. 여기서 $n$은 우리가 가진 기능의 수입니다. 각 기능의 값은 특정 좌표의 값입니다. 그런 다음 두 클래스를 충분히 분리하는 초평면을 찾으려고 합니다.
최상의 초평면을 식별한 후에는 두 클래스를 더 분리하는 여백을 추가하려고 합니다.
SVM은 특성의 수가 매우 많거나 특성의 수가 데이터 샘플의 수보다 많은 경우에 매우 효과적입니다. 그러나 SVM은 벡터 기반으로 작동하기 때문에 사용 전에 데이터를 정규화하는 것이 중요합니다.
신경망
신경망 알고리즘은 아마도 기계 학습 연구에서 가장 흥미로운 분야일 것입니다. 신경망은 뇌의 뉴런이 함께 연결되는 방식을 모방하려고 합니다.
이것이 신경망의 모습입니다. 우리는 각 노드가 일련의 입력을 취하고 여기에 몇 가지 계산을 적용하고 값을 출력하는 많은 노드를 함께 결합합니다.
지도 학습과 비지도 학습 모두에 대해 매우 다양한 신경망 알고리즘이 있습니다. 신경망은 자율주행 자동차를 운전하고, 게임을 하고, 비행기를 착륙시키고, 이미지를 분류하는 데 사용할 수 있습니다.
악명 높은 타이타닉
RMS 타이타닉호는 1912년 4월 15일 북대서양에서 빙산과 충돌하여 침몰한 영국 여객선입니다. 약 2,224명의 승무원과 승객이 있었고 1,500명 이상이 사망하여 역사상 가장 치명적인 상업 해상 재해 중 하나가 되었습니다.
이제 분류 문제에 사용되는 가장 기본적인 기계 학습 알고리즘의 이면에 있는 직관을 이해하기 때문에 우리의 지식을 적용하여 타이타닉에 탑승한 사람들의 생존 결과를 예측할 수 있습니다.
우리의 데이터 세트는 Kaggle 데이터 과학 대회 플랫폼에서 빌릴 것입니다.
import os from pandas import read_csv, concat # Load data data_path = os.path.join(os.getcwd(), "data/titanic.csv") dataset = read_csv(data_path, skipinitialspace=True) dataset.head(5)
승객 ID | 생존 | 피클래스 | 이름 | 섹스 | 나이 | 시브스프 | 볶다 | 티켓 | 요금 | 선실 | 승선 | |
0 | 1 | 0 | 삼 | 브라운 씨, 오웬 해리스 | 남성 | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | 난 | 에스 |
1 | 2 | 1 | 1 | 커밍스, 존 브래들리 부인(플로렌스 브릭스... | 여자 | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | 씨 |
2 | 삼 | 1 | 삼 | 하이키넨, 미스 라이나 | 여자 | 26.0 | 0 | 0 | 스톤/O2. 3101282 | 7.9250 | 난 | 에스 |
삼 | 4 | 1 | 1 | 퓨트렐, 자크 히스 부인(릴리 메이 필) | 여자 | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | 에스 |
4 | 5 | 0 | 삼 | 앨런, 윌리엄 헨리 씨 | 남성 | 35.0 | 0 | 0 | 373450 | 8.0500 | 난 | 에스 |
첫 번째 단계는 데이터를 로드하고 탐색하는 것입니다. 891개의 테스트 기록이 있습니다. 각 레코드의 구조는 다음과 같습니다.
- 승객 ID – 탑승한 승객의 ID
- 생존 – 사람이 충돌에서 살아남았는지 여부
- pclass – 티켓 등급(예: 1, 2, 3)
- 성별 – 승객의 성별: 남성 또는 여성
- 이름 – 제목 포함
- 나이 – 나이(년)
- sibsp – 타이타닉에 탑승한 형제/배우자의 수
- parch – 타이타닉호에 탑승한 부모/자녀의 수
- 티켓 – 티켓 번호
- 운임 – 여객 운임
- 객실 – 객실 번호
- embarked - 승선항
이 데이터 세트에는 숫자 및 범주 데이터가 모두 포함되어 있습니다. 일반적으로 데이터를 더 깊이 파고들어 이를 기반으로 가정을 하는 것이 좋습니다. 그러나 이 경우 이 단계를 건너뛰고 바로 예측으로 이동합니다.
import pandas as pd # We need to drop some insignificant features and map the others. # Ticket number and fare should not contribute much to the performance of our models. # Name feature has titles (eg, Mr., Miss, Doctor) included. # Gender is definitely important. # Port of embarkation may contribute some value. # Using port of embarkation may sound counter-intuitive; however, there may # be a higher survival rate for passengers who boarded in the same port. dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\.', expand=False) dataset = dataset.drop(['PassengerId', 'Ticket', 'Cabin', 'Name'], axis=1) pd.crosstab(dataset['Title'], dataset['Sex'])
Title \ Sex | 여자 | 남성 |
캡틴 | 0 | 1 |
안부 | 0 | 2 |
백작 부인 | 1 | 0 |
두목 | 0 | 1 |
박사 | 1 | 6 |
Jonkheer | 0 | 1 |
숙녀 | 1 | 0 |
주요한 | 0 | 2 |
주인 | 0 | 40 |
놓치다 | 182 | 0 |
Mlle | 2 | 0 |
음 | 1 | 0 |
~ 씨 | 0 | 517 |
부인 | 125 | 0 |
양 | 1 | 0 |
신부님 | 0 | 6 |
선생님 | 0 | 1 |
# We will replace many titles with a more common name, English equivalent, # or reclassification dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col',\ 'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Other') dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss') dataset['Title'] = dataset['Title'].replace('Ms', 'Miss') dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs') dataset[['Title', 'Survived']].groupby(['Title'], as_index=False).mean()
제목 | 생존 | |
0 | 주인 | 0.575000 |
1 | 놓치다 | 0.702703 |
2 | ~ 씨 | 0.156673 |
삼 | 부인 | 0.793651 |
4 | 다른 | 0.347826 |
# Now we will map alphanumerical categories to numbers title_mapping = { 'Mr': 1, 'Miss': 2, 'Mrs': 3, 'Master': 4, 'Other': 5 } gender_mapping = { 'female': 1, 'male': 0 } port_mapping = { 'S': 0, 'C': 1, 'Q': 2 } # Map title dataset['Title'] = dataset['Title'].map(title_mapping).astype(int) # Map gender dataset['Sex'] = dataset['Sex'].map(gender_mapping).astype(int) # Map port freq_port = dataset.Embarked.dropna().mode()[0] dataset['Embarked'] = dataset['Embarked'].fillna(freq_port) dataset['Embarked'] = dataset['Embarked'].map(port_mapping).astype(int) # Fix missing age values dataset['Age'] = dataset['Age'].fillna(dataset['Age'].dropna().median()) dataset.head()
생존 | Pclass | 섹스 | 나이 | SibSp | Parch | 요금 | 승선 | 제목 | |
0 | 0 | 삼 | 0 | 22.0 | 1 | 0 | 7.2500 | 0 | 1 |
1 | 1 | 1 | 1 | 38.0 | 1 | 0 | 71.2833 | 1 | 삼 |
2 | 1 | 삼 | 1 | 26.0 | 0 | 0 | 7.9250 | 0 | 2 |
삼 | 1 | 1 | 1 | 35.0 | 1 | 0 | 53.1000 | 0 | 삼 |
4 | 0 | 삼 | 0 | 35.0 | 0 | 0 | 8.0500 | 0 | 1 |
At this point, we will rank different types of machine learning algorithms in Python by using scikit-learn
to create a set of different models. It will then be easy to see which one performs the best.
- Logistic regression with varying numbers of polynomials
- 선형 커널이 있는 서포트 벡터 머신
- Support vector machine with a polynomial kernel
- 신경망
For every single model, we will use $k$-fold validation.
from sklearn.model_selection import KFold, train_test_split from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures, StandardScaler from sklearn.neural_network import MLPClassifier from sklearn.svm import SVC # Prepare the data X = dataset.drop(['Survived'], axis = 1).values y = dataset[['Survived']].values X = StandardScaler().fit_transform(X) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state = None) # Prepare cross-validation (cv) cv = KFold(n_splits = 5, random_state = None) # Performance p_score = lambda model, score: print('Performance of the %s model is %0.2f%%' % (model, score * 100)) # Classifiers names = [ "Logistic Regression", "Logistic Regression with Polynomial Hypotheses", "Linear SVM", "RBF SVM", "Neural Net", ] classifiers = [ LogisticRegression(), make_pipeline(PolynomialFeatures(3), LogisticRegression()), SVC(kernel="linear", C=0.025), SVC(gamma=2, C=1), MLPClassifier(alpha=1), ]
# iterate over classifiers models = [] trained_classifiers = [] for name, clf in zip(names, classifiers): scores = [] for train_indices, test_indices in cv.split(X): clf.fit(X[train_indices], y[train_indices].ravel()) scores.append( clf.score(X_test, y_test.ravel()) ) min_score = min(scores) max_score = max(scores) avg_score = sum(scores) / len(scores) trained_classifiers.append(clf) models.append((name, min_score, max_score, avg_score)) fin_models = pd.DataFrame(models, columns = ['Name', 'Min Score', 'Max Score', 'Mean Score'])
fin_models.sort_values(['Mean Score']).head()
이름 | 최소 점수 | 최대 점수 | 평균 점수 | |
2 | 선형 SVM | 0.793296 | 0.821229 | 0.803352 |
0 | 로지스틱 회귀 | 0.826816 | 0.860335 | 0.846927 |
4 | 신경망 | 0.826816 | 0.860335 | 0.849162 |
1 | Logistic Regression with Polynomial Hypotheses | 0.854749 | 0.882682 | 0.869274 |
삼 | RBF SVM | 0.843575 | 0.888268 | 0.869274 |
Ok, so our experimental research says that the SVM classifier with a radial basis function (RBF) kernel performs the best. Now, we can serialize our model and re-use it in production applications.
import pickle svm_model = trained_classifiers[3] data_path = os.path.join(os.getcwd(), "best-titanic-model.pkl") pickle.dump(svm_model, open(data_path, 'wb'))
Machine learning is not complicated, but it's a very broad field of study, and it requires knowledge of math and statistics in order to grasp all of its concepts.
Right now, machine learning and deep learning are among the hottest topics of discussion in Silicon Valley, and are the bread and butter of almost every data science company, mainly because they can automate many repetitive tasks including speech recognition, driving vehicles, financial trading, caring for patients, cooking, marketing, and so on.
Now you can take this knowledge and solve challenges on Kaggle.
This was a very brief introduction to supervised machine learning algorithms. Luckily, there are a lot of online courses and information about machine learning algorithms. I personally would recommend starting with Andrew Ng's course on Coursera.
자원
- Andrew Ng's course on Coursera
- Kaggle datasets
- A deep learning reading list
- A list of free books on machine learning algorithms, data mining, deep learning, and related topics
- 기계 학습 이론 및 응용 소개: 예제가 포함된 시각적 자습서