[빅데이터] 타이타닉 데이터 분석

구글 코랩 환경에서 데이터 분석을 진행하였으며, 이 데이터셋은 seaborn 라이브러리에 포함되어 있어 별도의 다운로드 없이 사용할 수 있다.


타이타닉 데이터셋의 주요 항목은 다음과 같다.

  1. Survived (생존 여부): 0은 생존하지 못한 경우, 1은 생존한 경우이다. 생존율은 약 38%다.
  2. Pclass (객실 등급): 1, 2, 3등급으로 나뉘며, 등급이 높을수록 생존율이 높다.
  3. Sex (성별): 남성이 577명, 여성이 314명으로, 생존율은 여성이 더 높다.
  4. Age (나이): 평균 29.7세, 결측값은 177개다. 어린이와 여성의 생존율이 높다.
  5. Fare (요금): 평균 요금은 약 32.20이며, 상위 등급일수록 요금이 높다.
  6. Embarked (탑승 항구): S(사우샘프턴), C(쉐르부르), Q(퀸스타운)에서 탑승했으며, S가 가장 많다.

1. 데이터 요약

  • 총 데이터 수: 891행, 15개 열
  • 열별 데이터 타입:
  • 정수형(int64): survived, pclass, sibsp, parch
  • 실수형(float64): age, fare
  • 범주형(category): class, deck
  • 객체형(object): sex, embarked, who, embark_town, alive
  • 부울형(bool): adult_male, alone

2. 결측값

  • age 열에 177개의 결측값이 있으며, deck 열은 결측값이 대부분(688개)이다.
  • embarkedembark_town에도 각각 2개의 결측값이 있다.

3. 기본 통계 정보

  • 생존율: 평균 생존율이 약 38.4%로, 다수의 승객이 생존하지 못했다.
  • 연령: 평균 나이는 약 29.7세이며, 최연소 승객은 0.42세, 최고령 승객은 80세다.
  • 요금(fare): 요금의 중앙값은 약 14.45, 평균은 32.2로 요금 분포가 넓다. 최고 요금은 512.33이다.
  • 성별 분포: 남성 승객이 577명으로, 여성보다 많다.
  • 객실 등급: 대부분 3등급 승객이며, 1등급과 2등급 승객이 상대적으로 적다.

간단한 분석 결과

  • 성별에 따른 생존율: 일반적으로 여성 승객의 생존율이 남성보다 높다.
  • 객실 등급에 따른 생존율: 상위 등급(1등급)의 승객이 하위 등급 승객보다 생존율이 높은 경향이 있다.

1. 타이타닉 데이터셋 불러오기

import seaborn as sns

# 타이타닉 데이터셋 불러오기
titanic = sns.load_dataset('titanic')
print(titanic.head())

2. 데이터 정보 확인

# 데이터 정보 확인
titanic.info()

이 코드는 데이터셋의 행과 열 수, 각 열의 데이터 타입, 결측값 여부 등을 보여준다.

데이터 요약

  • 총 데이터 수: 891행, 15개 열
  • 열별 데이터 타입:
    • 정수형(int64): survived, pclass, sibsp, parch
    • 실수형(float64): age, fare
    • 범주형(category): class, deck
    • 객체형(object): sex, embarked, who, embark_town, alive
    • 부울형(bool): adult_male, alone

3. 결측값 분석

#각 열의 결측값 개수 확인
missing_data = titanic.isnull().sum()
print("Missing Values in Each Column:\n", missing_data)

이 코드를 통해 각 열에 포함된 결측값의 개수를 확인할 수 있다.

결측값

  • age 열에 177개의 결측값이 있으며, deck 열은 결측값이 대부분(688개)이다.
  • embarkedembark_town에도 각각 2개의 결측값이 있다.

4. 기본 통계 정보

#수치형 및 범주형 데이터의 통계 요약
print("Statistical Summary:\n", titanic.describe(include='all'))

이 코드는 수치형 데이터의 평균, 표준편차, 최소/최대 값 등을 확인하며, 범주형 데이터는 고유 값 개수와 최빈도 값을 제공한다.

기본 통계 정보

  • 생존율: 평균 생존율이 약 38.4%로, 다수의 승객이 생존하지 못했다.
  • 연령: 평균 나이는 약 29.7세이며, 최연소 승객은 0.42세, 최고령 승객은 80세다.
  • 요금(fare): 요금의 중앙값은 약 14.45, 평균은 32.2로 요금 분포가 넓다. 최고 요금은 512.33이다.
  • 성별 분포: 남성 승객이 577명으로, 여성보다 많다.
  • 객실 등급: 대부분 3등급 승객이며, 1등급과 2등급 승객이 상대적으로 적다.

먼저 결측값 처리를 수행하고, 이후 주어진 변수들에 따른 생존율을 분석해 보겠다.

1. 결측값 처리

결측값이 있는 열에 대해 다음과 같은 처리를 해야한다.

  • age: 평균값으로 채우기
  • embarkedembark_town: 최빈값으로 채우기
  • deck: 결측값이 많아 분석에서 제외

deck 열을 제외한 이유는 결측값이 전체 데이터의 약 77%에 달하기 때문이다. 결측값이 많은 열은 분석에 왜곡을 줄 수 있어 일반적으로 분석에서 제외하거나 다른 방식으로 처리하는 경우가 많다.

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt

# 데이터 불러오기
titanic = sns.load_dataset('titanic')

# 결측값 처리
titanic['age'].fillna(titanic['age'].mean(), inplace=True)
titanic['embarked'].fillna(titanic['embarked'].mode()[0], inplace=True)
titanic['embark_town'].fillna(titanic['embark_town'].mode()[0], inplace=True)
titanic.drop(columns=['deck'], inplace=True)

2. 성별에 따른 생존율

# 성별에 따른 생존율 분석
gender_survival = titanic.groupby('sex')['survived'].mean()
print("성별에 따른 생존율:\n", gender_survival)

sns.barplot(x='sex', y='survived', data=titanic)
plt.title('Survival Rate by Gender')
plt.show()

성별에 따른 생존율

  • 여성 생존율: 약 74.2%
  • 남성 생존율: 약 18.9%

결과적으로, 여성의 생존율이 남성보다 훨씬 높다는 것을 알 수 있다. 이는 당시 배에서 여성과 아이들이 우선적으로 구조되었다는 것을 시사한다.

3. 객실 등급에 따른 생존율

# 객실 등급에 따른 생존율 분석
pclass_survival = titanic.groupby('pclass')['survived'].mean()
print("객실 등급에 따른 생존율:\n", pclass_survival)

sns.barplot(x='pclass', y='survived', data=titanic)
plt.title('Survival Rate by Passenger Class')
plt.show()

객실 등급에 따른 생존율

  • 1등급 승객 생존율: 약 62.9%
  • 2등급 승객 생존율: 약 47.3%
  • 3등급 승객 생존율: 약 24.2%

객실 등급이 높을수록 생존율이 높아지는 경향이 있다. 이는 높은 등급 승객들이 구조될 가능성이 더 컸음을 의미할 수 있다.

4. 나이 분포에 따른 생존율

# 나이 분포에 따른 생존율 분석
plt.figure(figsize=(10, 6))
sns.histplot(titanic, x='age', hue='survived', multiple='stack', kde=True)
plt.title('Age Distribution by Survival')
plt.show()

