머신러닝_예시

가연·2025년 1월 21일

생존 여부 예측 모델링

모델링 조건

  1. 결측값이 없어야 함 : 제거 or 대표값 or 결측치를 나타내는 값(N)으로 대체
  2. 숫자가 아닌 데이터를 숫자로 변환 : 인코딩
    2-1) 정수값으로 수치화 - 라벨 인코딩
    from sklearn.preprocessing import LabelEncoder
    2-2) 값의 유무 yes/no 분류 - 원핫 인코딩
    from sklearn.preprocessing import OneHotEncoder

모델링 과정

EDA

전처리 전에 EDA 필수

전처리

  1. data.info()로 누락 데이터 확인
    중요하지 않다고 생각하면 제거
    채우고자 결정 하면 어떤 방법으로 채울지 결정
    이 때, 그 결정에 대한 합리적인 근거가 있어야함.
  • 누락된 데이터 채우기
def check_fillna(df):
	df.loc[:,"Age"].fillna(df.loc[:,"Age"].mean(), inplace=True )
	#Age 컬럼의 결측치를 train 데이터 평균값으로 채우기
    df.loc[:,"Cabin"].fillna( "N", inplace=True)
    df.loc[:,"Embarked"].fillna( "N", inplace=True)
    df.loc[:,"Fare"].fillna(0, inplace=True)
    #Cabin, Embarked, Fare 컬럼의 결측치를 정보없음의 값(N, 0)으로 채우기
    return df
  • 누락된 데이터 제거 + 불필요 데이터 제거
def drop_feature(df):
    # tree기반의 모델이 중요하다고 하는 변수 중심으로 남기고 나머지들을 제외를 하거나 수정해서 Feature를 변경
    # pandas에서 drop : axis = 0/1
    df.drop( ["PassengerId","Name","Ticket"], axis=1, inplace=True )
    return df
  1. 인코딩
    : 숫자가 아닌 컬럼의 값을 숫자로 변경. 라벨 vs 원핫
    ex/ 성별 : female/male -> 0/1, 학교 : 초/중/고.. -> 0/1/2.. , etc
def encode_feature(df):
    # Cabin : 개별의 종류가 147개
    # => EDA + 도메인 특성 이용해 앞글자 1개만 대표화
    data.loc[:,"Cabin"]=data.loc[:,"Cabin"].apply(lambda x : str(x)[:1])

    # 라벨인코딩
    cols = ["Cabin", "Sex", "Embarked"]
    for col in cols:
        le = LabelEncoder()
        le.fit(df.loc[:,col])
        df.isetitem( df.columns.get_loc(col), le.transform(df.loc[:,col]))
    return df

train/test 정확히 구별하기!!
train 데이터만 가지고 처리하고, test에서는 적용만 해야함
test 시 new/unseen 나타날 경우 train과 별개로 뒤에 새로운 룰 추가

  1. 전처리 함수 정리
def titanic_preproccessing( df ):
    df = check_fillna(df)
    df = drop_feature(df)
    df = encode_feature(df)
    # ........
    return df

학습

train, validation, test dataset

y_titanic = data.loc[:,"Survived"] #정답 분리
X_titanic = data.drop("Survived", axis=1)
train은 학습에 사용되고 valid 과 test는 평가에 사용
val은 정답을 알고 자체 평가, test은 정답을 모름

  • 데이터 분리
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(
    X_titanic, # 처리가 된 문제지
    y_titanic, # 처리가 된 정답지
    test_size = 0.2, # train 중에서 얼마를 val으로 남길지
    random_state=1234 
    stratify=y_titanic # 특정한 값의 비율을 유지하려고 할 때 추가
)
  • k번 train 검증 (k-fold)
    k-fold 에서 재현성을 가지고 동일한 비교 셋 세팅 -> 나중에 HPT 비교
    1) 일반적인 k-fold
    from sklearn.model_selection import KFold
    kfold = KFold(n_splits = 5, random_state=1234, shuffle=True)
    2) 비율을 유지하며 k-fold
    from sklearn.model_selection import StratifiedKFold
    str_kfold = StratifiedKFold(n_splits = 5, random_state=1234, shuffle=True)

cf) 데이터 수가 부족할 때 -> 데이터 펌핑한 후 진행
from sklearn.model_selection import RepeatedKFold
rkfold = RepeatedKFold(n_splits = 5, random_state=1234, n_repeats=10 )
from sklearn.model_selection import RepeatedStratifiedKFold
rskfold = RepeatedStratifiedKFold(n_splits = 5, random_state=1234, n_repeats=10)

