광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ
반응형

예… 그… 펭귄 데이터입니다. 그건 아는데 이걸 왜 꺼냈냐… 분류 할거라서 꺼냈습니다. 예. 아니 진짜 할거임.


전처리 하기 전에...

그냥 EDA였으면 범주화하고 결측값 확인하고 채우거나 날리거나 했을텐데, 이번에는 그렇게 하고 땡 하면 안된다. 왜냐… 무작정 아무 칼럼이나 학습하는데 썼다간 모델 성능이 떨어지거든요. 그리고 범주형 칼럼중에 학습에 쓸 칼럼은 인코딩도 해 줘야 한다.

 

학습에 쓸 수 없는 칼럼 날리기

내 일일이 올리기 귀찮아서 올리지는 않는다만... 분석하기 전에 항상 .head()랑 .column 써서 뭐 있는지 보고 가죠? shape는 잘 안씀... 아무튼. 거기서 칼럼들을 확인해보고 우선 날릴 것부터 정할거다.

# Copy
penguin_drop = penguin.copy()

# 하고 날려날려 칼럼
penguin_drop.drop(['studyName','Sample Number','Region','Individual ID','Clutch Completion', 'Comments', 'Date Egg', 'Stage'], axis=1, inplace=True)
penguin_drop.head()

이걸 날리는 이유는 되게 간단하다. 학습에 도움이 안 돼서.

 

결측값 채우기

sns.kdeplot(penguin_drop['Culmen Length (mm)'])

롸? 갑자기 쟤가 왜 나옴? 임퓨터가 평균, 중앙값, 최빈값으로 채워주는건데 문제가 하나 있습니다. 그게 값 분포에 따라 적절한 걸 골라야지 덮어놓고 히히 평균해야징 하다간 모델 성능이 똥멍청이 1이 됩니다. 그래서 때우기 전에 분포를 본 건데, 이게 보니까… 저거 그 어린왕자 그 코끼리 그거 아님? 그럼 어떻게 합니까?

 

num_cols = ['Culmen Length (mm)', 'Culmen Depth (mm)', 'Flipper Length (mm)', 'Body Mass (g)'] # 일단 떄울 칼럼

imputer = KNNImputer(n_neighbors=5) # 얘는 그 이웃 참고해서 때워주는 친구입니다
penguin_drop[num_cols] = imputer.fit_transform(penguin_drop[num_cols]) # 때-움

임퓨터중에 KNN Imputer라는 게 있는데, 얘는 결측값을 이웃한 그룹들을 참고해서 채워주는 친구다. 그렇게 해서 몸무게까지 네개 채워주면 일단 끝… 왜 저걸 일괄로 채움? 이유는 간단하다. 저 칼럼에 결측값이 두개씩 있었는데 그 두개가 같은 펭귄에서 빠져있었거든…

 

# . 대치합니닷 
penguin_drop['Sex'] = penguin_drop['Sex'].replace('.', np.nan)

penguin_drop['Sex'].unique()

성별은 범주형이라 최빈값으로 채워야 하는데, 그거 말고도 다른 문제가 있다. 저 점 뭐야 점. 저것도 결측값으로 바꾸고 최빈값으로 때울거다.

 

imputer = SimpleImputer(strategy='most_frequent')
penguin_drop[['Sex']] = imputer.fit_transform(penguin_drop[['Sex']]) # 때-움

됐으. 이제 동위원소 때우러 가자.

 

num_cols = ['Delta 15 N (o/oo)', 'Delta 13 C (o/oo)'] # 일단 떄울 칼럼

imputer = KNNImputer(n_neighbors=5) # 얘는 그 이웃 참고해서 때워주는 친구입니다
penguin_drop[num_cols] = imputer.fit_transform(penguin_drop[num_cols]) # 때-움

이것도 걍 KNN으로 때웠고, 이제 남은건 범주형 변수 인코딩하고 수치형 변수 스케일러 적용하는거다.

 

스탠다드 스케일러 

scaler = StandardScaler() # 스케일러가 요기잉눼?

num_features = ['Culmen Length (mm)', 'Culmen Depth (mm)', 'Flipper Length (mm)',
                'Body Mass (g)', 'Delta 15 N (o/oo)', 'Delta 13 C (o/oo)'] # 스케일러
cat_features = ['Island', 'Sex'] # 인코더

