250x250
Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags more
Archives
Today
Total
관리 메뉴

Python 연습장

pipeline 본문

코딩

pipeline

포숑 2022. 1. 9. 23:26
728x90

그동안 '머신러닝 학습을 할 때 pipeline을 쓰면 간단해진다'라고 들어만 봤지 pipeline이 정확히 어떤 때에 쓰이는 건지 잘 몰라서 안 쓰고 있었다. 안 쓰더라도 남이 짠 코드는 이해를 해야 하니까 오늘 한 번 알아보도록 하겠다.

 

pipeline이란 데이터를 일련의 순서대로 처리하고 분석하는 단계를 의미한다. 데이터 분석 머신러닝의 기본 절차로 null값 처리 같은 Data Cleansing, Scaling과 같은 데이터 전처리, 주성분 분석(PCA), 머신러닝 모델 적용 등의 절차가 있는데 이 모든 과정들을 하나의 pipeline이라고 할 수 있다. 

sklearn의 pipeline은 이 절차를 깔끔하게 코드한 줄로 나타내 줄 수 있는 모듈이며 이를 한 번 적용해보도록 하겠다.

 

데이터 불러오기 

먼저 data를 불러오고, X, y를 지정해준다. X 는 iris.data, y는 iris.target or iris.target_names [iris.target]으로 지정할 수도 있다.

굳이 pd.DataFrame() 형식으로 데이터를 불러오는 건 나중에 csv 파일로 대체했을 때 코드 수정을 최소화하기 위함이다.

import pandas as pd
from sklearn.datasets import load_iris 
iris = load_iris() 
df = pd.DataFrame(data = iris.data, columns = iris.feature_names)
df['target'] = iris.target_names[iris.target] 
print(df)

X = df.iloc[:, :4]
y = df['target']

 

train test split

이번에는 train_test_split 모듈을 불러와서 데이터셋을 나눠주겠다.

글과는 크게 관련없는 이야기지만 train_test_split은 모델링 연습해볼 때나 쓰는 거지 진짜 모델을 만들고 평가할 때에는 인덱스 순서 혹은 시간 순서별로 잘라줘야 한다. random split 이 보통 더 성능이 좋게 나오기 때문이다. 

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

 

modeling

iris dataset 의 target 값은 문자로 multiclass classificaion으로 볼 수 있으니 classificaion 모델을 불러온다.

tree 모델 중에 가장 기본 모델인 DecisionTree Classifier 를 불러왔다. 

 

또한 input 값으로 들어가는 X 인자가 모두 numeric type 이므로 모두 scaling 처리를 해준다. 이때 X_test 도 scaling 해주는데, fitting 은 X_train에서 받은 값으로 하고 tranform 처리만 해준다. 혹은 X를 train test로 split 하기 전에 먼저 scaling (fit_transform) 처리를 해줘도 되는데, 내가 여러 데이터셋에 테스트해본 결과 먼저 전체에 스케일링을 하든, 뒤에 X_test에만 fitting 하여 스케일링을 하든 결괏값은 같았다. 

 

decision tree 모델에 X_train 과 y_train으로 fitting 시켜 학습시켜주고 X_test 값을 y_pred로 받아온 다음 성능평가를 한다.

from sklearn.preprocessing import MinMaxScaler
from sklearn.tree import DecisionTreeClassifier

sc = MinMaxScaler()
X_train_sc = sc.fit_transform(X_train)
X_test_sc = sc.transform(X_test)

myclf = DecisionTreeClassifier()
myclf.fit(X_train_sc, y_train)
y_pred = myclf.predict(X_test_sc)

from sklearn.metrics import accuracy_score
import numpy as np

myclf_accuracy = accuracy_score(y_test, y_pred)
print(np.round(myclf_accuracy,2))

평가결과는 0.89~0.96 범위로 나오는데, decision tree 모델의 parameter 를 fix 시키지 않았으므로 계속 다르게 나온다.

 

이 번에는 scaling 을 standard scaling으로 바꾸고, 모델을  knn 알고리즘으로 변경하여 데이터 스케일링 > 모델링 > 평가까지 진행해보자. 

다 똑같이 복사 붙여넣기하고 'sc =' 부분과 'myclf =' 부분만 변경해주면 된다.

from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

sc = StandardScaler()
X_train_sc = sc.fit_transform(X_train)
X_test_sc = sc.transform(X_test)

myclf = KNeighborsClassifier()
myclf.fit(X_train_sc, y_train)
y_pred = myclf.predict(X_test_sc)

myclf_accuracy = accuracy_score(y_test, y_pred)
print(np.round(myclf_accuracy,2))

accuracy는 0.89 로 나온다. 

 

Pipeline 적용

그런데, 이걸 매번 모델과 스케일링을 변경할 때마다 계속 복사 붙여 넣기로 입력해줘야 하는 걸까? pipeline을 활용하면 간단하게 한 줄로 줄일 수 있다.