나이 분포에 따른 생존율

  • 30대 승객이 가장 많고, 그 연령대에서 사망자가 많은 것으로 보인다.
  • 어린 나이의 승객들은 상대적으로 생존율이 높다.

이 분석을 통해 나이대에 따라 생존율의 차이가 존재함을 알 수 있으며, 어린 승객들은 비교적 우선적으로 구조된 것으로 보인다.

5. 가족 여부에 따른 생존율

가족 여부는 sibspparch를 사용해 혼자가 아닌 경우로 구분한다.

# 가족 여부에 따른 생존율 분석
titanic['has_family'] = (titanic['sibsp'] + titanic['parch'] > 0)
family_survival = titanic.groupby('has_family')['survived'].mean()
print("가족 여부에 따른 생존율:\n", family_survival)

sns.barplot(x='has_family', y='survived', data=titanic)
plt.title('Survival Rate by Family Status')
plt.xlabel('Has Family')
plt.show()

가족 여부에 따른 생존율

  • 가족이 없는 경우 생존율: 약 30.4%
  • 가족이 있는 경우 생존율: 약 50.6%

가족이 있는 승객들이 더 높은 생존율을 보이고 있다. 이는 가족이 함께 행동하면서 구조될 가능성이 높아졌음을 시사할 수 있다.

6. 탑승 항구에 따른 생존율

# 탑승 항구에 따른 생존율 분석
embarked_survival = titanic.groupby('embarked')['survived'].mean()
print("탑승 항구에 따른 생존율:\n", embarked_survival)

sns.barplot(x='embarked', y='survived', data=titanic)
plt.title('Survival Rate by Embarkation Port')
plt.show()

탑승 항구에 따른 생존율

  • Cherbourg(C)에서 탑승한 승객 생존율: 약 55.4%
  • Queenstown(Q)에서 탑승한 승객 생존율: 약 38.9%
  • Southampton(S)에서 탑승한 승객 생존율: 약 33.9%

Cherbourg에서 탑승한 승객의 생존율이 상대적으로 높고, Southampton에서 탑승한 승객의 생존율이 가장 낮다. 이는 탑승 항구에 따라 배치된 승객의 사회적 지위나 구조 우선 순위가 달랐을 수 있음을 시사한다.

7. 혼자 여부에 따른 생존율

# 혼자 여부에 따른 생존율 분석
alone_survival = titanic.groupby('alone')['survived'].mean()
print("혼자 여부에 따른 생존율:\n", alone_survival)

sns.barplot(x='alone', y='survived', data=titanic)
plt.title('Survival Rate by Alone Status')
plt.xlabel('Alone')
plt.show()

혼자 여부에 따른 생존율

  • 혼자가 아닌 경우 생존율: 약 50.6%
  • 혼자인 경우 생존율: 약 30.4%

혼자가 아닌 승객들의 생존율이 혼자인 승객들보다 높다. 이는 혼자가 아닌 승객들이 더 많은 지원을 받을 수 있었거나 구조 우선 순위에 영향을 받았을 가능성을 시사한다.

타이타닉 데이터셋에서 각 변수 간의 상관관계를 분석하기 위해 survived와 관련된 변수들 간의 상관 계수를 계산하고 시각화하겠다. 수치형 변수들을 기준으로 상관관계 분석을 진행하며, 이를 시각화한 히트맵도 제공할 수 있다.

1. 상관관계 분석 코드

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt

# 타이타닉 데이터셋 불러오기
titanic = sns.load_dataset('titanic')

# 결측값 처리
titanic['age'].fillna(titanic['age'].mean(), inplace=True)
titanic['embarked'].fillna(titanic['embarked'].mode()[0], inplace=True)
titanic['embark_town'].fillna(titanic['embark_town'].mode()[0], inplace=True)
titanic.drop(columns=['deck'], inplace=True)

# 수치형 변수 상관관계 분석
correlation_matrix = titanic[['survived', 'pclass', 'age', 'sibsp', 'parch', 'fare']].corr()

# 상관관계 히트맵 그리기
plt.figure(figsize=(10, 6))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', linewidths=0.5)
plt.title('Correlation Matrix of Titanic Dataset')
plt.show()

# 상관계수 출력
print(correlation_matrix)

2. 상관관계 분석 결과

  1. survived와 다른 변수 간의 상관관계를 해석하면
  • pclasssurvived는 음의 상관관계가 있다. 즉, 객실 등급이 낮을수록 생존율이 낮아지는 경향이 있다.
  • faresurvived는 양의 상관관계를 보인다. 즉, 높은 요금을 지불한 승객일수록 생존율이 높아지는 경향이 있다.
  • agesurvived는 약한 음의 상관관계를 보인다. 나이가 많을수록 생존율이 약간 낮아지는 경향이 있다.
  • sibspparch는 가족 여부를 나타내며, 이 둘도 생존율에 미미한 상관관계를 보인다.

상관계수 표를 바탕으로, 변수들 간의 상관관계에 대한 해석은 다음과 같다.

1. survived (생존 여부)와 다른 변수들 간의 상관관계

  • pclass (객실 등급): 상관계수는 -0.34로, 객실 등급이 낮을수록 생존 가능성이 낮다는 것을 의미한다. 즉, 3등급 승객보다 1등급 승객의 생존율이 더 높다.
  • age (나이): 상관계수는 -0.07로, 나이가 많을수록 생존 가능성이 조금 낮은 경향이 있지만, 이 상관관계는 매우 약하다.
  • sibsp (형제/배우자 수): 상관계수는 -0.035로, 거의 상관관계가 없다고 할 수 있다. 형제나 배우자의 수가 생존율에 미치는 영향은 크지 않다.
  • parch (부모/자녀 수): 상관계수는 0.082로, 부모나 자녀가 있는 경우 생존 가능성이 약간 높아지는 경향을 보이지만, 이 역시 약한 상관관계다.
  • fare (요금): 상관계수는 0.26으로, 요금이 높을수록 생존 가능성이 높다는 것을 알 수 있다. 더 비싼 티켓을 구매한 승객들이 더 많이 생존한 것으로 해석된다.

2. 다른 변수들 간의 상관관계

  • pclassfare: 상관계수는 -0.55로, 객실 등급이 낮을수록 요금도 저렴한 경향을 보인다. 객실 등급이 낮을수록 저렴한 티켓 가격을 반영한다.
  • sibspparch: 상관계수는 0.414로, 가족 구성원이 있는 승객들끼리의 상관관계가 중간 정도 있다. 즉, 형제/배우자 수가 많을수록 부모/자녀가 있는 경우도 더 많다는 것을 의미한다.
  • agepclass: 상관계수는 -0.33로, 객실 등급이 낮을수록 승객의 평균 나이가 적다는 것을 시사한다. 이는 3등급 승객들이 젊은 층일 가능성이 높음을 의미할 수 있다.

주요 요약

  • 객실 등급과 요금이 생존율에 큰 영향을 미쳤음을 알 수 있다. 높은 요금을 지불한 승객이 더 높은 등급의 객실을 이용하며, 이로 인해 생존율도 높아진 경향이 있다.
  • 나이, 형제/배우자 수, 부모/자녀 수 등은 생존율과 약한 상관관계를 보인다.
  • 특히 pclassfaresurvived에 상대적으로 중요한 영향을 미쳤다.

