Python to AI

titanic 데이터셋 분석 및 모델 학습

최 수빈 2025. 1. 29. 00:37

 

학습을 위한 코드이며, 최선의 코드가 아님


 

데이터 로드 및 기본 정보 확인

import numpy as np
import pandas as pd

df = pd.read_csv('./titanic_csv')

df.info()
df.head(3)

"""
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB

	PassengerId	Survived	Pclass	Name	Sex	Age	SibSp	Parch	Ticket	Fare	Cabin	Embarked
0	1	0	3	Braund, Mr. Owen Harris	male	22.0	1	0	A/5 21171	7.2500	NaN	S
1	2	1	1	Cumings, Mrs. John Bradley (Florence Briggs Th...	female	38.0	1	0	PC 17599	71.2833	C85	C
2	3	1	3	Heikkinen, Miss. Laina	female	26.0	0	0	STON/O2. 3101282	7.9250	NaN	S

"""

 

  • 데이터 로드
    titanic.csv파일을 pandas의 read_csv 함수를 통해 데이터프레임으로 불러옴
  • 데이터 정보 확인
    df.info()를 통해 데이터의 열 정보, 데이터 타입, 결측값 여부 등을 확인

 

*컬럼 설명

PassengerID 탑승자 데이터의 고유 ID
Survived 생존 여부 (0 : 사망, 1 : 생존)
Pclass 선실 등급 (1, 2, 3)
Sex 성별
Age 나이
SibSp 동반한 형제자매 또는 배우자 수
Parch 동반한 부모 또는 자녀 수
Fare 티켓 요금
Cabin 선실 번호
Embarked 승선 항구 (C: Cherbourg, Q = Queenstown, S = Southampton)

 

 

데이터 전처리

 

결측값 처리

 

Age 평균 값으로 채움 (평균값 대신 중위값 또는 다른 대체값을 사용할 수도 있음)

Cabin ‘N’으로 채움

Embarked ‘N’으로 채움

def fillna(df):
    df['Age'] = df['Age'].fillna(df['Age'].mean())
    df['Cabin'] = df['Cabin'].fillna('N')
    df['Embarked'] = df['Embarked'].fillna('N')
    return df

 

 

불필요한 컬럼 제거

 

PassengerId

Name

Ticket

모델 학습에 사용하지 않을 컬럼 : 제거

def drop_features(df):
    return df.drop(['PassengerId', 'Name', 'Ticket'], axis=1)

 

 

범주형 데이터 처리

Sex, Embarked: LabelEncoder를 이용해 숫자형으로 변환

Cabin: 문자열의 첫 번째 문자만 추출 후 숫자형으로 변환

from sklean.preprogressing import LabelEncoder

def format_features(df):
    df['Cabin'] = df['Cabin'].astype(str).str[:1]
    features = ['Cabin', 'Sex', 'Embarked']
    for feature in features:
        le = LabelEncoder()
        df[feature] = le.fit_transform(df[feature])
    return df

 

 

전처리 함수 통합

위의 모든 단계를 통합한 전처리 함수 작성

def transform_features(df):
    df = fillna(df)
    df = drop_features(df)
    df = format_features(df)
    return df

 

 

데이터 분리

Survived 종속변수(y), 나머지 데이터 독립변수(X)

train_test_split을 사용학습/테스트 데이터로 나눔

from sklearn.model_selection import train_test_split