preprocessor = ColumnTransformer(
    transformers=[
        ('num', StandardScaler(), num_features),
        ('cat', OneHotEncoder(handle_unknown='ignore'), cat_features)
    ])

X_processed = preprocessor.fit_transform(penguin_drop)

일단 저 칼럼 트랜스포머가 뭐 하는 친구인지는 모르겠고 저게 다 된 거 맞습니다. 이대로 학습 들어가면 되는'데'...

 

이제 학습해야징 히히

y = penguin_drop['Species'] # 문제지
X_train, X_test, y_train, y_test = train_test_split(X_processed, y, test_size = 0.2, random_state=42, stratify=y) # 기본값 8:2

print(f'전체 데이터의 수 : {len(X_processed)}')
print(f'학습 데이터의 수 : {len(X_train)}')
print(f'테스트 테이터의 수 : {len(X_test)}')

있어봐요 우리 모델도 아직 못골랐어... 일단 나눈거야... 저거 참고로 비율은 보통 5:3:2가 국룰인데, 5는 학습용이고 3은 과적합 여부 확인용, 2가 테스트용이다.

 

랜덤포레스트

forest = RandomForestClassifier(random_state=42) # 얘는 근데 숲이랑 뭔 상관이 있길래 이름이 랜덤포리스트인겨
forest.fit(X_train, y_train) # 학습
forest_pred = forest.predict(X_test)

이게 다냐고? 예. 구글링했더니 뭐가 막 장황하게 나오긴 했는데 기본적으로는 이게 다다.

 

# 얼마나 맞췄는지 점수(%) 확인
print(f"정확도: {accuracy_score(y_test, forest_pred):.3f}")

# 종별로 얼마나 잘 분류했는지 상세 리포트
print(classification_report(y_test, forest_pred))
정확도: 0.986
                                           precision    recall  f1-score   support

      Adelie Penguin (Pygoscelis adeliae)       0.97      1.00      0.98        30
Chinstrap penguin (Pygoscelis antarctica)       1.00      0.93      0.96        14
        Gentoo penguin (Pygoscelis papua)       1.00      1.00      1.00        25

                                 accuracy                           0.99        69
                                macro avg       0.99      0.98      0.98        69
                             weighted avg       0.99      0.99      0.99        69

????? 아니 이게 내가 예상했던것보다 너무 잘나왔는데? 나 한 80퍼 되나 했는데 이게 뭐시여?????? 되게 지금 당황스러운데? 근데 아델리펭귄에 대한 정밀도는 좀 떨어지는데, 이게 그 결측값때문일수도 있다.

 

이 모델이 펭귄을 분류하는 데 있어서 중요하게 생각한 게 뭘까? 에 대한 답. 부리 길이와 날개 길이, 그리고 13-탄소가 피쳐 TOP 3인데... 저 동위원소 뭔데요? 저거 먹이활동같은거 추적할때 넣는 방사성 동위원소입니다.

 

SVM(서포트 벡터 머신)

svm_model = SVC(kernel='rbf', C=1.0, random_state=42)
svm_model.fit(X_train, y_train)
svm_predictions = svm_model.predict(X_test)
# 1. 성적표 (Classification Report)
print("--- SVM 분류 성적표 ---")
print(classification_report(y_test, svm_predictions))

# 2. 오답 분석 (Confusion Matrix)
cm = confusion_matrix(y_test, svm_predictions)
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=svm_model.classes_)
disp.plot(cmap='viridis')
plt.title("SVM Confusion Matrix")
plt.show()
--- SVM 분류 성적표 ---
                                           precision    recall  f1-score   support

      Adelie Penguin (Pygoscelis adeliae)       1.00      1.00      1.00        30
Chinstrap penguin (Pygoscelis antarctica)       1.00      1.00      1.00        14
        Gentoo penguin (Pygoscelis papua)       1.00      1.00      1.00        25

                                 accuracy                           1.00        69
                                macro avg       1.00      1.00      1.00        69
                             weighted avg       1.00      1.00      1.00        69

어… 이게… 이렇게 됨?

 

이거는… 걍 히트맵 그리는게 나을듯… 저 선 진짜 거슬려요.

 

XGBoost

# 1. 변환기 생성
le = LabelEncoder()

