인공지능

[빅데이터 직무연구회] 2주차 모임 정리

Chipmunks 2018. 5. 3.
728x90

[빅데이터 직무연구회] 2주차 모임 정리

모임 요일 : 4월 30일 일요일 저녁 6시

2.1 분류와 회귀

지도 학습에는 분류(Classification)회귀(Regression)가 있다.


1. 분류 : 미리 정의된, 가능성 있는 여러 클래스 레이블(class label) 중 하나를 예측하는 것

  • 이진 분류 : 두 개의 클래스로 분류, 양성(positive) 클래스, 음성(negative) 클래스
  • 다중 분류 : 셋 이상의 클래스로 분류


2. 회귀 : 연속적인 숫자, 또는 프로그래밍 용어로 말하면 부동소수점수(수학 용어로는 실수)를 예측하는 것, 예상 출력 값 사이에 연속성이 있음


2.2 일반화, 과대적합, 과소적합

  • 일반화(Generalization) : 모델이 처음 보는 데이터에 대해 정확하게 예측할 수 있을 때, 훈련 세트에서 테스트 세트로 일반화 되었다고 함. 가능한 한 정확하게 일반화되도록 해야 함
  • 과대적합(Overfitting) : 가진 정보를 모두 사용해서 너무 복잡한 모델을 만드는 것. 훈련 세트에 너무 가깝게 맞춰져서 새로운 데이터에 일반화되기 어려움
  • 과소적합(Underfitting) : 너무 간단한 모델. 데이터의 면면과 다양성을 잡아내지 못하고 훈련 세트에도 잘 맞지 않을 것

=> 과대적합과 과소적합 모두 피해 일반화 성능이 최대가 되는 최적점을 찾아야 함

2.2.1 모델 복잡도와 데이터셋 크기의 관계

데이터를 더 많이 수집하고 적절하게 더 복잡한 모델을 만들면, 놀라운 결과를 얻을 수 있음.

2.3 지도 학습 알고리즘

2.3.1 예제에 사용할 데이터셋

  1. forge 데이터셋 : 이진 분류 데이터셋 (26개의 데이터포인트, 2개의 특성)
  2. wave 데이터셋 : 회귀 알고리즘 설명
  3. 위스콘신 유방암 데이터셋 : 유방암 종양의 임상 데이터를 기록해놓은 것 (569개의 데이터포인트, 30개의 특성)
  4. 보스턴 주택가격 데이터셋 : 범죄율, 찰스강 인접도, 고속도록 접근성 등의 정보를 이용해 1970년대 보스턴 주변의 주택 평균 가격을 예측하는 것 (506개의 데이터포인트, 13개의 특성)

2.3.2 k-최근접 이웃

k-NN (k-Nearest Neighbors) 알고리즘 : 가장 간단한 머신러닝 알고리즘. 새로운 데이터 포인트에 대해 예측할 때 알고리즘이 훈련 데이터셋에서 가장 가까운 데이터 포인트, 즉 '최근접 이웃'을 찾는다.

k-최근접 이웃 분류

  • k가 1일 때 : 가장 가까운 훈련 데이터 포인트 하나를 최근접 이웃으로 찾아 예측
  • k가 2이상일 때 : 가장 가까운 k개를 선택, 이웃이 더 많은 클래스를 레이블로 지정

KNeighborsClassifier 분석

  • 이웃을 적게 사용 : 모델의 복잡도 증가 ( 결정 경계가 뾰족함 )
  • 이웃을 많이 사용 : 모델의 복잡도 감소 ( 결정 경계가 부드러움 )

k-최근접 이웃 회귀

  • k가 1일 때 : 가장 가까운 이웃의 타깃값
  • k가 2이상일 때 : 이웃 간의 평균이 예측

결정 계수 R^2 : 회귀 모델에서 예측의 적합도를 0과 1 사이의 값으로 계산한 것


KNeighborsRegressor 분석

이웃을 많이 사용 : 훈련 데이터에는 잘 안 맞을 수 있음. 그러나 더 안정된 예측이 가능

장단점과 매개변수

< 매개변수 >
  • 데이터 포인트 사이의 거리를 재는 방법 : 기본적으로 유클리디안 거리 방식 ( metric 매개변수의 기본값은 민코프스키 거리, 거듭제곱의 크기는 2 )
  • 이웃의 수
< 장점 >
  • 이해하기 매우 쉬운 모델
  • 많이 조정하지 않아도 자주 좋은 성능 발휘
  • 매우 빠르게 만들 수 있음