타이타닉 데이터셋에 대한 더 깊은 통계적 분석을 진행하기 위해 T-검정, 회귀분석, 선형회귀 분석, 분산 분석, 군집 분석, 판별 분석을 단계별로 설명하겠다.

1. T-검정 (t-test)

성별에 따른 생존율의 차이가 유의미한지를 확인하기 위해 독립 표본 T-검정을 사용하겠다.

from scipy import stats

# 남성과 여성의 생존율 비교
male_survived = titanic[titanic['sex'] == 'male']['survived']
female_survived = titanic[titanic['sex'] == 'female']['survived']

# 독립 표본 t-검정
t_stat, p_value = stats.ttest_ind(male_survived, female_survived)
print(f"T-검정 결과: t-통계량 = {t_stat}, p-값 = {p_value}")
  • T-통계량(t-stat): 두 그룹 간 차이를 나타내는 값이다. 값이 클수록 그룹 간 차이가 크다.
  • p-값(p-value): p-값이 일반적으로 0.05 미만일 때, 두 그룹 간의 차이가 통계적으로 유의미하다고 결론을 내릴 수 있다.

T-검정 결과

  • t-통계량: -19.30
  • p-값: 1.406e-69

성별에 따른 생존율의 T-검정 결과, p-값이 매우 작아(0.05보다 훨씬 작음), 성별에 따른 생존율 차이가 통계적으로 유의미하다는 결론을 내릴 수 있다. 남성과 여성 간에 생존율의 차이가 매우 크다.

2. 회귀분석 (Logistic Regression)

survived (생존 여부)을 종속 변수로 하여, 성별, 나이, 객실 등급, 요금 등의 변수를 사용하여 로지스틱 회귀분석을 수행한다.

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# 분석에 사용할 변수 선택 및 전처리
titanic['sex'] = titanic['sex'].map({'male': 0, 'female': 1})  # 성별을 숫자로 변환
features = ['sex', 'age', 'pclass', 'fare', 'sibsp', 'parch']
X = titanic[features]
y = titanic['survived']

# 훈련 및 테스트 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 로지스틱 회귀 모델 생성 및 학습
model = LogisticRegression(max_iter=200)
model.fit(X_train, y_train)

# 테스트 데이터로 예측
y_pred = model.predict(X_test)

# 모델 성능 평가 (정확도)
accuracy = accuracy_score(y_test, y_pred)
print(f"로지스틱 회귀 분석 정확도: {accuracy:.2f}")

# 각 독립 변수의 회귀 계수
print("회귀 계수:", model.coef_)
  • 정확도: 로지스틱 회귀 모델이 생존 여부를 얼마나 정확히 예측하는지를 보여준다.
  • 회귀 계수: 각 독립 변수(성별, 나이, 객실 등급, 요금 등)가 종속 변수(생존)에 미치는 영향을 나타낸다

로지스틱 회귀 분석 결과

  • 정확도: 81%
  • 회귀 계수: [ 2.51, -0.03, -0.90, 0.003, -0.29, -0.12]

로지스틱 회귀 분석의 결과, 모델의 정확도가 81%로 상당히 높은 예측 성능을 보였다. 각 독립변수의 회귀 계수는 다음을 의미한다.

  • 성별(남성=0, 여성=1)의 회귀 계수는 2.51로, 여성이 생존할 가능성이 더 높다는 것을 나타낸다.
  • 나이(age), 객실 등급(pclass), 형제/배우자 수(sibsp), 부모/자녀 수(parch)는 모두 생존율에 음의 영향을 미친다.

3. 선형 회귀 분석

fare (티켓 요금)를 종속 변수로 하고, 나이, 객실 등급 등의 변수를 사용하여 선형 회귀 분석을 수행한다.

from sklearn.linear_model import LinearRegression
import numpy as np

# 선형 회귀 모델
linear_model = LinearRegression()

# 객실 등급과 나이를 독립 변수로, 요금을 종속 변수로 설정
X = titanic[['age', 'pclass']]
y = titanic['fare']

# 결측값 제거
X = X.dropna()
y = y.loc[X.index]

# 선형 회귀 모델 학습
linear_model.fit(X, y)

# 회귀 계수 출력
print("선형 회귀 분석 회귀 계수:", linear_model.coef_)

# 테스트 예측
predicted_fare = linear_model.predict(X)

# 실제 값과 예측 값 비교
plt.scatter(X['age'], y, color='blue', label='Actual Fare')
plt.scatter(X['age'], predicted_fare, color='red', label='Predicted Fare')
plt.title('Age vs Fare: Actual vs Predicted')
plt.xlabel('Age')
plt.ylabel('Fare')
plt.legend()
plt.show()
  • 회귀 계수: 나이와 객실 등급이 요금에 미치는 영향을 설명하는 계수다.
  • 그래프는 실제 요금과 예측된 요금 간의 차이를 시각화하여 모델의 성능을 평가할 수 있다.

선형 회귀 분석 결과

  • 회귀 계수: 나이(age)에 대한 회귀 계수는 -0.39, 객실 등급(pclass)에 대한 회귀 계수는 -34.66이다.

이는 나이가 많을수록, 객실 등급이 낮을수록 요금(fare)이 낮다는 것을 의미한다. 객실 등급이 요금에 큰 영향을 미치며, 나이가 많을수록 약간 더 낮은 요금을 지불한 경향이 있음을 시사한다.

그래프 설명

  • 위 그래프는 나이(Age)와 요금(Fare) 간의 관계를 보여주며, 파란 점은 실제 요금(Actual Fare), 빨간 점은 선형 회귀 모델이 예측한 요금(Predicted Fare)을 나타낸다.

해석

  • 파란 점(실제 값): 실제 데이터를 보면, 연령이 다양한 승객들이 요금에 있어 매우 다양한 분포를 보이는 것을 알 수 있다. 특히 30~40대 사이에서 일부 승객들이 매우 높은 요금을 지불한 사례가 있다.
  • 빨간 점(예측 값): 선형 회귀 모델은 나이가 많아질수록 요금이 감소하는 경향을 예측했다. 하지만 이 예측이 상당히 단순화되어, 실제 데이터와의 차이가 크다. 이는 나이만으로 요금을 설명하기에는 한계가 있음을 의미한다.
  • 실제 요금 분포는 매우 다양하며, 단순한 선형 회귀 모델로 모든 승객의 요금을 정확하게 예측하기 어렵다. 특히, 나이 외에도 객실 등급이나 탑승 항구, 성별 등의 다른 변수들이 요금에 더 큰 영향을 미쳤을 가능성이 크다.
  • 선형 회귀 모델의 한계는 실제 값과 예측 값 간의 차이에서 드러나며, 보다 복잡한 모델(예: 다변량 회귀 분석)을 적용할 필요가 있을 수 있다.

4. 분산분석(ANOVA)

ANOVA는 범주형 독립변수와 연속형 종속변수 간의 관계를 분석하는 데 사용된다. 예를 들어, 탑승 항구(embarked)에 따른 생존율의 차이를 분석할 수 있다.

import statsmodels.api as sm
from statsmodels.formula.api import ols