# 2. 정답지(y)를 숫자로 변환
y_train_encoded = le.fit_transform(y_train)
y_test_encoded = le.transform(y_test)

# 다중 분류이므로 objective를 'multi:softmax'로 설정하는 게 정석입니다
xgb_model = XGBClassifier(objective='multi:softmax', n_estimators=50, random_state=42)
xgb_model.fit(X_train, y_train_encoded)

# 결과 확인
print(classification_report(y_test, le.inverse_transform(xgb_model.predict(X_test))))

롸? 라벨인코더 쟤는 왜 나옴? 쟤는 답지도 인코딩해줘야 학습합니다... 그리고 XGBoost랑 LightGBM은 싸이킷런에 없으니까 따로 설치하십쇼.

 

                                           precision    recall  f1-score   support

      Adelie Penguin (Pygoscelis adeliae)       0.97      1.00      0.98        30
Chinstrap penguin (Pygoscelis antarctica)       1.00      0.93      0.96        14
        Gentoo penguin (Pygoscelis papua)       1.00      1.00      1.00        25

                                 accuracy                           0.99        69
                                macro avg       0.99      0.98      0.98        69
                             weighted avg       0.99      0.99      0.99        69

랜덤포레스트랑 비슷한디…?

 

LightGBM

얘도 설치하셔야됩니다… lightbgm 쳐놓고 왜 못깔지 이러고 있었음…ㅋㅋㅋㅋ

 

lgbm_model = lgb.LGBMClassifier(n_estimators=10, random_state=42, verbose=-1)
lgbm_model.fit(X_train, y_train_encoded)

# 1. 모델이 예측한 값(숫자)을 받아옵니다
lgb_pred_encoded = lgbm_model.predict(X_test)

# 2. 숫자를 다시 원래 펭귄 이름(문자열)으로 돌립니다
# 여기서 le(LabelEncoder)가 아까 학습(fit)된 상태여야 합니다
lgb_pred = le.inverse_transform(lgb_pred_encoded)

쟤는 좀 적죠…? 50번 돌렸더니 10번만에 여까지해 됐어 퍼펙트해 하고 모델이 GG쳤음…

 

print("--- LightGBM 분류 성적표 ---")
print(classification_report(y_test, lgb_pred))

# 3. 마지막 혼동 행렬 시각화
cm = confusion_matrix(y_test, lgb_pred)
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=lgbm_model.classes_)
disp.plot(cmap='Greens')
plt.title("LightGBM Confusion Matrix")
plt.show()
--- LightGBM 분류 성적표 ---
                                           precision    recall  f1-score   support

      Adelie Penguin (Pygoscelis adeliae)       0.94      0.97      0.95        30
Chinstrap penguin (Pygoscelis antarctica)       1.00      0.86      0.92        14
        Gentoo penguin (Pygoscelis papua)       0.96      1.00      0.98        25

                                 accuracy                           0.96        69
                                macro avg       0.97      0.94      0.95        69
                             weighted avg       0.96      0.96      0.96        69

빨리 GG친 것 치고는 니가 성적이 제일 꼴찌여 이자식아...

 

근데 그럴수밖에 없는게 XGBoost나 LightGBM 둘 다 스케일이 큰 애들에 특화되어 있습니다. 그 미국에서 호미 엄청 사가는거 아십니까? 거기는 막 옥수수밭에서 길 잃어먹는 사람도 있을 정도로 밭이 커갖고 농기구들도 스케일이 장난 아니예요. 근데 그게 호미랑 뭔 상관이냐고? 그 농기구들로 정원 손질하려니 세밀하게 안되는거지 이제. 잡초 뽑으려다가 엄한 꽃도 다치고 그러거든요. 근데 호미는 미쿡 농기구 스케일에 비하면 스케일도 작지, 하나로 다 하지… 그거임다.

 

아래 두 개는 입장에서 펭귄 데이터갖고 분류하라는건 미쿡 농기구로 화분에 꽃심는격임.

반응형

'Coding > EDA' 카테고리의 다른 글

Medical Cost Personal Datasets  (0) 2026.03.18
Red Wine Quality  (0) 2026.03.13
Google Play Store – Most Downloaded Android Apps  (0) 2026.03.02
얘! clinvar도 EDA가 된단다! (3)  (0) 2026.02.18
얘! clinvar도 EDA가 된단다! (2)  (0) 2026.02.17