< 단점 >

  • 훈련 세트가 매우 크면 예측이 느려짐
  • 데이터 전처리 과정 중요
  • 많은 특성을 가진 데이터 셋에는 잘 동작하지 않음
  • 특성 값 대부분이 0인 (희소한) 데이터셋과는 특히 잘 작동되지 않음
: 예측이 느리고 많은 특성을 처리하는 능력이 부족해 현업에서 쓰지 않음


2.3.3 선형 모델

: 입력 특성에 대한 선형 함수를 만들어 예측. 특성이 많은 데이터셋에서 매우 훌륭한 성능을 냄

회귀의 선형 모델

: 선형 모델을 위한 일반화된 예측 함수

  • x[0]~x[p] : 하나의 데이터 포인트에 대한 특성 ( 특성의 개수 : p + 1 )

  • w와 b : 모델이 학습할 파라미터

  • y햇 : 모델이 만들어낸 예측값

Note. 하이퍼파라미터(hyperparameter) : 모델이 학습할 수 없어서 사람이 직접 설정해 주어야 하는 파라미터

  • 특성이 하나일 때 : 직선
  • 두개일 때 : 평면
  • 더 높은 차원 : 초평면(hyperplane)

< 회귀를 위한 선형 모델들 차이 >
  • 훈련 데이터로부터 모델 파라미터 w와 b를 학습하는 방법
  • 모델의 복잡도를 제어하는 방법


선형 회귀(최소제곱법)

  • 가장 간단하고 오래된 회귀용 선형 알고리즘.
  • 예측과 훈련 세트에 있는 타깃 y 사이의 평균제곱오차(Mean Squared Error)를 최소화하는 파라미터 w와 b를 찾음

평균제곱오차(MSE) : 예측값과 타깃값의 차이를 제곱하여 더한 후, 샘플의 개수로 나눈 것

  • 매개변수가 없음. => 모델의 복잡도를 제어할 방법이 없음 
  • w : 기울기 파라미터, 가중치(weight) 또는 계수(coefficient). LinearRegression() 객체의 coef_ 속성에 저장됨
  • b : 편향(offset) 또는 절편(intercept). 객체의 intercept_ 속성에 저장됨
  • 훈련 데이터에서 유도된 속성은 끝에 밑줄(_)을 붙임


  • 훈련 세트와 테스트 세트의 점수가 비슷함 : 과소적합 상태
  • 훈련 세트의 점수는 좋지만, 테스트 세트의 점수는 좋지 않음 : 과대적합 상태

=> 복잡도를 제어할 수 있는 모델을 사용해야 함.


릿지 회귀(Ridge)

: 복잡도를 제어해주는 추가 제약 조건이 추가됨. L2 규제 사용

규제(Regularization) : 가중치의 절댓값을 가능한 한 작게 만듦. w(기울기)의 모든 원소가 0에 가깝게 만들어 줌. 모든 특성이 출력에 주는 영향을 최소한으로 만듦.


L2 규제 : 평균제곱오차(MSE) 식에 

항이 추가 됨.


  • 𝛂를 크게 : 패널티의 효과가 커짐
  • 𝛂를 작게 : 그 반대가 됨
  • 모델의 복잡도가 낮아짐 : 훈련 세트에서의 성능은 낮아짐. 그러나 더 일반화된 모델이 됨
  • alpha 매개변수로 릿지 회귀 객체 생성 시 설정 가능

< 선형 회귀와 릿지 회귀의 비교 >
  • 훈련 데이터셋 크기가 400 미만 : 선형 회귀는 어떤 것도 학습하지 못함. 릿지 회귀는 학습함
  • 훈련 데이터셋 크기가 400보다 커짐 : 데이터가 많아질 수록 규제 항은 덜 중요해져서, 두 모델의 성능이 같아짐.
  • 데이터셋이 커질 수록 선형 회귀의 훈련 데이터 성능이 감소함. 이는 데이터가 많아질수록 모델이 데이터를 기억하거나 과대적합하기 어려워지기 때문


라쏘(Lasso)

: 릿지와 마찬가지로 𝛂를 설정함. 계수를 0에 가깝게 만들고자 함. L1 규제를 사용함. 모델을 이해하기 쉽고 중요한 특성이 무엇인지 파악하기 쉬움

L1 규제 : 어떤 계수들은 값이 0이 되어 완전히 제외되기도 함. 특성 선택(feature selection)이 자동으로 이뤄짐