# 탑승 항구에 따른 요금의 차이 (일원 분산분석)
model = ols('fare ~ C(embarked)', data=titanic).fit()
anova_table = sm.stats.anova_lm(model, typ=2)
print(anova_table)
  • 객실 등급(pclass), 성별(sex), 탑승 항구(embarked)와 같은 범주형 변수들이 있으므로, 이 범주형 변수들이 연속형 변수들(예: fare, age)에 미치는 영향을 분석할 때 유용하다.
  • 예시: 탑승 항구에 따라 요금(fare)에 차이가 있는지 분석할 수 있다.

분산분석 (ANOVA) 결과

  • 탑승 항구(embarked)에 따른 요금 차이 분석:
    • F-통계량: 37.90
    • p-값: 1.60e-16

ANOVA 분석 결과, 탑승 항구에 따른 요금 차이가 매우 유의미함을 알 수 있다. 탑승 항구에 따라 요금이 큰 차이가 있음을 시사한다. 탑승 항구가 생존에 영향을 미친 것으로 추정되며, 요금과 연관될 가능성이 있다.

5. 군집분석(Clustering)

군집분석은 데이터를 비슷한 특성을 가진 그룹으로 나누는 기법이다. 타이타닉 데이터에서 승객들을 여러 그룹으로 나누어 생존율에 따른 패턴을 찾는 데 유용할 수 있다.

from sklearn.cluster import KMeans
import matplotlib.pyplot as plt

# 나이, 요금, 객실 등급을 기준으로 군집화
X = titanic[['age', 'fare', 'pclass']].dropna()
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)

# 군집화 결과 시각화
plt.scatter(X['age'], X['fare'], c=kmeans.labels_, cmap='viridis')
plt.title('Clustering based on Age, Fare, and Pclass')
plt.xlabel('Age')
plt.ylabel('Fare')
plt.show()
  • 승객들을 비슷한 특성을 가진 그룹으로 나누어, 각 군집의 생존율을 비교할 수 있다.
  • 예를 들어, 나이, 요금, 객실 등급에 따라 승객들을 여러 군집으로 나누고, 각 군집의 생존율을 비교할 수 있다.

그래프 설명

  • 위 그래프는 나이(Age)와 요금(Fare)을 기준으로 승객들을 군집화한 결과를 보여준다. 다른 색상은 다른 군집을 나타낸다.
  • 3개의 군집을 생성한 결과, 각각의 색깔로 표시된 군집이 있다
    • 노란색 군집: 요금이 매우 높은 일부 승객들
    • 보라색 군집: 중간 수준의 요금을 지불한 승객들
    • 청록색 군집: 저렴한 요금을 지불한 다수의 승객들

해석

  • 요금과 나이에 따른 군집 분포
    • 노란색 군집은 요금을 매우 높게 지불한 승객들로 주로 30~50대 성인 승객들이다. 이 승객들은 아마도 1등급 객실을 이용했을 가능성이 높다.
    • 보라색 군집은 요금을 중간 정도 지불한 승객들이며, 이들은 20~50대 사이에 분포되어 있다. 이들은 아마도 2등급 객실을 이용한 승객들일 수 있다.
    • 청록색 군집은 저렴한 요금을 지불한 다수의 승객들로, 나이대가 넓고, 대부분 3등급 객실을 이용한 승객들일 가능성이 크다.
  • 군집 분석을 통해 나이요금에 따라 승객들이 크게 3개의 군집으로 나뉘는 것을 확인할 수 있다. 특히, 요금이 중요한 구분 기준임을 알 수 있다.
  • 군집화 결과는 승객들의 사회적/경제적 지위에 따른 차이를 반영할 수 있으며, 이 군집별로 생존율이 다르게 나타날 가능성이 크다.

6. 판별분석(Discriminant Analysis)

판별분석은 그룹 간의 차이를 분석하고, 새 데이터를 주어진 그룹 중 어느 그룹에 속할지 예측하는 기법이다. 타이타닉 데이터에서는 생존 여부를 예측하는 데 유용할 수 있다.

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA

# 성별, 나이, 객실 등급을 이용해 판별분석 수행
X = titanic[['sex', 'age', 'pclass']].dropna()
y = titanic['survived'].dropna()

lda = LDA()
lda.fit(X, y)

# 정확도 확인
y_pred = lda.predict(X)
accuracy = accuracy_score(y, y_pred)
print(f"판별분석 정확도: {accuracy:.2f}")
  • 판별분석을 통해 승객의 특성(성별, 나이, 객실 등급 등)에 따라 그 승객이 생존했는지 여부를 예측할 수 있다.
  • 로지스틱 회귀와 유사하지만, 판별분석은 그룹 간 차이를 분석하는 데 중점을 둔다.

판별분석 결과

  • 정확도: 79%

판별분석의 결과, 생존 여부를 79%의 정확도로 예측할 수 있었다. 로지스틱 회귀 분석의 정확도와 유사한 수준이다. 판별분석을 통해 타이타닉 승객의 생존 여부를 잘 분류할 수 있었음을 알 수 있다.

다중 선형 회귀 분석은 여러 개의 독립 변수를 사용하여 하나의 종속 변수를 예측하는 방법이다. 타이타닉 데이터셋에서 다중 선형 회귀 분석을 수행하여 티켓 요금(fare)을 예측해 보겠다. 주요 독립 변수로는 age, pclass, sibsp, parch를 사용하겠다.

1. 다중 선형 회귀 분석 코드

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import numpy as np

# 분석에 사용할 변수 선택
X = titanic[['age', 'pclass', 'sibsp', 'parch']]
y = titanic['fare']

# 결측값 제거
X = X.dropna()
y = y.loc[X.index]

# 학습 및 테스트 데이터 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 선형 회귀 모델 생성 및 학습
model = LinearRegression()
model.fit(X_train, y_train)

# 회귀 계수 출력
print("회귀 계수:", model.coef_)
print("절편:", model.intercept_)

# 테스트 데이터로 예측
y_pred = model.predict(X_test)

# 모델 성능 평가 (R² 스코어)
r2_score = model.score(X_test, y_test)
print(f"R² 스코어: {r2_score:.2f}")

코드 해석

  • 회귀 계수: 각 독립 변수(age, pclass, sibsp, parch)가 종속 변수인 fare에 미치는 영향의 크기를 나타낸다. 음수 값은 해당 변수가 증가할 때 fare가 감소함을 의미하고, 양수 값은 증가할 때 fare가 증가함을 의미한다.
  • 절편: 모든 독립 변수가 0일 때 예측된 fare 값이다.
  • R² 스코어: 모델의 설명력을 나타냅니다. 1에 가까울수록 독립 변수들이 종속 변수를 잘 설명한다는 의미이며, 0에 가까울수록 설명력이 부족함을 나타낸다.

1. 회귀 계수

  • 나이가 1살 증가할 때마다 요금(fare)은 약 0.11 단위 감소한다. 하지만 이 값이 상대적으로 작기 때문에 나이가 요금에 미치는 영향은 크지 않다고 볼 수 있다.
  • 객실 등급이 1 증가(즉, 더 낮은 등급으로 이동)할 때마다 요금은 약 34.59 단위 감소한다. 이는 객실 등급이 요금에 매우 중요한 영향을 미친다는 것을 의미한다. 1등급 승객이 평균적으로 더 비싼 요금을 지불한 것으로 해석할 수 있다.
  • 형제나 배우자가 1명 더 있을 때 요금은 5.46 단위 증가한다. 가족 구성원이 많은 승객이 더 높은 요금을 지불했을 가능성이 있다.
  • 부모나 자녀가 1명 더 있을 때 요금은 10.31 단위 증가한다. 가족이 많을수록 요금이 더 높아진다는 경향을 보인다

