머신러닝의 기본적인 스텝

포동동·2022년 5월 16일
0
post-thumbnail

처음 배우는 사람이고, 정확하지 않겠지만, 과제를 수행하고 스스로 kaggle에 도전하기 위해 (즉, 내가 보려고) 기본적인 스텝을 한 번 정리해보겠다.

<지도학습분류문제의 경우>

1. 전처리

2. 타겟, 피쳐 분리

3. train, (validation set), test set 분리

4. Baseline 설정 및 성능확인

5. train set으로 모델 학습

6. 모델 성능 확인

7. 모델 성능 개선

8. test set으로 확인


기본적인 스텝은 위와 같고, 아래는 자세한 코드와 함께 정리해두겠다.


1. 전처리

⭕⭕⭕
null값, 이상치, 정보 누수, 범주형/수치형 데이터 처리, 로그 변환 등의 정리를 잘 해줘야 성능이 좋아지기 때문에 신경써서 할 것!
⭕⭕⭕


2,3. 타겟, 피쳐 분리 + train/val/test set 분리

def get_train_test_dataset(df=None):
    from sklearn.model_selection import train_test_split 

    target = '타겟'
    y_target = df[target]
    X_features = df.drop(columns=target)
    
    # train, test 분할
    X_train, X_test, y_train, y_test = train_test_split(X_features, y_target, test_size=0.2, stratify=y_target)
    # train, val 분할
    X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.2, stratify=y_train)
    
    return X_train, X_val, X_test, y_train, y_val, y_test

X_train, X_val, X_test, y_train, y_val, y_test = get_train_test_dataset(df)
print(X_train.shape, X_val.shape, X_test.shape, y_train.shape, y_val.shape, y_test.shape)

4. Baseline 설정 및 성능확인 + target의 클래스 비율 확인

from sklearn.metrics import accuracy_score

#기준모델 설정
major = y_train.mode()[0]
y_pred_base = [major] * len(y_train)

#기준모델 성능 확인
print("baseline의 정확도: ", accuracy_score(y_train, y_pred_base))

#target의 클래스 비율 확인
1_cnt = df['타겟'].value_counts()[1]
total_cnt = df['타겟'].count()
print('맞추고 싶은 클래스의 비율은 {0:.2f}'.format((1_cnt / total_cnt)))

5. train set으로 모델 학습

모델을 잘 선택해야함. 그 데이터가 가지고 있는 성질을 확인해서 아래 중에서 잘 선택해서 해 볼 것.

  • LogisticRegression
  • DecisionTreeClassifier(Bagging기법)
  • RandomForestClassifier(Bagging기법)
  • XGBClassifier(Boosting기법)
  • LGBMClassifier(Boosting기법)
    등등

로지스틱 회귀

lr_clf = LogisticRegression()
lr_clf.fit(X_train , y_train)
pred = lr_clf.predict(X_test)
accuracy = accuracy_score(y_test, pred)
print('로지스틱 회귀 정확도: {0:.4f}'.format(accuracy))

결정 트리

dt_clf = DecisionTreeClassifier(n_estimators=100, random_state=0, max_depth=8)
dt_clf.fit(X_train , y_train)
pred = dt_clf.predict(X_test)
accuracy = accuracy_score(y_test , pred)
print('랜덤 포레스트 정확도: {0:.4f}'.format(accuracy))

랜덤 포레스트

rf_clf = RandomForestClassifier(n_estimators=100, random_state=0, max_depth=8)
rf_clf.fit(X_train , y_train)
pred = rf_clf.predict(X_test)
accuracy = accuracy_score(y_test , pred)
print('랜덤 포레스트 정확도: {0:.4f}'.format(accuracy))

XGB

xgb_wrapper = XGBClassifier(n_estimators=400, learning_rate=0.05, max_depth=3, eval_metric='logloss')
xgb_wrapper.fit(X_train, y_train, verbose=True)
pred = xgb_wrapper.predict(X_test)
accuracy = accuracy_score(y_test , pred)
print('XGB 정확도: {0:.4f}'.format(accuracy))

