### 2021.12.13

 

from 이수안컴퓨터연구소

https://www.youtube.com/watch?v=eVxGhCRN-xA

scikit-learn 특징

  • 다양한 머신러닝 알고리즘을 구현한 파이썬 라이브러리
  • 심플하고 일관성 있는 API, 유용한 온라인 문서, 풍부한 예제
  • 머신러닝을 위한 쉽고 효율적인 개발 라이브러리 제공
  • 다양한 머신러닝 관련 알고리즘과 개발을 위한 프레임워크와 API 제공
  • 많은 사람들이 사용하며 다양한 환경에서 검증된 라이브러리

모듈설명

모듈 설명
sklearn.datasets 내장된 예제 데이터 세트
sklearn.preprocessing 다양한 데이터 전처리 기능 제공 (변환, 정규화, 스케일링 등)
sklearn.feature_selection 특징(feature)를 선택할 수 있는 기능 제공
sklearn.feature_extraction 특징(feature) 추출에 사용
sklearn.decomposition 차원 축소 관련 알고리즘 지원 (PCA, NMF, Truncated SVD 등)
sklearn.model_selection 교차 검증을 위해 데이터를 학습/테스트용으로 분리, 최적 파라미터를 추출하는 API 제공 (GridSearch 등)
sklearn.metrics 분류, 회귀, 클러스터링, Pairwise에 대한 다양한 성능 측정 방법 제공 (Accuracy, Precision, Recall, ROC-AUC, RMSE 등)
sklearn.pipeline 특징 처리 등의 변환과 ML 알고리즘 학습, 예측 등을 묶어서 실행할 수 있는 유틸리티 제공
sklearn.linear_model 선형 회귀, 릿지(Ridge), 라쏘(Lasso), 로지스틱 회귀 등 회귀 관련 알고리즘과 SGD(Stochastic Gradient Descent) 알고리즘 제공
sklearn.svm 서포트 벡터 머신 알고리즘 제공
sklearn.neighbors 최근접 이웃 알고리즘 제공 (k-NN 등)
sklearn.naive_bayes 나이브 베이즈 알고리즘 제공 (가우시안 NB, 다항 분포 NB 등)
sklearn.tree 의사 결정 트리 알고리즘 제공
sklearn.ensemble 앙상블 알고리즘 제공 (Random Forest, AdaBoost, GradientBoost 등)
sklearn.cluster 비지도 클러스터링 알고리즘 제공 (k-Means, 계층형 클러스터링, DBSCAN 등)

estimator API

  • 일관성: 모든 객체는 일관된 문서를 갖춘 제한된 메서드 집합에서 비롯된 공통 인터페이스 공유
  • 검사(inspection): 모든 지정된 파라미터 값은 공개 속성으로 노출
  • 제한된 객체 계층 구조
    • 알고리즘만 파이썬 클래스에 의해 표현
    • 데이터 세트는 표준 포맷(NumPy 배열, Pandas DataFrame, Scipy 희소 행렬)으로 표현
    • 매개변수명은 표준 파이썬 문자열 사용
  • 구성: 많은 머신러닝 작업은 기본 알고리즘의 시퀀스로 나타낼 수 있으며, Scikit-Learn은 가능한 곳이라면 어디서든 이 방식을 사용
  • 합리적인 기본값: 모델이 사용자 지정 파라미터를 필요로 할 때 라이브러리가 적절한 기본값을 정의

 

API 사용 방법

  1. Scikit-Learn으로부터 적절한 estimator 클래스를 임포트해서 모델의 클래스 선택
  2. 클래스를 원하는 값으로 인스턴스화해서 모델의 하이퍼파라미터 선택
  3. 데이터를 특징 배열과 대상 벡터로 배치
  4. 모델 인스턴스의 fit() 메서드를 호출해 모델을 데이터에 적합
  5. 모델을 새 데이터에 대해서 적용
    • 지도 학습: 대체로 predict() 메서드를 사용해 알려지지 않은 데이터에 대한 레이블 예측
    • 비지도 학습: 대체로 transform()이나 predict() 메서드를 사용해 데이터의 속성을 변환하거나 추론

 