2. R² 스코어: 0.43

  • R² 값은 0.43으로, 이 모델은 요금(fare) 변동의 약 43%를 설명한다. 즉, 사용된 변수들(나이, 객실 등급, 형제/배우자 수, 부모/자녀 수)이 요금을 예측하는 데 어느 정도 유의미한 영향을 미치지만, 모델의 설명력은 43%로 다소 제한적이다.
  • 나머지 57%의 요금 변동은 이 모델에서 설명하지 못한 다른 요인들(예: 승객의 직업, 사회적 지위 등)에 의해 설명될 가능성이 있다.

다음으로 데이터 모델링을 통해 타이타닉 데이터에서 승객의 생존 여부를 예측하거나, 다른 중요한 변수들을 예측하는 모델을 구축할 수 있다. 이 과정에서는 다양한 머신러닝 모델을 사용하여 생존 여부를 예측하고, 성능을 비교하는 방식으로 진행할 것이다.

1. 데이터 전처리

2. 모델 선택 및 학습

3. 모델 평가

4. 모델 성능 비교

1. 데이터 전처리

먼저, 범주형 변수의 인코딩과 결측값 처리를 진행한 후 모델링에 사용할 변수를 선택한다.

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 타이타닉 데이터셋 로드
titanic = sns.load_dataset('titanic')

# 결측값 처리
titanic['age'].fillna(titanic['age'].mean(), inplace=True)
titanic['embarked'].fillna(titanic['embarked'].mode()[0], inplace=True)

# 성별 변수 인코딩 (남성: 0, 여성: 1)
titanic['sex'] = titanic['sex'].map({'male': 0, 'female': 1})

# 필요한 변수 선택
X = titanic[['sex', 'age', 'pclass', 'fare', 'sibsp', 'parch']]
y = titanic['survived']

# 학습 및 테스트 데이터 분할 (7:3)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 데이터 표준화 (필요에 따라)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

2. 모델 선택 및 학습

여기서 다양한 모델을 선택하여 학습을 진행해 보겠다. 로지스틱 회귀, 랜덤 포레스트, 서포트 벡터 머신(SVM), 의사 결정 트리 등의 기법을 사용할 수 있다.

로지스틱 회귀

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report

# 로지스틱 회귀 모델 학습
log_reg = LogisticRegression()
log_reg.fit(X_train_scaled, y_train)

# 예측 및 성능 평가
y_pred_log_reg = log_reg.predict(X_test_scaled)
accuracy_log_reg = accuracy_score(y_test, y_pred_log_reg)

print(f"로지스틱 회귀 정확도: {accuracy_log_reg}")
print(classification_report(y_test, y_pred_log_reg))

로지스틱 회귀(Logistic Regression)

  • 정확도: 80.97%
  • 정밀도(precision)
    • 클래스 0: 0.81
    • 클래스 1: 0.81
  • 재현율(recall)
    • 클래스 0: 0.88 (생존하지 않은 승객을 잘 예측)
    • 클래스 1: 0.71 (생존한 승객을 예측하는 데 다소 부족)
  • F1-스코어
    • 클래스 0: 0.84
    • 클래스 1: 0.76

로지스틱 회귀는 생존하지 않은 승객(클래스 0)에 대해 높은 재현율을 보였으나, 생존한 승객(클래스 1)에 대한 재현율은 조금 낮았다. 전반적으로 정확도는 81%로 양호하다.

랜덤 포레스트

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report

# 랜덤 포레스트 모델 생성 및 학습
forest_model = RandomForestClassifier(n_estimators=100, random_state=42)
forest_model.fit(X_train, y_train)

# 예측 및 평가
y_pred_forest = forest_model.predict(X_test)
print("랜덤 포레스트 정확도:", accuracy_score(y_test, y_pred_forest))
print(classification_report(y_test, y_pred_forest))

랜덤 포레스트(Random Forest)

  • 정확도: 79.85%
  • 정밀도(precision)
    • 클래스 0: 0.80
    • 클래스 1: 0.79
  • 재현율(recall)
    • 클래스 0: 0.87
    • 클래스 1: 0.69
  • F1-스코어
    • 클래스 0: 0.84
    • 클래스 1: 0.74

랜덤 포레스트는 클래스 0에 대한 재현율이 높아 생존하지 않은 승객을 잘 예측하는 반면, 클래스 1에 대한 재현율은 다소 낮다. 전반적인 정확도는 80%로, 로지스틱 회귀와 비슷한 수준의 성능을 보인다.

서포트 벡터 머신(SVM)

from sklearn.svm import SVC

# 서포트 벡터 머신 학습
svm_model = SVC()
svm_model.fit(X_train_scaled, y_train)

# 예측 및 성능 평가
y_pred_svm = svm_model.predict(X_test_scaled)
accuracy_svm = accuracy_score(y_test, y_pred_svm)
print(f"SVM 정확도: {accuracy_svm:}")
print(classification_report(y_test, y_pred_svm))

서포트 벡터 머신(SVM)

  • 정확도: 82.83%
  • 정밀도(precision)
    • 클래스 0: 0.82
    • 클래스 1: 0.84
  • 재현율(recall)
    • 클래스 0: 0.90
    • 클래스 1: 0.73
  • F1-스코어
    • 클래스 0: 0.86
    • 클래스 1: 0.78

평가: SVM은 정확도가 82.83%로 가장 높은 성능을 보였다. 생존하지 않은 승객에 대해 높은 재현율을 보이고 있으며, 생존한 승객에 대해서도 적절한 예측을 하고 있다. 전반적으로 균형 잡힌 성능을 보이는 모델이다.

의사 결정 트리

from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report

# 의사결정 트리 모델 생성 및 학습
tree_model = DecisionTreeClassifier()
tree_model.fit(X_train, y_train)

# 예측 및 평가
y_pred_tree = tree_model.predict(X_test)
print("의사결정 트리 정확도:", accuracy_score(y_test, y_pred_tree))
print(classification_report(y_test, y_pred_tree))

의사 결정 트리(Decision Tree)

  • 정확도: 64.93%
  • 정밀도(precision)
    • 클래스 0: 0.67
    • 클래스 1: 0.60
  • 재현율(recall)
    • 클래스 0: 0.80
    • 클래스 1: 0.44 (생존한 승객을 예측하는 데 매우 부족)
  • F1-스코어
    • 클래스 0: 0.73
    • 클래스 1: 0.51

의사결정 트리는 생존하지 않은 승객(클래스 0)에 대한 재현율은 양호하지만, 생존한 승객(클래스 1)에 대한 재현율이 0.44로 매우 낮다. 따라서 생존자 예측에 어려움이 있는 모델이다. 전체적으로 65%의 정확도로, 다른 모델들에 비해 성능이 낮다.

모델 성능 비교

모델정확도클래스 0 F1-score클래스 1 F1-score
로지스틱 회귀80.97%0.840.76
의사결정 나무64.93%0.730.51
랜덤 포레스트79.85%0.840.74
SVM82.83%0.860.78

SVM(Support Vector Machine)의 성능을 향상시키기 위해서는 하이퍼파라미터 튜닝특징 선택을 고려할 수 있다. SVM의 핵심 하이퍼파라미터인 C, gamma, 커널(kernel) 등의 값을 최적화하고, 교차검증을 통해 모델의 성능을 향상시킬 수 있다.