< 릿지와 라쏘 둘 중 무엇을 선택해야 할까? >
  • Ridge : 어떤 계수도 0이 되지 않음. 주로 선호
  • Lasso : 특성이 많고 그 중 일부분만 중요하다면 더 좋은 선택일 수 있음. 분석하기 쉬운 모델임
  • ElasticNet : scikit-learn에서 제공. L1 규제와 L2 규제 두 매개변수를 조정할 수 있음
< 규제 방법 >
  • Alpha 매개변수 지원. 기본 값 1.0
  • 과소적합 줄임 : Alpha 값을 줄임 ( max_iter, 반복 실행하느 최대 횟수, 의 기본값을 늘려야 함 )
  • Alpha 값을 너무 맞추면 규제의 효과가 없어져 과대적합이 됨

라쏘는 계수 벡터의 L1 노름(Norm)을 패널티로 사용. 계수의 절댓값의 합






from IPython.display import display
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import mglearn

# 폰트 관련 자료
# https://programmers.co.kr/learn/courses/21/lessons/950
import matplotlib
matplotlib.rc("font", family="NanumGothicCoding")
In [2]:
# 데이터셋을 만듭니다.
X, y = mglearn.datasets.make_forge()
# 산점도를 그립니다.
mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
plt.legend(["클래스 0", "클래스 1"], loc=4)
plt.xlabel("첫 번째 특성")
plt.ylabel("두 번째 특성")
print("X.shape: {}".format(X.shape))
X.shape: (26, 2)
In [3]:
X, y = mglearn.datasets.make_wave(n_samples=40)
plt.plot(X, y, 'o')
plt.ylim(-3, 3)
plt.xlabel("특성")
plt.ylabel("타깃")
Out[3]:
Text(0,0.5,'타깃')
In [4]:
# 위스콘신 유방암 데이터
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
print("cancer.keys(): \n{}".format(cancer.keys()))
cancer.keys(): 
dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])
In [5]:
print("유방암 데이터의 형태: {}".format(cancer.data.shape))
유방암 데이터의 형태: (569, 30)
In [6]:
print("클래스별 샘플 개수:\n{}".format(
    {n: v for n, v in zip(cancer.target_names, np.bincount(cancer.target))}
))
클래스별 샘플 개수:
{'malignant': 212, 'benign': 357}
In [7]:
print("특성 이름:\n{}".format(cancer.feature_names))
특성 이름:
['mean radius' 'mean texture' 'mean perimeter' 'mean area'
 'mean smoothness' 'mean compactness' 'mean concavity'
 'mean concave points' 'mean symmetry' 'mean fractal dimension'
 'radius error' 'texture error' 'perimeter error' 'area error'
 'smoothness error' 'compactness error' 'concavity error'
 'concave points error' 'symmetry error' 'fractal dimension error'
 'worst radius' 'worst texture' 'worst perimeter' 'worst area'
 'worst smoothness' 'worst compactness' 'worst concavity'
 'worst concave points' 'worst symmetry' 'worst fractal dimension']
In [8]:
# 보스턴 주택가격
from sklearn.datasets import load_boston
boston = load_boston()
print("데이터의 형태: {}".format(boston.data.shape))
데이터의 형태: (506, 13)
In [9]:
X, y = mglearn.datasets.load_extended_boston()
print("X.shape: {}".format(X.shape))
X.shape: (506, 104)
In [10]:
mglearn.plots.plot_knn_classification(n_neighbors=1)
In [11]:
mglearn.plots.plot_knn_classification(n_neighbors=3)
In [12]:
from sklearn.model_selection import train_test_split
X, y = mglearn.datasets.make_forge()

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
In [13]:
from sklearn.neighbors import KNeighborsClassifier
clf = KNeighborsClassifier(n_neighbors=3)
In [14]:
clf.fit(X_train, y_train)
Out[14]:
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=1, n_neighbors=3, p=2,
           weights='uniform')
In [15]:
print("테스트 세트 예측: {}".format(clf.predict(X_test)))
테스트 세트 예측: [1 0 1 0 1 0 0]
In [16]:
print("테스트 세트 정확도: {:.2f}".format(clf.score(X_test, y_test)))
테스트 세트 정확도: 0.86
In [17]:
fig, axes = plt.subplots(1, 3, figsize=(10, 3))