# API 예제 

import numpy as np
import matplotlib.pyplot as plt
plt.style.use(['seaborn-whitegrid']

x = 10 * np.random.rand(50)
y = 2 * x + np.random.rand(50)
plot.scatter(x,y)

#1. 적절한 extimator 클래스를 임포트해서 모델의 클래스 선택
from sklearn.linear_model import LinearRegression

#2. 클래스를 원하는 값으로 인스턴스화해서 모델의 하이퍼파라미터 선택
model = LinearRegression(fit_intercept=True)
model

# out : LinearRegreesion(copy_X=True, fit_intercept=True, n_jobs=None, normalize=False)

 

  • copy_X            X를 복사해서 사용할 것인가
  • fit_intercept    상수인가
  • n_jobs             CPU를 병렬로 사용할것인가
  • normalize        정규화가 되어있냐
# 3.데이터를 특징 배열과 대상 벡터로 배치
X = x[:, np.newaxis]

X

# out : (50,1) 인 2차원 행렬 생성

 

# 4. 모델 인스턴스의 fit() 메서드를 호출해 모델을 데이터에 적합
model.fit(X,y)

model.coef_
# out : array([1.99630302])

model.intercept_
# out : 0.4759856348626279
#5. 모델을 새 데이터에 대해서 적용
xfit = np.linspace(-1,11)
Xfit = xfit[:, np.newaxis]
yfit = model.predict(Xfit)

plt.scatter(x,y)
plt.plot(xfit,yfit, '--r')

 

# 예제 데이터 세트

분류 또는 회귀용 데이터 세트

API 설명
datasets.load_boston() 미국 보스턴의 집에 대한 특징과 가격 데이터 (회귀용)
datasets.load_breast_cancer() 위스콘신 유방암 특징들과 악성/음성 레이블 데이터 (분류용)
datasets.load_diabetes() 당뇨 데이터 (회귀용)
datasets.load_digits() 0에서 9까지 숫자 이미지 픽셀 데이터 (분류용)
datasets.load_iris() 붓꽃에 대한 특징을 가진 데이터 (분류용)

온라인 데이터 세트

  • 데이터 크기가 커서 온라인에서 데이터를 다운로드 한 후 에 불러오는 예제 데이터 세트
API 설명
fetch_california_housing() 캘리포니아 주택 가격 데이터
fetch_covtype() 회귀 분석용 토지 조사 데이터
fetch_20newsgroups() 뉴스 그룹 텍스트 데이터
fetch_olivetti_faces() 얼굴 이미지 데이터
fetch_lfw_people() 얼굴 이미지 데이터
fetch_lfw_paris() 얼굴 이미지 데이터
fetch_rcv1() 로이터 뉴스 말뭉치 데이터
fetch_mldata() ML 웹사이트에서 다운로드

분류와 클러스터링을 위한 표본 데이터 생성

API 설명
datasets.make_classifications() 분류를 위한 데이터 세트 생성. 높은 상관도, 불필요한 속성 등의
노이즈를 고려한 데이터를 무작위로 생성
datasets.make_blobs() 클러스터링을 위한 데이터 세트 생성. 군집 지정 개수에 따라
여러 가지 클러스터링을 위한 데이터 셋트를 무작위로 생성

 

# 예제 데이터 세트 구조

  • 일반적으로 딕셔너리 형태로 구성
  • data: 특징 데이터 세트
  • target: 분류용은 레이블 값, 회귀용은 숫자 결과값 데이터
  • target_names: 개별 레이블의 이름 (분류용)
  • feature_names: 특징 이름
  • DESCR: 데이터 세트에 대한 설명과 각 특징 설명
from sklearn.datasets import load_diabetes

diabetes = load_diabetes()
print(diabetes.keys())
# dict_keys(['data', 'target', 'frame', 'DESCR', 'feature_names', 'data_filename', 'target_filename', 'data_module'])

print(diabetes.data)

[[ 0.03807591  0.05068012  0.06169621 ... -0.00259226  0.01990842
  -0.01764613]
 [-0.00188202 -0.04464164 -0.05147406 ... -0.03949338 -0.06832974
  -0.09220405]
 [ 0.08529891  0.05068012  0.04445121 ... -0.00259226  0.00286377
  -0.02593034]
 ...
 [ 0.04170844  0.05068012 -0.01590626 ... -0.01107952 -0.04687948
   0.01549073]
 [-0.04547248 -0.04464164  0.03906215 ...  0.02655962  0.04452837
  -0.02593034]
 [-0.04547248 -0.04464164 -0.0730303  ... -0.03949338 -0.00421986
   0.00306441]]

print(diabetes.target)
# 442개의 값이 나옴

print(diabetes.DESCR)
# 데이터셋에 대한 설명이 나옴

print(diabetes.feature_names)
# ['age', 'sex', 'bmi', 'bp', 's1', 's2', 's3', 's4', 's5', 's6']

print(diabetes.data_filename)
# diabetes_data.csv.gz

print(diabetes.target_filename)
# diabetes_target.csv.gz

 

model_selection 모듈

  • 학습용 데이터와 테스트 데이터로 분리
  • 교차 검증 분할 및 평가
  • Estimator의 하이퍼 파라미터 튜닝을 위한 다양한 함수와 클래스 제공

train_test_split(): 학습/테스트 데이터 세트 분리

from sklearn.linear_model import LinearRegression
from sklearn.medel_selection import train_test_split
from sklearn.datasets import load_diabetes 

diabetes = load_diabetes()

X_ train, X_test, y_train, y_test = train_test_split(diabetes.data, diabetes.target, test_size = 0.3)
# feature(독립변수) 와 target(종속변수)을 넣어줌
# test_size = 0.3.  -> train data는 70% / test data는 30%

model = LinearRegression()

# 학습용 데이터를 가져와야한다.
model.fit(X_train, y_train)

print("학습 데이터 점수 : {}".format(model.score(X_train, y_train)))
print("평가 데이터 점수 : {}".format(model.score(X_test, y_test)))
학습 데이터 점수 : 0.5077991367726067
평가 데이터 점수 : 0.515546766783626

#1.0에 가까워야지 좋은 점수
# 왜 점수가 이렇게 밖에 안나왔을까?

import matplotlib.pyplot as plt

predicted = model.predict(X_test)
expected = y_test

plt.figure(figsize=(8,4))
plt.scatter(expected, predicted)
plt.plot([30,350],[30,350], '--r')
plt.tight_layout()

점들이 선에서 벗어나있는게 많아서 신뢰도가 낮음

-> 모델을 다른 것을 쓰거나, 데이터를 다른 것을 가져와야한다.

 

cross_val_score(): 교차 검증

from sklearn.model_selection import cross_val_score, cross_validate
from sklearn.linear_model import LinearRegression
from sklearn.datasets import load_diabetes 

diabetes = load_diabetes()
scores = cross_val_score(model, diabetes.data, diabetes.target, cv=5)

print("교차 검증 정확도: {}".format(scores))
print("교차 검증 정확도: {} +/- {}".format(np.mean(scores), np.std(scores)))

#교차 검증 정확도: [0.42955643 0.52259828 0.4826784  0.42650827 0.55024923]
#교차 검증 정확도: 0.48231812211149394 +/- 0.049266197765632194

 

GridSearchCV: 교차 검증과 최적 하이퍼 파라미터 찾기

  • 훈련 단계에서 학습한 파라미터에 영향을 받아서 최상의 파라미터를 찾는 일은 항상 어려운 문제
  • 다양한 모델의 훈련 과정을 자동화하고, 교차 검사를 사용해 최적 값을 제공하는 도구 필요
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import Ridge
import pandas as pd

alpha = [0.001, 0.01, 0.1, 1, 10, 100, 1000]
param_grid = dict(alpha=alpha)

gs = GridSearchCV(estimator=Ridge(), param_grid=param_grid, cv=10)
result = gs.fit(diabetes.data, diabetes.target)

print("최적 점수 : {}".format(reshlt.best_score_))
print("최적 파라미터 : {}".format(result.best_params_))
print(gs.best_estimator_)

# 최적 점수 : 0.4633240541517593
# 최적 파라미터 : {'alpha': 0.1}
# Ridge(alpha=0.1)

pd.DataFrame(result.cv_results_)

  • multiprocessing을 이용한 GridSearchCV
import multiprocessing #모델을 페럴하게 사용하기위해
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression

iris = load_iris()

param_grid = [{'penalty' : ['l1','l2'],
               'C' : [0.5, 1.0, 1.5, 1.8, 2.0, 2.4]}]

gs = GridSearchCV(estimator=LogisticRegression(), param_grid=param_grid,
					scoring='accuracy', cv=10, n_jobs=multiprocessing.cpu_count())
                    
result = gs.fit(iris.data, iris.target)

print("최적 점수 : {}".format(reshlt.best_score_))
print("최적 파라미터 : {}".format(result.best_params_))
print(gs.best_estimator_)

# 최적 점수 : 0.9800000000000001
# 최적 파라미터 : {'C': 2.4, 'penalty': 'l2'}
# LogisticRegression(C=2.4)

pd.DataFrame(result.cv_results_)

 

preprocessing 데이터 전처리 모듈

  • 데이터의 특징 스케일링(feature scaling)을 위한 방법으로 표준화(Standardization)와 정규화(Normalization) 사용
  • 표준화 방법

  • 정규화 방법

  • scikit-learn에서는 개별 벡터 크기를 맞추는 형태로 정규화

 

StandardScaler: 표준화 클래스

iris = load_iris()
iris_df = pd.DataFrame(data=iris.data, columns = iris.feature_names)
iris_df.describe()

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
iris_scaled = scaler.fit_transform(iris_df)
# fit를 통해 정규화된 정보를 가져오고 / transform을 통해 스케일된 변환을 거친다.
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)