1. GridSearchCV를 사용한 하이퍼파라미터 튜닝

GridSearchCV를 사용해 SVM의 하이퍼파라미터 조합을 테스트하고, 가장 성능이 좋은 조합을 선택하는 방법이다.

하이퍼파라미터

  • C: 모델의 규제 강도를 조절한다. 큰 값일수록 규제가 적고, 작은 값일수록 규제가 강해진다.
  • gamma: 결정 경계의 복잡성을 조정하는 파라미터로, RBF 커널에서 사용된다.
  • kernel: SVM에서 사용하는 커널 종류 (linear, poly, rbf, sigmoid 등).
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report

# 하이퍼파라미터 그리드 설정
param_grid = {
    'C': [0.1, 1, 10, 100],               # C 값 후보
    'gamma': [1, 0.1, 0.01, 0.001],       # gamma 값 후보
    'kernel': ['rbf', 'poly', 'sigmoid']   # 커널 후보
}

# GridSearchCV를 사용한 하이퍼파라미터 튜닝
grid = GridSearchCV(SVC(), param_grid, refit=True, verbose=2, cv=5)
grid.fit(X_train_scaled, y_train)

# 최적의 하이퍼파라미터 출력
print("최적의 하이퍼파라미터:", grid.best_params_)

# 테스트 데이터에 대해 예측 및 평가
y_pred_grid = grid.predict(X_test_scaled)
print(f"최적 SVM 모델 정확도: {accuracy_score(y_test, y_pred_grid):.2f}")
print(classification_report(y_test, y_pred_grid))

하이퍼파라미터 설명

  • C: 규제 파라미터. 큰 값일수록 과적합될 가능성이 있고, 작은 값일수록 일반화 성능이 향상된다.
  • gamma: RBF 커널에서 중요한 파라미터로, 데이터 포인트가 영향을 미치는 범위를 결정한다. 작은 값은 더 넓은 범위에서 영향을 미치고, 큰 값은 더 좁은 범위에서 영향을 미친다.
  • kernel: SVM에서 결정 경계를 그리는 방식이다. linear는 선형, rbf는 비선형 커널이다.

2. 교차검증(K-Fold Cross Validation)

모델의 성능을 더 신뢰할 수 있도록 하기 위해 교차검증을 사용할 수 있다. 교차검증은 데이터를 여러 번 나누어 학습 및 검증하여, 훈련 데이터와 테스트 데이터에 대한 성능 차이를 줄여준다.

from sklearn.model_selection import cross_val_score

# 최적화된 SVM 모델에서 교차검증 실행
cross_val_scores = cross_val_score(grid.best_estimator_, X_train_scaled, y_train, cv=5)
print("교차검증 정확도:", cross_val_scores.mean())

최적화된 SVM 모델 결과 분석

최적의 하이퍼파라미터

  • C: 1 (적당한 규제 강도)
  • gamma: 0.1 (결정 경계의 복잡도를 적당히 조절)
  • kernel: ‘rbf’ (비선형 데이터를 처리하는 커널)

최적 SVM 모델 정확도: 83%

  • 정확도는 83%로, 이전 SVM 모델과 동일한 수준의 성능을 보였다.
  • 정밀도(precision)
  • 클래스 0 (생존하지 않은 승객): 0.82
  • 클래스 1 (생존한 승객): 0.84
  • 재현율(recall)
  • 클래스 0: 0.90 (생존하지 않은 승객을 잘 예측)
  • 클래스 1: 0.73 (생존한 승객을 예측하는 데 다소 부족)
  • F1-score
  • 클래스 0: 0.86
  • 클래스 1: 0.78

교차검증 정확도: 82.02%

  • 교차검증을 통해 얻은 정확도가 82.02%로, 최종 모델의 일반화 성능이 높은 것으로 확인되었다. 이는 모델이 과적합되지 않고 적절하게 학습되었음을 의미한다.

SVM 모델의 성능을 더 향상시키기 위해 다음과 같은 추가적인 방법들을 사용할 수 있다.

1. SMOTE(Synthetic Minority Over-sampling Technique) 데이터 불균형 해결

현재 생존하지 않은 승객(클래스 0)과 생존한 승객(클래스 1) 간에 약간의 불균형이 존재한다. 이를 해결하기 위해 SMOTE를 사용하여 소수 클래스의 데이터를 증가시키면 성능을 향상시킬 수 있다.

from imblearn.over_sampling import SMOTE
from sklearn.model_selection import train_test_split

# SMOTE 적용
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X_train_scaled, y_train)

# 다시 SVM 모델 학습
svm_model_smote = SVC(C=1, gamma=0.1, kernel='rbf')
svm_model_smote.fit(X_resampled, y_resampled)

# 테스트 데이터로 예측
y_pred_smote = svm_model_smote.predict(X_test_scaled)
accuracy_smote = accuracy_score(y_test, y_pred_smote)
print(f"SMOTE 적용 후 SVM 모델 정확도: {accuracy_smote:.2f}")
print(classification_report(y_test, y_pred_smote))
  • SMOTE는 소수 클래스의 데이터를 인위적으로 증가시켜 모델이 소수 클래스(생존한 승객)를 더 잘 학습할 수 있게 한다. 이를 통해 재현율(recall)이 향상될 수 있다.

SMOTE 적용 후 SVM

  • 정확도: 82%
  • 정밀도
    • 클래스 0: 0.82
    • 클래스 1: 0.81
  • 재현율
    • 클래스 0: 0.88 (생존하지 않은 승객을 잘 예측)
    • 클래스 1: 0.73 (생존한 승객을 예측하는 데 다소 부족)
  • F1-score
    • 클래스 0: 0.85
    • 클래스 1: 0.77
  • SMOTE를 통해 소수 클래스인 생존한 승객을 더 잘 학습시킴으로써 성능이 약간 향상되었다.
  • 클래스 1의 재현율이 약간 증가하여, 생존자 예측에서의 성능이 개선되었다.

2. 하이퍼파라미터 최적화 범위 확장

현재 GridSearchCV로 탐색한 하이퍼파라미터 범위를 확장하거나, Bayesian Optimization 같은 기법을 통해 더 다양한 파라미터 조합을 탐색할 수 있다.

랜덤 서치(RandomizedSearchCV)

GridSearchCV 대신 RandomizedSearchCV를 사용하여 더 넓은 범위의 하이퍼파라미터 조합을 무작위로 탐색할 수 있다.

from sklearn.model_selection import RandomizedSearchCV
import numpy as np

# 랜덤 서치를 위한 하이퍼파라미터 공간 정의
param_distributions = {
    'C': np.logspace(-3, 2, 10),  # C 값의 로그 스케일 탐색
    'gamma': np.logspace(-4, 1, 10),  # gamma 값의 로그 스케일 탐색
    'kernel': ['rbf', 'poly', 'sigmoid']  # 여러 커널 테스트
}

# RandomizedSearchCV 적용
random_search = RandomizedSearchCV(SVC(), param_distributions, n_iter=50, cv=5, verbose=2, random_state=42, n_jobs=-1)
random_search.fit(X_train_scaled, y_train)

# 최적의 하이퍼파라미터 출력
print("최적의 하이퍼파라미터:", random_search.best_params_)