for n_neighbors, ax in zip([1, 3, 9], axes):
    # fit 메서드는 self 객체를 반환
    # 그래서 객체 생성과 fit 메서드를 한 줄에 쓸 수 있음
    clf = KNeighborsClassifier(n_neighbors=n_neighbors).fit(X, y)
    mglearn.plots.plot_2d_separator(clf, X, fill=True, eps=0.5, ax=ax, alpha=.4)
    mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax=ax)
    ax.set_title("{} 이웃".format(n_neighbors))
    ax.set_xlabel("특성 0")
    ax.set_ylabel("특성 1")
axes[0].legend(loc=3)
Out[17]:
<matplotlib.legend.Legend at 0x10ee284a8>
In [18]:
from sklearn.datasets import load_breast_cancer

cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=66)

training_accuracy = []
test_accuracy = []
# 1에서 10까지 n_neighbors를 적용
neighbors_settings = range(1, 11)

for n_neighbors in neighbors_settings:
    # 모델 생성
    clf = KNeighborsClassifier(n_neighbors=n_neighbors)
    clf.fit(X_train, y_train)
    
    # 훈련 세트 정확도 저장
    training_accuracy.append(clf.score(X_train, y_train))
    # 일반화 정확도 저장
    test_accuracy.append(clf.score(X_test, y_test))

plt.plot(neighbors_settings, training_accuracy, label="train accuracy")
plt.plot(neighbors_settings, test_accuracy, label="test accuracy")
plt.ylabel("accuracy")
plt.xlabel("n_neighbors")
plt.legend()
Out[18]:
<matplotlib.legend.Legend at 0x1065fe9b0>
In [19]:
# k-최근접 이웃 회귀
mglearn.plots.plot_knn_regression(n_neighbors=1)
In [20]:
mglearn.plots.plot_knn_regression(n_neighbors=3)
In [21]:
from sklearn.neighbors import KNeighborsRegressor

X, y = mglearn.datasets.make_wave(n_samples=40)

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

reg = KNeighborsRegressor(n_neighbors=3)
reg.fit(X_train, y_train)

print("테스트 세트 예측:\n{}".format(reg.predict(X_test)))
print("테스트 세트 R^2: {:.2f}".format(reg.score(X_test, y_test)))
테스트 세트 예측:
[-0.05396539  0.35686046  1.13671923 -1.89415682 -1.13881398 -1.63113382
  0.35686046  0.91241374 -0.44680446 -1.13881398]
테스트 세트 R^2: 0.83
In [22]:
# KNeighborsRegressor 분석
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# -3과 3사이에 1,000개의 데이터 포인터를 만듦
line = np.linspace(-3, 3, 1000).reshape(-1, 1)
for n_neighbors, ax in zip([1, 3, 9], axes):
    # 1, 3, 9 이웃을 사용한 예측
    reg = KNeighborsRegressor(n_neighbors=n_neighbors)
    reg.fit(X_train, y_train)
    ax.plot(line, reg.predict(line))
    ax.plot(X_train, y_train, '^', c=mglearn.cm2(0), markersize=8)
    ax.plot(X_test, y_test, 'v', c=mglearn.cm2(1), markersize=8)
    
    ax.set_title("{} 이웃의 훈련 스코어: {:.2f} 테스트 스코어: {:.2f}".format(n_neighbors, reg.score(X_train, y_train), reg.score(X_test, y_test)))
    ax.set_xlabel("특성")
    ax.set_ylabel("타깃")
axes[0].legend(["모델 예측", "훈련 데이터/타깃", "테스트 데이터/타깃"], loc="best")

# 절댓값, 맨하탄 등 다른 방법들이 있다.
Out[22]:
<matplotlib.legend.Legend at 0x10ede16d8>
In [23]:
mglearn.plots.plot_linear_regression_wave()
/usr/local/lib/python3.6/site-packages/scipy/linalg/basic.py:1226: RuntimeWarning: internal gelsd driver lwork query error, required iwork dimension not returned. This is likely the result of LAPACK bug 0038, fixed in LAPACK 3.2.2 (released July 21, 2010). Falling back to 'gelss' driver.
  warnings.warn(mesg, RuntimeWarning)
w[0]: 0.393906  b: -0.031804
In [24]:
from sklearn.linear_model import LinearRegression
X, y = mglearn.datasets.make_wave(n_samples=60)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

lr = LinearRegression().fit(X_train, y_train)