iris_df_scaled.describe()

X_train, X_test, y_train, y_test = train_test_split(iris_df_scaled, iris.target, test_size=0.3)

model = LogisticRegression()
model.fit(X_train, y_train)

print("훈련 데이터 점수 : {}".format(model.score(X_train, y_train)))
print("평가 데이터 점수 : {}".format(model.score(X_test, y_test)))

# 훈련 데이터 점수 : 0.9809523809523809
# 평가 데이터 점수 : 0.9111111111111111

 

MinMaxScaler: 정규화 클래스

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
iris_scaled = scaler.fit_transform(iris_df)
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
iris_df_scaled.describe()

X_train, X_test, y_train, y_test = train_test_split(iris_df_scaled, iris.target, test_size=0.3)

model = LogisticRegression()
model.fit(X_train, y_train)

print("훈련 데이터 점수 : {}".format(model.score(X_train, y_train)))
print("평가 데이터 점수 : {}".format(model.score(X_test, y_test)))

# 훈련 데이터 점수 : 0.9142857142857143
# 평가 데이터 점수 : 0.9333333333333333

 

성능 평가 지표

정확도(Accuracy)

  • 정확도는 전체 예측 데이터 건수 중 예측 결과가 동일한 데이터 건수로 계산
  • scikit-learn에서는 accuracy_score 함수를 제공
  • 정확도만 보고 이 데이터의 신뢰도를 정확히 알 수는 없다.