# 테스트 데이터로 예측
y_pred_random_search = random_search.predict(X_test_scaled)
accuracy_random_search = accuracy_score(y_test, y_pred_random_search)
print(f"RandomizedSearchCV 적용 후 SVM 모델 정확도: {accuracy_random_search:.2f}")
print(classification_report(y_test, y_pred_random_search))

랜덤 서치의 장점

  • GridSearchCV는 모든 조합을 탐색하므로 시간이 오래 걸릴 수 있지만, RandomizedSearchCV는 무작위로 몇 가지 조합만 탐색하여 더 빠르게 최적의 하이퍼파라미터를 찾을 수 있다.
  • 더 넓은 범위를 무작위로 탐색하므로 더 나은 성능을 얻을 가능성이 있다.

RandomizedSearchCV 적용 후 SVM

  • 최적의 하이퍼파라미터: {‘kernel’: ‘poly’, ‘gamma’: 0.0599, ‘C’: 100.0}
  • 정확도: 80%
  • 정밀도
    • 클래스 0: 0.79
    • 클래스 1: 0.81
  • 재현율
    • 클래스 0: 0.89
    • 클래스 1: 0.68
  • F1-score
    • 클래스 0: 0.84
    • 클래스 1: 0.74
  • 최적의 하이퍼파라미터를 찾았으나, 정확도는 80%로 다소 낮아다.
  • poly 커널이 최적화되었지만, 생존자 예측에서는 약간 부족한 성능을 보였다.
  • SMOTE 적용 후의 SVM 모델보다 성능이 다소 낮았다.

3. 특성 엔지니어링 및 추가 변수 생성

모델의 성능을 높이기 위해 새로운 특성을 추가하거나, 기존 특성을 변환하여 추가적인 정보를 제공하는 방법이다.

가족 크기 변수 추가

  • sibsp(형제/배우자 수)와 parch(부모/자녀 수)를 더해 family_size라는 새로운 변수를 생성하고 이를 모델에 포함시키면 성능이 향상될 수 있다.
# 새로운 특성(family_size) 생성
titanic['family_size'] = titanic['sibsp'] + titanic['parch'] + 1

# 가족 크기를 포함한 새로운 변수 선택
X = titanic[['sex', 'age', 'pclass', 'fare', 'family_size']]
y = titanic['survived']

# 데이터 나누기 및 표준화 다시 수행
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# SVM 모델 다시 학습
svm_model_new = SVC(C=1, gamma=0.1, kernel='rbf')
svm_model_new.fit(X_train_scaled, y_train)

# 테스트 데이터로 예측
y_pred_new = svm_model_new.predict(X_test_scaled)
accuracy_new = accuracy_score(y_test, y_pred_new)
print(f"새로운 특성 추가 후 SVM 모델 정확도: {accuracy_new:.2f}")
print(classification_report(y_test, y_pred_new))

새로운 특징 추가 후 SVM

  • 정확도: 82%
  • 정밀도
    • 클래스 0: 0.82
    • 클래스 1: 0.83
  • 재현율
    • 클래스 0: 0.90
    • 클래스 1: 0.71
  • F1-score
    • 클래스 0: 0.85
    • 클래스 1: 0.77
  • family_size라는 새로운 특성을 추가한 후, 정확도가 82%로 유지되었으며, 클래스 1(생존자)에 대한 성능이 약간 향상되었다.
  • SMOTE 적용 후와 성능이 유사하지만, 특징 추가가 데이터의 더 많은 정보를 반영하는 데 도움이 되었음을 알 수 있다.

4. 앙상블 기법 적용

앙상블 모델을 적용하여 성능을 더 높일 수 있다. 예를 들어, SVM, 랜덤 포레스트, 로지스틱 회귀의 예측 결과를 앙상블하여 최종 결정을 내리는 방식이다.

from sklearn.ensemble import VotingClassifier

# 앙상블 모델 생성
ensemble_model = VotingClassifier(estimators=[
    ('svm', SVC(C=1, gamma=0.1, kernel='rbf', probability=True)),
    ('rf', RandomForestClassifier(n_estimators=100, random_state=42)),
    ('lr', LogisticRegression())
], voting='soft')

ensemble_model.fit(X_train_scaled, y_train)

# 테스트 데이터로 예측
y_pred_ensemble = ensemble_model.predict(X_test_scaled)
accuracy_ensemble = accuracy_score(y_test, y_pred_ensemble)
print(f"앙상블 모델 정확도: {accuracy_ensemble:.2f}")
print(classification_report(y_test, y_pred_ensemble))

앙상블 설명

  • 여러 모델의 예측을 평균하여 더 정확한 결정을 내린다. Voting Classifier는 여러 모델을 결합하여 각각의 강점을 활용할 수 있다.
  • 다양한 모델의 예측을 결합하면 단일 모델보다 더 안정적이고 강력한 성능을 얻을 수 있다.

앙상블 모델

  • 정확도: 82%
  • 정밀도
    • 클래스 0: 0.82
    • 클래스 1: 0.84
  • 재현율
    • 클래스 0: 0.90
    • 클래스 1: 0.71
  • F1-score
    • 클래스 0: 0.86
    • 클래스 1: 0.77
  • 앙상블 모델은 다양한 모델의 강점을 결합하여 전체적인 성능을 82%로 유지했다.
  • SVM, 로지스틱 회귀, 랜덤 포레스트의 예측을 결합하여, 생존하지 않은 승객(클래스 0)에 대한 높은 재현율을 유지하면서 생존한 승객(클래스 1)의 예측 성능도 개선되었다.

앙상블 모델을 사용하여 타이타닉 데이터의 생존 여부를 예측하고, 성능을 최적화해 보겠다. VotingClassifier를 사용하여 다양한 모델(SVM, 랜덤 포레스트, 로지스틱 회귀)을 결합한 앙상블 모델을 구성할 것이다.

앙상블 모델 생성 및 학습

아래는 앙상블 모델을 구성하고, 학습 및 평가를 수행하는 코드다

from sklearn.ensemble import VotingClassifier
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report

# 개별 모델 정의
svm_model = SVC(C=1, gamma=0.1, kernel='rbf', probability=True, random_state=42)
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
log_reg_model = LogisticRegression(random_state=42)

# 앙상블 모델 생성 (소프트 보팅)
ensemble_model = VotingClassifier(
    estimators=[
        ('svm', svm_model),
        ('rf', rf_model),
        ('lr', log_reg_model)
    ],
    voting='soft'  # 소프트 보팅 사용
)

# 앙상블 모델 학습
ensemble_model.fit(X_train_scaled, y_train)

# 테스트 데이터에 대해 예측 및 평가
y_pred_ensemble = ensemble_model.predict(X_test_scaled)
accuracy_ensemble = accuracy_score(y_test, y_pred_ensemble)
print(f"앙상블 모델 정확도: {accuracy_ensemble:.2f}")
print(classification_report(y_test, y_pred_ensemble))