from sklearn.pipeline import Pipeline

pipe = Pipeline([('scaler', StandardScaler()), ('model', KNeighborsClassifier())])
pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)
pipe_accuracy = accuracy_score(y_test, y_pred)
print(np.round(pipe_accuracy,2))

위와 마찬가지로 0.89의 값을 얻을 수 있다.

 

대충 개념은 알았다. 근데, Pipeline 에 들어갈 수 있는 parameter 가 어떤 게 있는 건지를 모르겠고 사이킷런 홈페이지에도 제대로 설명이 안되어있는 것 같아서 감이 안 왔다.

그래서 적용하는 예제들을 살펴보니, scaler, pca, polynomialfeatures 등이 자주 나오길래 공통점을 보니까 모두 fitting 하는 것 같다.

from sklearn.preprocessing import PolynomialFeatures
X_train_poly = PolynomialFeatures(degree=2).fit_transform(X_train)

from sklearn.decomposition import PCA
X_train_PCA = PCA(n_components = 2).fit_transform(X_train)

from sklearn.preprocessing import StandardScaler
X_train_sc = StandardScaler().fit_transform(X_train)

근데 또 완벽하게 공통점이라고 볼 수는 없는 게 알고리즘은 fit(X, y) 형태인데 pipeline에 적용되니까 어차피 sklearn에 들어있는 모듈들을 불러와서 쓰는 거니까 알아서 처리하는건가 싶다. 

그래서 pipeline 에 sklearn 에 없는 모듈인 xgboost, lightgbm, catboost 등을 불러와서 써보니까 작동한다.

(아 그전에 맥에서 xgboost 설치하려면 homebrew를 먼저 설치하고 brew install libomp라고 터미널에 입력 후에 가능하다.)

이때 type을 보면, XGBClassifier는 sklearn.XGBClassifier이고, lgbm 도 마찬가지로 sklearn.LGBMClassifier인데,  catboost는 core.~ 로 시작되어서 sklearn에 내장 혹은 연동 여부랑은 관계없이 다 가능한 것 같다.

from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
from catboost import CatBoostClassifier

model = LGBMClassifier() # XGBClassifier(), CatBoostClassifier()
pipe = Pipeline([('scaler', StandardScaler()), ('model', model) ])

 

여기서 잠깐, pipeline 은 sklearn 에도 있고, imblearn 에도 있다. 

제공하는 함수는 sklearn pipeline 이 더 다양한데, imblearn은 sampling 기능을 지원한다. 

찾아봤을 때 어디서는 sklearn pipeline 은 train, validation set 모두를 sampling 한다는데 아예 resampled 된 값이 반환되지를 않아서 모르겠다. 어쨌든 정상적으로 학습에 필요한 sampling 은 현재 버전의 sklearn (1.0.2) 에서는 안된다. 

 

from sklearn.pipeline import Pipeline as skpipe
from imblearn.pipeline import Pipeline as impipe
from sklearn.preprocessing import MinMaxScaler
from imblearn.over_sampling import RandomOverSampler

pipe1 = skpipe( [('sc',MinMaxScaler()), ('ros',RandomOverSampler())] )
pipe1.fit(juice[['PriceCH']],juice['STORE'])
resamepled = pipe1.transform(juice[['PriceCH']],juice['STORE']) 
# 불가

pipe2 = impipe( [('sc',MinMaxScaler()), ('ros',RandomOverSampler())] )
pipe2.fit(juice[['PriceCH']],juice['STORE'])
resamepled = pipe2.fit_resample(juice[['PriceCH']],juice['STORE'])
# 가능

 

 

Make pipeline

sklearn.pipeline 에는 make_pipeline도 있는데 이건 Pipeline처럼 닉네임 안 붙여주고 자동으로 소문자로 붙여주는 모듈이다. 조금 더 사용하기 편하다.

from sklearn.pipeline import make_pipeline
from xgboost import XGBClassifier

pipe = make_pipeline(StandardScaler(), XGBClassifier())

닉네임은 이런 식으로 사용된다. 나중에 파이프라인으로 모델링을 하고 나서 PCA component와 같은 중간단계를 살펴볼 수 있다. 근데 이거 말고는 따로 어떤 걸 추가로 확인할 수 있는지는 아직 못 찾았다. 나중에 추가로 업데이트하겠다.

from sklearn.pipeline import make_pipeline
from xgboost import XGBClassifier

pipe = make_pipeline(StandardScaler(), PCA(n_components=2), XGBClassifier())
pipe.fit(X_train,y_train)
comps = pipe.steps[1][1].components_
comps2 = pipe['pca'].components_
comps3 = pipe.named_steps['pca'].components_

comps, comps2, comps3는 모두 동일한 값이다.

 

다음번에 테스트할 때에는 Pipeline을 활용해서 좀 더 간단하게 모델을 구현해봐야겠다.

 

 

728x90
Comments