본문 바로가기
Machine Learning

scikit-learn의 Getting Started 따라하기

by AlbertIm 2024. 7. 25.

Scikit-learn

Scikit-learn은 지도 및 비지도 학습을 지원하는 오픈소스 머신러닝 라이브러리입니다. 또한 모델 피팅, 데이터 전처리, 모델 선택, 모델 평가 및 기타 여러 유틸리티를 위한 다양한 도구를 제공합니다.

기능

1.피팅(Fitting) 및 예측(predicting): 추정기(estimator) basics

Scikit-learn은 추정기라고 불리는 수십 개의 built-in 머신러닝 알고리즘과 모델을 제공합니다. 각 추정기는 fit 메서드를 사용하여 일부 데이터를 fitted할 수 있습니다.

estimator

이 객체는 모델의 추정 및 디코딩을 관리합니다.

fit

모든 추정기에는 fit 메소드가 제공됩니다. 이 메소드는 일반적으로 샘플 X, 모델이 감독 학습(supervised learning)인 경우 목표 y, 그리고 경우에 따라 샘플 속성(예: sample_weight)을 인수로 받습니다. fit 메소드는 다음과 같은 작업을 수행해야 합니다:

 

  1. 이전 속성 초기화: warm_start가 사용되지 않는 한 추정기에 저장된 이전 속성을 모두 지워야 합니다.
  2. 매개변수 검증 및 해석: 매개변수를 검증하고 해석하며 유효하지 않은 경우에는 오류를 발생시켜야 합니다.
  3. 입력 데이터 검증: 입력 데이터를 검증해야 합니다.
  4. 모델 속성 추정 및 저장: 추정된 매개변수와 제공된 데이터를 기반으로 모델 속성을 추정하고 저장해야 합니다.
  5. 체이닝을 위한 추정기 반환: 이제 맞춰진(fitted) 추정기를 반환하여 메소드 체이닝을 용이하게 해야 합니다.
# 피팅 및 예측: 추정기 기본 사항
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(random_state=0)
X = [[ 1,  2,  3],  # 2 samples, 3 features
     [11, 12, 13]]
y = [0, 1]  # classes of each sample
clf.fit(X, y)

fit 메소드는 일반적으로 두 가지 입력을 받습니다

  1. 샘플 행렬 (또는 디자인 행렬) X: X의 크기는 일반적으로 (n_samples, n_features)이며 이는 샘플이 행으로 특성이 열로 표현된다는 의미입니다.
  2. 목표 값 y: 회귀 작업의 경우 y는 실수(real numbers)이고 분류 작업의 경우 y는 정수(integers) 또는 다른 이산 값(discrete values)이 됩니다.

비지도 학습(unsupervised learning) 작업에서는 y를 지정할 필요가 없습니다. y는 일반적으로 1차원 배열(1d array)이며 i 번째 항목은 X의 i 번째 샘플(행)의 목표를 나타냅니다.

 

X와 y는 일반적으로 numpy 배열 또는 유사한 배열 형식의 데이터 타입으로 예상되지만 일부 추정기는 희소 행렬(sparse matrices)과 같은 다른 형식도 처리할 수 있습니다.

 

추정기가 한 번 학습(fitted)되면 새로운 데이터의 목표 값을 예측하는 데 사용할 수 있습니다. 추정기를 다시 학습시킬 필요는 없습니다

 

clf.predict(X)  # 훈련 데이터의 클래스 예측
# 결과: array([0, 1])

# 위에서 [1,2,3] == 0,[11,12,13] == 1로 학습했기에
# [4,5,6] == 0, [14,15,16] == 1 을 예상한다.
clf.predict([[4, 5, 6], [14, 15, 16]])  # 새로운 데이터의 클래스 예측
# 결과: array([0, 1])

 

학습한 데이터 부족해서 [21,22,23] == 1 나온 것 같습니다.

# 새로운 데이터의 클래스 예측
clf.predict([[17,18,19], [21,22,23]])  
# 결과: array([1, 1])

 

[21,22,23]도 학습해봅니다.

clf.fit([[21,22,23]],[2])
# [17,18,19] == 2로 표시된다
clf.predict([[17,18,19], [21,22,23]])
# 결과: array([2, 2])

 