y_titanic_df = df['Survived']
X_titanic_df = df.drop('Survived, axis = 1, inplace = False)
X_titanic_df = transform_features(X_titanic_df)

X_train, X_test, y_train, y_test = train_test_split(X_titanic_df, y_titanic_df, test_size=0.2, random_state=11)

 

 

모델 학습 및 평가

 

모델 정의

DecisionTreeClassifier

RandomForestClassifier

LogisticRegression 

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report

models = {
    'DecisionTree': DecisionTreeClassifier(random_state=0),
    'RandomForest': RandomForestClassifier(random_state=0),
    'LogisticRegression': LogisticRegression(solver='liblinear')
}

 

 

모델 학습 및 정확도 평가

accuracy_score

confusion_matrix

classification_report

→모델 성능 평가

 

def evaluate_models(models, X_train, X_test, y_train, y_test):
    results = {}
    for name, model in models.items():
        model.fit(X_train, y_train)
        pred = model.predict(X_test)
        acc = accuracy_score(y_test, pred)
        results[name] = acc
        print(f'{name} 정확도: {acc:.4f}')
        print("Confusion Matrix:\n", confusion_matrix(y_test, pred))
        print("Classification Report:\n", classification_report(y_test, pred))
    return results
    
    #모델 평가
    results = evaluate_models(models, X_train, X_test, y_train, y_test)
    
    """
    DecisionTree 정확도: 0.8045
Confusion Matrix:
 [[101  17]
 [ 18  43]]
Classification Report:
               precision    recall  f1-score   support

           0       0.85      0.86      0.85       118
           1       0.72      0.70      0.71        61

    accuracy                           0.80       179
   macro avg       0.78      0.78      0.78       179
weighted avg       0.80      0.80      0.80       179

RandomForest 정확도: 0.8436
Confusion Matrix:
 [[106  12]
 [ 16  45]]
Classification Report:
               precision    recall  f1-score   support

           0       0.87      0.90      0.88       118
           1       0.79      0.74      0.76        61

    accuracy                           0.84       179
...
    accuracy                           0.87       179
   macro avg       0.85      0.84      0.85       179
weighted avg       0.86      0.87      0.86       179
    """

 

 

결과 시각화

모델 별 정확도를 막대그래프로 시각화

import matplotlib.pyplot as plt

plt.bar(results.keys(), results.values())
plt.title('Model Accuracy Comparison')
plt.ylabel('Accuracy')
plt.show()

Model Accuracy Comparison

 

 

교차 검증

 

K-Fold 교차 검증

KFold를 활용해 데이터를 K개로 나누어 검증

from sklearn.model_selection import KFold

def exec_kfold(clf, folds=5):
    kfold = KFold(n_splits=folds)
    scores = []
    for iter_count, (train_index, test_index) in enumerate(kfold.split(X_titanic_df)):
        X_train, X_test = X_titanic_df.values[train_index], X_titanic_df.values[test_index]
        y_train, y_test = y_titanic_df.values[train_index], y_titanic_df.values[test_index]
        clf.fit(X_train, y_train)
        predictions = clf.predict(X_test)
        accuracy = accuracy_score(y_test, predictions)
        scores.append(accuracy)
        print(f'교차 검증 {iter_count} 정확도: {accuracy:.4f}')
    mean_score = np.mean(scores)
    print(f'평균 정확도: {mean_score:.4f}')
    
 exec_kfold(DecisionTreeClassifier(random_state=0))
 
 """
교차 검증 0 정확도: 0.7542
교차 검증 1 정확도: 0.7809
교차 검증 2 정확도: 0.7865
교차 검증 3 정확도: 0.7697
교차 검증 4 정확도: 0.8202
평균 정확도: 0.7823
 """

 

 

cross_val_score를 이용한 교차 검증

cross_val_score로 평균 정확도 계산

from sklearn.model_selection import cross_val_score

scores = cross_val_score(DecisionTreeClassifier(random_state=0), X_titanic_df, y_titanic_df, cv=5)

for iter_count, accuracy in enumerate(scores):
    print(f'교차 검증: {iter_count}, 정확도: {accuracy}')
print(f'평균 정확도 >>>> {np.mean(scores):.4f}')

"""
교차 검증: 0, 정확도: 0.7653631284916201
교차 검증: 1, 정확도: 0.7752808988764045
교차 검증: 2, 정확도: 0.797752808988764
교차 검증: 3, 정확도: 0.7808988764044944
교차 검증: 4, 정확도: 0.8258426966292135
평균 정확도 >>>> 0.7890
"""

 

 

하이퍼파라미터 튜닝

GridSearchCV를 사용해 하이퍼파라미터를 최적화

 

조합 정의 교차 검증 → 최적의 조합 선택 → 최적의 모델 반환 

from sklearn.model_selection import GridSearchCV

parameters = {'max_depth': [2, 3, 5, 10],
              'min_samples_split': [2, 3, 5],
              'min_samples_leaf': [1, 5, 8]}

grid_dclf = GridSearchCV(DecisionTreeClassifier(random_state=0), param_grid=parameters, scoring='accuracy', cv=5)
grid_dclf.fit(X_train, y_train)

print(f'최적의 파라미터 >>>> {grid_dclf.best_params_}')
print(f'최고 교차 검증 정확도 >>>> {grid_dclf.best_score_}')

"""
GridSearchCV 최적 하이퍼 파라미터 >>>> {'max_depth': 3, 'min_samples_leaf': 5, 'min_samples_split': 2}
GridSearchCV 최고 정확도: 0.7991825076332119
"""

 

하이퍼파라미터 범위 조정: GridSearchCV의 파라미터 범위는 데이터의 특성에 따라 조정 필요

 

 

*parameters


depth

너무 깊으면 과적합될 가능성이 높음

split

작으면 작을수록 트리가 복잡해짐

leaf

리프 노드가 최소한의 데이터를 포함하도록 설정

 

조합의 개수

조합 수 = depth 수 x split 수 x leaf 수 

 

 

 

*고려사항

 

데이터 불균형

Survived의 클래스 비율이 불균형하다면, class_weight 옵션을 설정하거나 오버샘플링(SMOTE) 등을 고려해야 함

 

 

 

전체 데이터셋을 활용하여 학습 및 검증

# 라이브러리 가져오기
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score

parameters = {'max_depth': [2, 3, 5, 10],
              'min_samples_split': [2, 3, 5],
              'min_samples_leaf': [1, 5, 8]}
              
grid_dclf = GridSearchCV(
    estimator=DecisionTreeClassifier(random_state=44),
    param_grid=parameters,
    scoring='accuracy',
    cv=5
)

grid_dclf.fit(X_titanic_df, y_titanic_df)

print(f'최적의 파라미터 >>>> {grid_dclf.best_params_}')
print(f'최고 교차 검증 정확도 >>>> {grid_dclf.best_score_}')

best_model = grid_dclf.best_estimator_
best_model
pred = best_model.predict(X_titanic_df)

print(f'GridSearchCV 최적의 값 >>>> {accuracy_score(y_titanic_df, pred)}')


"""
최적의 파라미터 >>>> {'max_depth': 10, 'min_samples_leaf': 8, 'min_samples_split': 2}
최고 교차 검증 정확도 >>>> 0.8159751428033394
GridSearchCV 최적의 값 >>>> 0.8720538720538721
"""

 

  • 데이터 활용 효율성 높음
    데이터가 적은 상황에서도 최대한 성능을 끌어낼 수 있음
  • 안정적인 결과
    교차 검증 과정에서 모든 데이터가 학습과 검증에 포함되므로, 데이터 부족으로 인한 성능 변화를 최소화
  • 과적합 가능성
    전체 데이터에서 교차 검증을 수행하므로, 테스트 데이터가 학습 데이터와 겹칠 가능성이 있음
    →최적의 하이퍼파라미터를 찾은 후 최종 평가 데이터로 독립적인 검증이 불가능

하이퍼파라미터 최적화와 검증을 동시에 수행하는 것이 주요 목표일 때

데이터셋이 작을 때

전체 데이터를 활용하여 학습 및 검증하는 방법을 사용할 수 있음