앙상블 모델 설명

  • VotingClassifier: 여러 분류기의 예측 결과를 결합하여 최종 결과를 도출한다.
  • 소프트 보팅(soft voting): 각 모델의 예측 확률 값을 평균하여 최종 클래스를 결정한다. 각 모델의 예측 강도를 반영하기 때문에 일반적으로 소프트 보팅하드 보팅(각 모델의 투표로 다수결 결정)보다 더 나은 성능을 보인다.
  • 사용된 모델:
    • SVM: 비선형 특성을 잘 학습할 수 있다.
    • 랜덤 포레스트: 여러 결정 트리를 결합하여 과적합을 방지하고, 데이터의 다양한 패턴을 학습할 수 있다.
    • 로지스틱 회귀: 해석이 용이하고, 기본적인 선형 분류 성능을 제공한다.

앙상블 모델의 성능 결과는 다음과 같다.

  • 정확도(Accuracy): 82%
  • 전체적으로 예측의 정확도가 82%로 나타났다. 이는 이전의 모델들과 유사한 수준이다.
  • 정밀도(Precision)
  • 클래스 0 (생존하지 않은 승객): 0.82
  • 클래스 1 (생존한 승객): 0.84
  • 생존한 승객(클래스 1)에 대한 정밀도가 높아, 양성으로 예측된 값 중 실제로 생존한 비율이 높다는 것을 의미한다.
  • 재현율(Recall)
  • 클래스 0: 0.90 (생존하지 않은 승객을 잘 예측)
  • 클래스 1: 0.71 (생존한 승객을 예측하는 데 약간 부족)
  • 생존하지 않은 승객(클래스 0)에 대한 재현율이 매우 높아, 생존하지 않은 경우를 잘 예측하고 있음을 보여준다.
  • F1-score
  • 클래스 0: 0.86
  • 클래스 1: 0.77
  • F1-score는 정밀도와 재현율의 조화를 나타내며, 클래스 0의 값이 더 높아 생존하지 않은 승객 예측에서 더 좋은 성능을 보인다.

다음은 입력받은 정보를 바탕으로 타이타닉 승객의 생존 여부를 예측할 수 있는 코드다. 정보 입력을 받아 모델에서 예측할 수 있도록 특성 값을 처리하고, 예측 결과를 출력하도록 할 것이다.

필요한 입력 정보

  • 성별: ‘male’ 또는 ‘female’
  • 나이: 숫자(예: 25)
  • 객실 등급: 1, 2, 3 중 선택
  • 형제/배우자 수 (sibsp): 숫자(예: 0)
  • 부모/자녀 수 (parch): 숫자(예: 0)
  • 티켓 요금 (fare): 숫자(예: 50)
import numpy as np

def predict_survival():
    # 사용자 입력 받기
    sex = input("성별 (male/female): ").strip().lower()
    age = float(input("나이: "))
    pclass = int(input("객실 등급 (1, 2, 3): "))
    sibsp = int(input("형제/배우자 수: "))
    parch = int(input("부모/자녀 수: "))
    fare = float(input("티켓 요금: "))

    # 성별을 숫자로 변환 ('male' = 0, 'female' = 1)
    sex = 1 if sex == 'female' else 0

    # 새로운 특징 계산 (예: family_size)
    family_size = sibsp + parch + 1

    # 입력 데이터를 배열로 준비 (특성 순서에 맞게)
    input_data = np.array([[sex, age, pclass, fare, family_size]])

    # 데이터 표준화
    input_data_scaled = scaler.transform(input_data)

    # 예측 수행
    prediction = ensemble_model.predict(input_data_scaled)
    prediction_proba = ensemble_model.predict_proba(input_data_scaled)[0]

    # 결과 출력
    if prediction[0] == 1:
        print(f"\n생존할 가능성이 높습니다! (생존 확률: {prediction_proba[1] * 100:.2f}%)")
    else:
        print(f"\n생존하지 않을 가능성이 높습니다. (사망 확률: {prediction_proba[0] * 100:.2f}%)")

# 함수 실행
predict_survival()

티켓 요금(fare)의 적절한 입력 범위는 타이타닉 데이터의 실제 요금 분포를 기반으로 설정하는 것이 좋다. 타이타닉 데이터셋에서 티켓 요금의 통계 요약을 살펴보면 다음과 같다.

  • 최소값: 0 (일부 승객의 요금)
  • 25% 백분위수: 약 7.91 (하위 25%의 요금)
  • 중앙값(50% 백분위수): 약 14.45 (중간 값)
  • 75% 백분위수: 약 31.00 (상위 25%의 요금)
  • 최대값: 512.33 (일부 상류층 승객의 요금)

추천 입력 범위

  • 일반적인 요금 범위: 7.91에서 31.00 사이가 대부분의 승객들이 지불한 요금이다.
  • 중간 수준 요금: 10에서 50 사이를 입력하는 것이 일반적인 범위로 볼 수 있다.
  • 상류층 승객의 요금: 50 이상을 입력하면, 1등석에서 상대적으로 더 비싼 티켓을 구매한 상류층 승객에 해당한다.
  • 무료 또는 저렴한 티켓: 0에서 7.91까지는 할인 티켓이나 일부 무료 티켓을 받은 승객에 해당한다.
  • 일반적으로 7.91에서 50 사이를 추천한다.
  • 최저값은 0부터 최대값 512.33까지 존재하지만, 100을 넘는 경우는 매우 드물다.
  • 중간값이 약 14.45이므로, 일반적인 승객의 티켓 요금으로 이 범위를 기준으로 입력하는 것이 적절하다.

예측 결과 해석

아래의 입력값을 바탕으로 한 두 가지 예측 결과를 비교해보면 성별이 생존 가능성에 큰 영향을 미친다는 점을 확인할 수 있다.

  1. 첫 번째 시나리오 (여성 승객):
  • 성별: female
  • 나이: 40
  • 객실 등급: 2등급
  • 형제/배우자 수: 2
  • 부모/자녀 수: 2
  • 티켓 요금: 14.25 예측 결과는 “생존할 가능성이 높습니다! (생존 확률: 69.32%)”로, 여성 승객의 생존 확률이 69.32%로 높게 나왔다.
  1. 두 번째 시나리오 (남성 승객):
  • 성별: male
  • 나이: 40
  • 객실 등급: 2등급
  • 형제/배우자 수: 2
  • 부모/자녀 수: 2
  • 티켓 요금: 14.25 예측 결과는 “생존하지 않을 가능성이 높습니다. (사망 확률: 88.22%)”로, 남성 승객의 생존 확률이 매우 낮게 나왔다.

주요 관찰점

  • 성별의 영향
  • 타이타닉 생존 데이터에서는 여성이 구조 우선순위에 있었기 때문에, 같은 나이와 다른 조건임에도 불구하고 여성의 생존 확률이 남성보다 훨씬 높게 예측되는 경향이 있다.
  • 이는 당시 ‘여성과 어린이 우선 구조’라는 규칙이 적용되었음을 반영한다.
  • 다른 조건들의 동일성
  • 두 시나리오 모두 같은 나이, 같은 객실 등급, 같은 가족 구성원 수, 같은 요금을 갖고 있지만, 예측 결과에서 큰 차이를 보이는 것은 성별에 따른 구조 우선순위가 모델에 반영되었기 때문이다.

결론

  • 타이타닉 데이터셋에서는 성별이 생존 여부를 결정하는 데 있어 중요한 변수임을 확인할 수 있다.
  • 이 예측 결과는 모델이 데이터를 기반으로 역사적 현실을 잘 반영하고 있음을 보여준다.
  • 다른 변수들도 영향을 미치겠지만, 여성 승객의 생존 확률이 높은 이유는 사회적 구조와 관련된 것이다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