추가로 더 학습해봅니다.

clf.fit([[17,18,19],[31,32,33]],[1,3])
# 예측 [41,42,42] == 3  X
clf.predict([[41,42,43], [17,18,19]])
# 결과: array([3, 1])

 

추가로 더 학습해봅니다.

clf.fit([[61,62,65],[73,72,71],[100,105,106]],[6,7,10])
clf.predict([[41,42,43], [17,18,19]])
# 결과: array([6, 6])

 

값이 모두 6이다. fit가 실행하면 값이 초기화한다고 의심이 됩니다.
원인혹인 이전 속성 초기화: warm_start가 사용되지 않는 한 추정기에 저장된 이전 속성을 모두 지워야 합니다.
잘 안됩니다. 충분한 데이터가 필요할 것 같습니다.

newClf = RandomForestClassifier(random_state=0)

newX = [[ 1,  2,  3],
        [11, 12, 13],
        [21,22,23],
        [17,18,19],
        [31,32,33],
        [61,62,65],
        [73,72,71],
        [100,105,106]]
newY = [0,1,2,1,3,6,7,10]  # classes of each sample

newClf.fit(newX, newY)

# 예측
newClf.predict([[41,42,43], [17,18,19]])
# array([3, 1])

 

예측을 위해서는 생각보다 충분히 많은 데이터가 필요할 것 같고 RandomForestClassifier는 스스로 추가로 학습하는 기능이 없는 것 같습니다.

2. 변화기(Transformers) 및 전처리기(pre-precessors)

scikit-learn에서 전처리기와 변환기는 추정기 객체와 동일한 API를 따릅니다 (실제로 모두 BaseEstimator 클래스에서 상속받습니다). 변환기 객체는 predict 메소드를 가지지 않고 대신 transform 메소드를 제공하여 새롭게 변환된 샘플 행렬 X를 출력합니다.

 

(표준편차란? 표준편차에 대한 이해를 높일 수 있는 블로그입니다.)

from sklearn.preprocessing import StandardScaler
X = [[0,15],
     [1,-10]]

StandardScaler().fit(X).transform(X)
# 결과: array([[-1.,  1.],[ 1., -1.]])

3. 파이프라인: 전처리기 및 추정기 연결

변환기(transformers)와 추정기(estimators, 예측기)는 하나의 통합 객체인 파이프라인(Pipeline)으로 결합될 수 있습니다. 파이프라인은 일반 추정기와 동일한 API를 제공하며 fit과 predict 메소드를 사용하여 학습 및 예측을 수행할 수 있습니다. 이후에 보게 되겠지만 파이프라인을 사용하면 데이터 누수(data leakage)를 방지할 수 있습니다. 즉, 테스트 데이터를 학습 데이터에 포함시키는 것을 방지할 수 있습니다.

Iris 데이터셋의 구성

  • 샘플: 150개의 샘플(꽃의 종류)
  • 특성: 4개의 특성
    • 꽃받침 길이 (sepal length): cm 단위
    • 꽃받침 폭 (sepal width): cm 단위
    • 꽃잎 길이 (petal length): cm 단위
    • 꽃잎 폭 (petal width): cm 단위
  • 클래스 레이블: 3개의 품종
    • Iris setosa
    • Iris versicolor
    • Iris virginica

각 품종은 50개의 샘플로 구성되어 있으며 각 샘플은 4개의 특성을 가집니다

from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# create a pipeline object
pipe = make_pipeline(
    StandardScaler(),
    LogisticRegression()
)
# Iris 데이터셋 로드
X, y = load_iris(return_X_y=True)
# 데이터를 학습 데이터와 테스트 데이터로 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# 전체 파이프라인 학습
pipe.fit(X_train, y_train)
# 이제 우리는 그것을 다른 추정기(estimator)처럼 사용할 수 있습니다.
# 정확도 점수 측정
accuracy_score(pipe.predict(X_test), y_test)
# 결과: 0.9736842105263158

4. 모델 평가

모델을 일부 데이터에 맞춘다고 해서 그 모델이 학습하지 않는 데이터에서도 잘 예측할 것이라고 보장할 수는 없습니다. 이를 직접적으로 평가해야 합니다. scikit-learn은 모델 평가, 특히 교차 검증을 위한 다른 많은 도구를 제공합니다.

 