LGBM

lgbm_wrapper = LGBMClassifier(n_estimators=400, learning_rate=0.05)
lgbm_wrapper.fit(X_tr, y_tr, early_stopping_rounds=50, eval_metric="logloss", 
                 eval_set=evals, verbose=True)
pred = lgbm_wrapper.predict(X_test)
accuracy = accuracy_score(y_test , pred)
print('LGBM 정확도: {0:.4f}'.format(accuracy))

6. 모델 성능 확인

데이터의 성질과 타겟값의 비율 등을 고려해서 아래 중에서 어떤 걸 중요하게 볼 것인가를 신경쓸 것.

  • accuracy
  • precision
  • recall
  • f1 score
  • auc
from sklearn.metrics import accuracy_score, precision_score , recall_score, f1_score, from sklearn.metrics import roc_auc_score

confusion = confusion_matrix(y_test, pred)
accuracy = accuracy_score(y_test , pred)
precision = precision_score(y_test , pred)
recall = recall_score(y_test , pred)
f1 = f1_score(y_test , pred)
roc_score = roc_auc_score(y_test, pred_proba)

(교차검증)

  • KFold
  • Stratifiedflod
  • cross_val_score() *거의 stratifiedfold 하는 경우가 많음

7. 모델 성능 개선

적당한 모델을 선택했으면, 각각의 하이퍼 파라미터를 최적화해서 성능을 더 끌어올려야 한다. 쓸 수 있는 방법은 아래와 같다.

  • RandomSearchCV
  • GridSearchCV
  • 베이지안 최적화(HyperOpt)

RandomSearchCV

dists = {
    '모델 인스턴스__n_estimators': randint(50, 500), 
    '모델 인스턴스__max_depth': [4, 5, 6, 8, 10, 15], 
    '모델 인스턴스__max_features': [3,5,8,10,15]
}

clf = RandomizedSearchCV(
    pipe, 
    param_distributions=dists, 
    n_iter=50, 
    cv=3, 
    scoring='f1', 
    refit=True, 
    verbose=1,
    n_jobs=-1
)

clf.fit(X_train, y_train)

print('RandomizedSearchCV 최적 하이퍼파라미터: ', clf.best_params_)
print('RandomizedSearchCV 최고 정확도: {0:.4f}'.format(clf.best_score_))

#쓸 수 있는 Attribute
clf.best_score_
clf.best_params_
clf.cv_results_
clf.best_estimator_

GridSearchCV

params = {
    '모델 인스턴스__max_depth': [8, 16, 24],
    '모델 인스턴스__min_samples_leaf' : [1, 6, 12],
    '모델 인스턴스__min_samples_split' : [2, 8, 16]
}
grid_cv = GridSearchCV('모델 인스턴스', param_grid=params, scoring='accuracy', cv=5, verbose=1) #refit=True는 주의해서!

grid_dtree.fit(X_train, y_train)
print('GridSearchCV 최적 파라미터:', grid_dtree.best_params_)
print('GridSearchCV 최고 정확도: {0:.4f}'.format(grid_dtree.best_score_))

#쓸 수 있는 Attribute
grid_cv.best_score_
grid_cv.best_params_
grid_cv.cv_results_
grid_cv.best_estimator_

그래도 성능이 안 나오면

특성 중요도를 확인하고 특성을 제거해주는 것도 방법임.


특성 중요도 확인

  • featureimportance
  • permutationimportance

feature importance(pipe line 썼을 때)

tree_feature_importances = (rf.named_steps['classifier'].feature_importances_)
sorted_idx = tree_feature_importances.argsort()

#시각화
y_ticks = np.arange(0, len(feature_names))
fig, ax = plt.subplots()
ax.barh(y_ticks, tree_feature_importances[sorted_idx])
ax.set_yticklabels(feature_names[sorted_idx])
ax.set_yticks(y_ticks)
ax.set_title("Random Forest Feature Importances (MDI)")
fig.tight_layout()
plt.show()