from sklearn.datasets import make_classification  #데이터를 만드는 모듈
from sklearn.linear_model import LogisticRegression
from sklearn.matrics import accuracy_score
  
X, y = make_classification(n_samples=1000, n_features=2, n_informative=2,
  				n_redundant=0, n_clusters_per_class=1)
#샘플은 1000개 / feature은 2개  / 의미있는 feature가 2개  /  노이즈가 0  / 클래스당 클러스터가 1개
 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
 
model = LogisticRegression()
model.fit(X_train, y_train)
 
print("훈련 데이터 점수 : {}".format(model.score(X_train, y_train)))
print("평가 데이터 점수 : {}".format(model.score(X_test, y_test)))

# 훈련 데이터 점수 : 0.9814285714285714
# 평가 데이터 점수 : 0.9766666666666667

predict = model.predict(X_test)
print("정확도 : {}".format(accuracy_score(y_test, predict)))

# 정확도 : 0.9766666666666667

 

오차 행렬(Confusion Matrix)

  • True Negative: 예측값을 Negative 값 0으로 예측했고, 실제 값도 Negative 값 0
  • False Positive: 예측값을 Positive 값 1로 예측했는데, 실제 값은 Negative 값 0
  • False Negative: 예측값을 Negative 값 0으로 예측했는데, 실제 값은 Positive 값 1
  • True Positive: 예측값을 Positive 값 1로 예측했고, 실제 값도 Positive 값 1

 