print("lr.coef_: {}".format(lr.coef_))
print("lr.intercept_: {}".format(lr.intercept_))
lr.coef_: [0.39390555]
lr.intercept_: -0.03180434302675976
In [25]:
print("훈련 세트 점수: {:.2f}".format(lr.score(X_train, y_train)))
print("테스트 세트 점수: {:.2f}".format(lr.score(X_test, y_test)))
훈련 세트 점수: 0.67
테스트 세트 점수: 0.66
In [26]:
X, y = mglearn.datasets.load_extended_boston()

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
lr = LinearRegression().fit(X_train, y_train)
In [27]:
print("훈련 세트 점수: {:.2f}".format(lr.score(X_train, y_train)))
print("테스트 세트 점수: {:.2f}".format(lr.score(X_test, y_test)))
훈련 세트 점수: 0.95
테스트 세트 점수: 0.61
In [28]:
from sklearn.linear_model import Ridge

ridge = Ridge().fit(X_train, y_train)
print("훈련 세트 점수: {:.2f}".format(ridge.score(X_train, y_train)))
print("테스트 세트 점수: {:.2f}".format(ridge.score(X_test, y_test)))
훈련 세트 점수: 0.89
테스트 세트 점수: 0.75
In [29]:
ridge10 = Ridge(alpha=10).fit(X_train, y_train)
print("훈련 세트 점수: {:.2f}".format(ridge10.score(X_train, y_train)))
print("테스트 세트 점수: {:.2f}".format(ridge10.score(X_test, y_test)))
훈련 세트 점수: 0.79
테스트 세트 점수: 0.64
In [30]:
ridge01 = Ridge(alpha=0.1).fit(X_train, y_train)
print("훈련 세트 점수: {:.2f}".format(ridge01.score(X_train, y_train)))
print("테스트 세트 점수: {:.2f}".format(ridge01.score(X_test, y_test)))
훈련 세트 점수: 0.93
테스트 세트 점수: 0.77
In [31]:
plt.plot(ridge10.coef_, '^', label="Ridge alpha=10")
plt.plot(ridge.coef_, 's', label="Ridge alpha=1")
plt.plot(ridge01.coef_, 'v', label="Ridge alpha=0.1")

plt.plot(lr.coef_, 'o', label="LinearRegression")
plt.xlabel("계수 목록")
plt.ylabel("계수 크기")
plt.hlines(0, 0, len(lr.coef_))
plt.ylim(-25, 25)
plt.legend()
Out[31]:
<matplotlib.legend.Legend at 0x111a5c438>
In [32]:
mglearn.plots.plot_ridge_n_samples()
In [33]:
from sklearn.linear_model import Lasso

lasso = Lasso().fit(X_train, y_train)
print("훈련 세트 점수: {:.2f}".format(lasso.score(X_train, y_train)))
print("테스트 세트 점수: {:.2f}".format(lasso.score(X_test, y_test)))
print("사용한 특성의 수: {}".format(np.sum(lasso.coef_ != 0)))
훈련 세트 점수: 0.29
테스트 세트 점수: 0.21
사용한 특성의 수: 4
In [34]:
lasso001 = Lasso(alpha=0.01, max_iter=100000).fit(X_train, y_train)

print("훈련 세트 점수: {:.2f}".format(lasso001.score(X_train, y_train)))
print("테스트 세트 점수: {:.2f}".format(lasso001.score(X_test, y_test)))
print("사용한 특성의 수: {}".format(np.sum(lasso001.coef_ != 0)))
훈련 세트 점수: 0.90
테스트 세트 점수: 0.77
사용한 특성의 수: 33
In [35]:
lasso00001 = Lasso(alpha=0.0001, max_iter=100000).fit(X_train, y_train)
print("훈련 세트 점수: {:.2f}".format(lasso00001.score(X_train, y_train)))
print("테스트 세트 점수: {:.2f}".format(lasso00001.score(X_test, y_test)))
print("사용한 특성의 수: {}".format(np.sum(lasso00001.coef_ != 0)))
훈련 세트 점수: 0.95
테스트 세트 점수: 0.64
사용한 특성의 수: 94
In [36]:
plt.plot(lasso.coef_, 's', label="Lasso alpha=1")
plt.plot(lasso001.coef_, '^', label="Lasso alpha=0.01")
plt.plot(lasso00001.coef_, 'v', label="Lasso alpha=0.0001")

plt.plot(ridge01.coef_, 'o', label="Ridge alpha=0.1")
plt.legend(ncol=2, loc=(0, 1.05))
plt.ylim(-25, 25)
plt.xlabel("계수 목록")
plt.ylabel("계수 크기")
Out[36]:
Text(0,0.5,'계수 크기')


댓글