평가

  1. 개별 모델에 대한 대략적인 성능 체크 : BaseLine
  2. 개별 모델에 대한 성능을 최대한 끌어올리는 작업 : HPT
  • RandomGridSearch : 크게 생각한 파라미터들의 조합을 추리
  • GridSearch : 좀 더 디테일한 탐색
    => 효율적인 방법 중 하나 : Bayeisan OPT + GridSearchcv 같이
  1. 실제 모의 평가 진행 : 개별 모델이 성능 최적화 잘 됐는지 체크 -> 성능이 별로면 다시 ... -> 최적의 f찾기
  2. 최적 모델 선택 : best를 찾고, 여러 모델을 종합해서 voting 시도(hard voting / soft voting : many+diversity), stacking ...
  3. 최종 test 의 문제 풀기
    train으로 처리한 기준을 그대로 적용, unseen의 경우 코드 처리(새로운 룰 추가)

학습에 필요한 모델

  • baseline : cross_val, 통으로 학습 fit / predict 평가
    from sklearn.model_selection import cross_val_score
  • 평가 : 출제자의 의도에 맞는 평가 방식으로 채점 ex/ accuracy를 기준으로 평가 or 평가 지표 직접 만들어도 됨
    from sklearn.metrics import accuracy_score
  • HPT : 시간 오래 소요됨. sklearn - RandomGridSearchCV, GridSearchCV +optuna 외부 pkg 활용까지 할 수도 있음
    from sklearn.model_selection import GridSearchCV

f를 KNN으로 가정

knn = KNeighborsClassifier(n_jobs=-1) #깡통
scores = cross_val_score(knn, X_train, y_train, cv=kfold, scoring = 'accuracy')

  • 테스트할 파라미터를 직접 지정
    (KneighborsClassifier 메뉴얼에서 확인 필요)
    parameters = {'n_neighbors' = [1,3,5,7,9,11,13,15],
    argorithm = []}

  • RGS

# 사용할 모델 세팅
knn = KNeighborsClassifier(n_jobs=-1)
# 테스트 수가 파라미터 조합 수보다 작아야 함
n_iter = 10
# RSCV 세팅 : 모델 - 지정한 파라미터 dict 넣어주기
knn_kf_rgs = RandomizeSearchCV(knn, param_distributions=parameters, 
cv=kfold, scoring = "accuracy", n_iter = n_iter, random_stats = 1234, # 재현성
n_jobs = -1)
  • 실제 데이터로 학습
    knn_kf_rgs.fit(X_train, y_train)
  • 수행 결과
    knn_kf_rgs.cv_results_

최적의 조합 찾기
knn_kf_rgs.best_score_
knn_kf_rgs.best_params_
가장 좋은 성능의 모델을 val로 자체평가
knn_kf_rgs_best = knn_kf_rgs.best_estimator
knn_kf_rgs_ypred = knn_kf_rgs_best.predict(X_val)
knn_kf_rgs_acc = accuracy_score(y_val, knn_kf_rgs_ypred) #채점
print(knn_kf_rgs_acc)
-> 값이 떨어질 경우 overfit 의심.. 알고리즘 x 파라미터 조절

  • best parameter 주변으로 더 디테일하게 찾아보기
    => GridSearchCV (GS)
# 1.테스트할 파라미터들 세팅!!!
parameters ={
    "n_neighbors" : [19,17,21], # 3
    "algorithm":["auto","ball_tree","kd_tree"] # 3
    # --> GS : 3*3=9가지 경우 모두다 실험!!!!
}
# 2. 사용할 모델
knn = KNeighborsClassifier(n_jobs=-1)
# 3. 직접 모든 파라미터들을 다 해주는 GridSearchCV ==> 하나의 모델
knn_kf_gs = GridSearchCV(
    knn,
    param_grid=parameters,
    cv = kfold,
    scoring="accuracy",
    ####
    n_jobs= -1
)
# 4. 실제 데이터를 넣어서 학습
knn_kf_gs.fit(X_train, y_train)

knn_kf_gs.cv_results_ 로 아까 찾은 best model과 비교하여 선택

f를 RF으로 가정

https://scikit-learn.org/1.5/modules/generated/sklearn.ensemble.RandomForestClassifier.html

from sklearn.ensemble import RandomForestClassifier

  • Baseline
rf = RandomForestClassifier( n_jobs=-1, random_state=1234)
scores = cross_val_score( rf,
                         X_train,y_train,
                          cv=kfold,scoring="accuracy")

로 대략 accuracy 구하기

-> 세부 parameter 조절
accuracy가 더 높게 나오도록 파라미터 조절하며 RF 최적화

  • RGS