from cklearn.metrics import confusion_matrix

confmat = confusion_matrix(y_true=y_test, y_pred=predict)
print(confmat)

# [[142   7]
#  [  0 151]]

fig, ax = plt.subplots(figsize = (2.5, 2.5))
ax.matshow(confmat, cmap=plt.cm.Blues, alpha=0.3)
for i in range(confmat.shape[0]):
    for j in range(confmat.shape[1]):
        ax.text(x=j, y=i, s=confmat[i,j], va='center', ha='center')
        
plt.xlabel('predicted label')
plt.ylabel('True label')
plt.tight_layout()
plt.show()

 

정밀도(Precision)와 재현율(Recall)

  • 정밀도 = TP / (FP + TP)
  • 재현율 = TP / (FN + TP)
  • 정확도 = (TN + TP) / (TN + FP + FN + TP)
  • 오류율 = (FN + FP) / (TN + FP + FN + TP)
from sklearn.metrics import precision_score, recall_score
 
precision = precision_score(y_test, predict)
recall = recall_score(y_test, predict)
 
print("정밀도 : {}".format(precision))
print("재현율 : {}".format(recall))
 
# 정밀도 : 0.9556962025316456
# 재현율 : 1.0

 

F1 Score(F-measure)

  • 정밀도와 재현율을 결합한 지표
  • 정밀도와 재현율이 어느 한쪽으로 치우치지 않을 때 높은 값을 가짐

from sklearn.metrics import f1_score

f1 = f1_score(y_test, predict)

print("F1 Score : {}".format(f1))

# F1 Score : 0.9773462783171522

ROC 곡선과 AUC

  • ROC 곡선은 FPR(False Positive Rate)이 변할 때 TPR(True Positive Rate)이 어떻게 변하는지 나타내는 곡선
    • TPR(True Positive Rate): TP / (FN + TP), 재현율
    • TNR(True Negative Rate): TN / (FP + TN)
    • FPR(False Positive Rate): FP / (FP + TN), 1 - TNR
  • AUC(Area Under Curve) 값은 ROC 곡선 밑에 면적을 구한 값 (1이 가까울수록 좋은 값)
from sklern.metrics import roc_curve

pred_proba_class1 = model.predict_proba(X_test)[:,1]
fprs, tprs, thresholds = roc_curve(y_test, pred_proba_class1)

plt.plot(fprs, tprs, label='ROC')
plt.plot([0,1], [0,1], '--k', label='Random')
start, end = plt.xlim()
plt.xticks(np.round(np.arange(start, end, 0.1), 2))
plt.xlim(0,1)
plt.ylim(0,1)
plt.xlabel('FPR')
plt.ylabel('TPR')
plt,legend()

from sklearn.metrics import roc_auc_score

roc_auc = roc_auc_score(y_test, predict)

print("ROC AUC Score : {}".format(roc_auc))

# ROC AUC Score : 0.963309480421352

+ Recent posts