#다른 방법
model_dt = pipe.named_steps['decisiontreeclassifier']
enc = pipe.named_steps['onehotencoder']
encoded_columns = enc.transform(X_val).columns

importances = pd.Series(model_dt.feature_importances_, encoded_columns)
plt.figure(figsize=(10,30))
importances.sort_values().plot.barh();

permulation importance(pipe line 안 썼을 때)

result = permutation_importance(rf, X_test, y_test, n_repeats=10, random_state=42, n_jobs=2)
sorted_idx = result.importances_mean.argsort()

#시각화
fig, ax = plt.subplots()
ax.boxplot(result.importances[sorted_idx].T,
           vert=False, labels=X_test.columns[sorted_idx])
ax.set_title("Permutation Importances (test set)")
fig.tight_layout()
plt.show()

그 외에도 전처리 단계에서 아래와 같은 방법을 사용.

인코더 바꾸기

  • TargetEncoder
  • LabelEncoder
  • OnehotEncoder
  • OrdinalEncoder

기본문법

from sklearn.preprocessing import LabelEncoder

# 라벨인코더 선언 및 Fitting
le = LabelEncoder()
le.fit(categorical_data)

# 인코딩한 데이터로 변환
le_encoded = le.transform(categorical_data)

데이터 스케일링

Train Data에만 해야함!

Standard Scaling

from sklearn.preprocessing import StandardScaler
# StandardScaler 선언 및 Fitting
sdscaler = StandardScaler()
sdscaler.fit(numeric_data)

# 데이터 변환
sdscaled_data = sdscaler.transform(numeric_data)

# 데이터 프레임으로 저장
sdscaled_data = pd.DataFrame(sdscaled_data)

Min-Max Scaling

from sklearn.preprocessing import MinMaxScaler

# MinMaxScaler 선언 및 Fitting
mMscaler = MinMaxScaler()
mMscaler.fit(numeric_data)

# 데이터 변환
mMscaled_data = mMscaler.transform(numeric_data)

# 데이터 프레임으로 저장
mMscaled_data = pd.DataFrame(mMscaled_data)

결측치 처리

SimpleImputer(strategy='대체할 값')
'mean', 'median' -> 수치형 데이터
'most_frequent'-> 범주형 데이터

from sklearn.impute import SimpleImputer
# 평균으로 Imputer 선언
imputer_mean = SimpleImputer(strategy='mean')
imputer_mean.fit(numeric_data)
# 데이터 변환 (array로 반환하기 때문에 필요에 맞는 형태로 변환 후 사용)
numeric_data = imputer_mean.transform(numeric_data)

이상치 제거

#함수 쓸 때
def get_outlier(df=None, column=None, weight=1.5):

    '타겟 1값' = df[df['타겟']==1][column]
    quantile_25 = np.percentile('타겟 1값'.values, 25)
    quantile_75 = np.percentile('타겟 1값'.values, 75)

    iqr = quantile_75 - quantile_25
    iqr_weight = iqr * weight
    lowest_val = quantile_25 - iqr_weight
    highest_val = quantile_75 + iqr_weight
   
    outlier_index = '타겟 1값'[('타겟 1값' < lowest_val) | ('타겟 1값' > highest_val)].index
    return outlier_index
 
 df.drop(outlier_index, axis=0, inplace=True)
 
#함수 안 쓰면
q1_a=df['타겟'].quantile(0.25)
q3_a=df['타겟'].quantile(0.75)
iqr=q3_a-q1_a

condition=(df['타겟'] > q3_a + 1.5*iqr) | (df['타겟'] < q1_a + 1.5*iqr)
a=df[condition].index
df.drop(a,inplace=True)


성능이 안 나온다💢💥💦

  • 모델을 바꾼다.
  • 하이퍼파라미터를 바꾼다.
  • 전처리를 다시한다(랜글링, 이상치 제거 등).
  • 특성 중요도를 확인한다.
  • 교차검증을 더 빡세게 한다.
profile
완료주의

0개의 댓글