rf = RandomForestClassifier( n_jobs=-1, random_state=1234)
# test할 parameter 선정
parameters ={
    # RF : Bagging -> 여러 모델의 종합 => 몇 개의 모델을 활용할 것인가? ( 너무 많으면 오래 걸림 )
    "n_estimators" : [10,30,50,70,100,200,300,500,1000,2000],
    # ==> many(col 어떻게 구성할지) + Diversity
    "max_features" : [3,4,5,6,7],

	# 개별 decision tree의 overfit을 조절하는 parameter
	"max_depth" : [2,3,4,5,6,7,8,10]
	"min_samples_split": [1,3,5,7,9]
	# Bias에서 좀 손해보더라도 Variance 확보 -> New 일반성

# RGS
n_iter = 20
rf_kf_rgs = RandomizeSearchCV(rf, param_distributions = parameters, cv = kfold, n_iter = n_iter, randomstate = 1234, scoring = "accuracy", n_jobs = -1)
  • 실제 데이터 넣고 학습
    rf_kf_rgs.fit(X_train, y_train)
    rf_kf_rgs.cv_results_ #전체결과
    rf_kf_rgs.best_score_ #가장높은성과
    rf_kf_rgs.best_params_ #그때의파라미터
  • RGS 모의 성능 평가
    rf_kf_rgs_best = rf_kf_rgs.best_estimator_
    rf_kf_rgs_ypred = rf_kf_rgs_best.predict(X_val)
    rf_kf_rgs_acc = accuracy_score(y_val, rf_kf_rgs_ypred)
  • GS
    RGS의 best parameter 주변으로 좀 더 디테일하게 찾기
rf = RandomForestClassifier(n_jobs=-1, random_state=1234)
parameters = {
    "n_estimators": [70, 50, 100,500],
    "max_features" :[7,6,5],
    "max_depth" :[3,4,5],
    #"min_samples_split":[4,5,6] 
    # ==> 4*3*3*3 = 27*4 = 1XX * cv5 = 5XX
}
rf_kf_gs = GridSearchCV(
    rf, param_grid=parameters,
    cv=kfold, scoring="accuracy",
    n_jobs=-1
)
rf_kf_gs.fit(X_train,y_train)

마찬가지로 성능 평가
rf_kf_gs.best_score_
rf_kf_gs.best_params_
#val에 대해 평가
rf_kf_gs_best = rf_kf_gs.best_estimator_
rf_kf_gs_ypred = rf_kf_gs_best.predict(X_val)
rf_kf_gs_acc = accuracy_score(y_val, rf_kf_gs_ypred)

-> RGS와 GS중 score 비교하여 선택

저장

import joblib
joblib.dump(rf_kf_best, "rf_kf_best.pkl") #저장

model_path = '/content/rf_kf_best.pkl' #열기
rf_backup = joblib.load(model_path)

*** OS가 다른 상황에서는 pickle 사용

import pickle
filename = "my_model.pkl" #저장
pickle.dump(rf_kf_gs_best, open(file_name,"wb")
model_path = '/content/my_model.pkl' #열기

* # 간단하게 불러온 게 동일한지 체크
(rf_kf_gs_best.predict(X_val) != rf_backup.predict(X_val)).sum()

f가 xgboost으로 가정

* colab에 이미 설치되어있음
xgboost - scikit api
https://xgboost.readthedocs.io/en/stable/python/python_api.html#module-xgboost.sklearn

  • baseline
    xgbc = XGBClassifier(n_jobs=-1, random_state=1234)
    scores = cross_val_score( xgbc, X_train,y_train,
    cv=kfold, scoring="accuracy")
    ** boosting 계열 알고리즘은 주된 파라미터를 제외하고는 튜닝에 의해 크게 차이가 나지 않음. 세부 파라미터까지 볼 필요 없음.

  • RGS

xgbc = XGBClassifier(n_jobs=-1, random_state=1234)
#test parameter 설정
parameters = {
    "n_estimators" : [10,30,50,100,300,500],
    "learning_rate" : [0.01, 0.1, 0.2, 0.3],
	#개별 모델 조절
	#인위적으로 트리 조절 - 깊이
	"max_depth" : [2,3,4,5,6,10],
	#더 분할할 지 - 너비
	"gamma" : [0.1, 0.2, 0.3],

	#OF risk 피하기 -> 샘플링 *가로*/세로 둘 다 사용 = RF 의 		max_feature + max_sample
	"subsample" : [ ] #가로 비율
	"colsample_bytree" : [ ] #세로 비율
	}
n_iter = 100
xgbc_kf_rgs = RandomizedSearchCV(
    xgbc,
    param_distributions=parameters,
    cv = kfold,
    scoring="accuracy",
    n_iter= n_iter,
    random_state=1234,
    n_jobs=-1
)
xgbc_kf_rgs.fit(X_train, y_train)
  • 결과 자체 평가
    xgbc_kf_rgs.best_score_
    xgbc_kf_best = xgbc_kf_rgs.best_estimator_
    xgbc_kf_ypred = xgbc_kf_best.predict(X_val)
    xgbc_kf_acc = accuracy_score(y_val,xgbc_kf_ypred )
  • GS
parameters= {
    "subsample": [0.4, 0.3],
    "n_estimators":[300,250,500],
    "max_depth":[2,3],
    "learning_rate":[0.01, 0.005, 0.02],
    "gamma" : [0.2, 0.15, 0.25],
    "colsample_bytree":[0.6, 0.5]
} # 2 * 3 * 2* 3* 3* 2
xgbc = XGBClassifier(n_jobs=-1, random_state=1234)
xgb_kf_gs = GridSearchCV(
    xgbc,
    param_grid=parameters,
    cv=kfold,
    scoring="accuracy",
    n_jobs=-1 # verbose 파라미터를 사용하여 중간 결과 모니터링
)
xgb_kf_gs.fit(X_train,y_train)

GS 평가
xgb_kf_gs.best_score_
xgb_kf_gs_best = xgb_kf_gs.best_estimator_
xgb_kf_gs_ypred = xgb_kf_gs_best.predict(X_val)
xgb_kf_gs_acc = accuracy_score(y_val, xgb_kf_gs_ypred)

=> RGS 와 GS score 비교하여 선택

f가 lightGBM으로 가정

xgboost랑 비슷. 속도가 좀 더 빠름.
https://lightgbm.readthedocs.io/en/v4.5.0/pythonapi/lightgbm.LGBMClassifier.html#lightgbm.LGBMClassifier
from lightgbm import LGBMClassifier

  • baseline
lgmc = LGBMClassifier( n_jobs=-1, random_state=1234)
scores = cross_val_score(lgmc, X_train, y_train,
                         cv=kfold, scoring="accuracy")
  • HPT
lgmc = LGBMClassifier(n_jobs=-1, random_state=1234)
parameters ={
    # 부스팅 관련된 주된 파라미터
    # 1) 몇 개의 모델을 사용할지...
    "n_estimators":[10,30,50,100,300,500],
    # 2) 어느 정도의 비율로 반영할지 lr
    "learning_rate":[0.01, 0.03, 0.05, 0.1, 0.3],

    # 개별 모델 : tree --> overfit
    "max_depth" : [2,3,4],
    "min_split_gain":[0.1, 0.2], # --> xgboost에서 gamma와 유사한 기능

    # 샘플링
    "subsample":[0.3, 0.5, 0.7, 0.9],
    "colsample_bytree":[0.3, 0.5, 0.7, 0.9]
    # 기타 : 규약
    
n_iter = 10
lgmc_kf_rgs = RandomizedSearchCV(
    lgmc,
    param_distributions = parameters,
    cv = kfold,
    n_iter = n_iter,
    scoring="accuracy",
    n_jobs=-1,
    random_state=1234
)
lgmc_kf_rgs.fit(X_train, y_train)
  • 평가
    lgmc_kf_rgs.best_score_
    lgmc_kf_rgs.best_params_
    lgmc_kf_rgs_best = lgmc_kf_rgs.best_estimator_
    lgmc_kf_rgs_ypred = lgmc_kf_rgs_best.predict(X_val)
    lgmc_kf_rgs_acc = accuracy_score(y_val, lgmc_kf_rgs_ypred)

f가 GridsearchCV일 때

혼자 해보기!

최종 모델 선정

KNN, RF, XGBoost, lightGBM 의 성능을 비교하며 최종 모델 선택

  • Voting 함수 사용
    - Hard Voting (1인 1표)
    		hard_clf = VotingClassifier(
    	# 어떤 모델들을 가지고 다수결을 할지 : 튜플로 개별 모델 -> 리스트
        estimators = [
            ("RF", rf_kf_gs_best),
            ("XGB",xgb_kf_gs_best),
            ("LGBM",lgmc_kf_rgs_best)
        ],
        # 어떤 방식으로 의견을 종합할지
        voting="hard",
        n_jobs=-1
        )
    		hard_clf.fit(X_train, y_train)
    		hard_clf_ypred = hard_clf.predict(X_val)
    		hard_clf_acc = accuracy_score(y_val, hard_clf_ypred)
    		```
    		- Soft Voting (1인 다표)
    		``` python
    soft_clf = VotingClassifier(
        # 어떤 모델들을 가지고 다수결 할지
        estimators = [
            ("RF", rf_kf_gs_best),
            ("LGBM",lgmc_kf_rgs_best)
        ],
        # 어떤 방식으로 의견 종합할지
        voting="soft",
        # 가중치 설정 !!!
        weights = [1, 2],
        n_jobs=-1
    )
    soft_clf.fit(X_train, y_train)
    soft_clf_ypred = hard_clf.predict(X_val)
    soft_clf_acc = accuracy_score(y_val, soft_clf_ypred)
    		```
    
    => 결과 acc 비교하여 모델 선정

0개의 댓글