여기서는 5-fold cross-validation 절차를 cross_validate 도구를 사용하여 수행하는 방법을 간략히 설명합니다. 또한 폴드를 수동으로 반복하거나 다양한 데이터 분할 전략을 사용하거나 사용자 정의 평가 함수를 사용할 수도 있습니다.

from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_validate
X, y = make_regression(n_samples=1000, random_state=0) # 회귀 분석을 위한 데이터셋 생성 (1000개의 샘플)
lr = LinearRegression() # 선형 회귀 모델 생성
result = cross_validate(lr, X, y)  # 모델에 대해 5-폴드 교차 검증 수행,기본값으로 5-폴드 교차 검증을 수행
result['test_score'] # 검증 데이터에 대한 성과 점수 출력 (r_squared 점수가 높은 이유는 데이터셋이 쉬운 문제이기 때문이다)
# 결과: array([1., 1., 1., 1., 1.])

5. 자동 매개변수 검색

모든 추정기는 조정할 수 있는 매개변수(문헌에서는 종종 하이퍼파라미터라고 부름)를 가지고 있습니다. 추정기의 일반화 성능은 종종 몇 가지 매개변수에 의해 크게 영향을 받을 수 있습니다. 예를 들어 RandomForestRegressor는 n_estimators라는 매개변수를 가지며 이는 숲 속의 나무 개수를 결정합니다. 또한 max_depth라는 매개변수도 있으며 이는 각 나무의 최대 깊이를 결정합니다. 이러한 매개변수의 정확한 값이 무엇인지 결정하는 것은 데이터에 따라 달라지기 때문에 종종 명확하지 않습니다.

 

Scikit-learn은 교차 검증을 통해 최적의 매개변수 조합을 자동으로 찾는 도구를 제공합니다. 다음 예제에서는 RandomizedSearchCV 객체를 사용하여 랜덤 포레스트의 매개변수 공간을 무작위로 검색합니다. 검색이 완료되면 RandomizedSearchCV는 최상의 매개변수 세트로 훈련된 RandomForestRegressor처럼 동작합니다.

from sklearn.datasets import fetch_california_housing
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import train_test_split
from scipy.stats import randint

# 캘리포니아 주택 데이터셋을 로드합니다.
X, y = fetch_california_housing(return_X_y=True)

# 데이터를 훈련 세트와 테스트 세트로 분할합니다.
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

# 탐색할 하이퍼파라미터 공간을 정의합니다.
# 랜덤 포레스트의 나무 수 (1부터 5까지의 정수 중 무작위 선택)
param_distributions = {'n_estimators': randint(1, 5), 
                        # 각 나무의 최대 깊이 (5부터 10까지의 정수 중 무작위 선택)
                       'max_depth': randint(5, 10)} 

# RandomizedSearchCV 객체를 생성하고 데이터를 사용하여 적합(fit)합니다.
search = RandomizedSearchCV(estimator=RandomForestRegressor(random_state=0), # 사용할 모델
                            n_iter=5, # 시도할 하이퍼파라미터 조합의 수
                            param_distributions=param_distributions, # 하이퍼파라미터 공간
                            random_state=0) # 난수 시드

search.fit(X_train, y_train) # 훈련 데이터에 적합(fit)시킵니다.

search.best_params_ # 최적의 하이퍼파라미터 조합을 출력합니다.

# 이제 search 객체는 최적의 하이퍼파라미터로 훈련된 랜덤 포레스트 추정기처럼 동작합니다.
# 테스트 데이터에 대한 성능을 평가합니다.
search.score(X_test, y_test)
# 결과: 0.735363411343253

마무리

scikit-learn의 Getting Started를 따라하면서 피팅 및 예측, 변환기 및 전처리기, 파이프라인, 모델 평가, 자동 매개변수 검색 등 다양한 기능을 사용해 보았습니다. 사용 방법은 쉽지만 그 원리를 이해하는 데는 어려움이 있습니다. 아직도 이해하지 못한 부분이 남아 있으며 이 부분은 나중에 ML 관련 책을 읽어보면서 보충해야 할 것 같습니다.

'Machine Learning' 카테고리의 다른 글

머신러닝의 기본 개념  (0) 2024.07.24

댓글