타이타닉 데이터로 실습해보고자 한다.
info()로 확인한 타이타닉 데이터의 컬럼별 정보이다.
데이터 분석은 아래의 단계로 이루어짐.
1. 데이터 로드 및 분리 (test / train)
2. 탐색적 데이터 분석(EDA)
데이터 분포 및 이상치 확인
3. 데이터 전처리
이상치 처리
결측치 처리
수치형/범주형 전처리 (스케일링 / 인코딩)
4. 모델 학습
5. 모델 평가
1. 데이터 로드 및 분리
라이브러리를 불러와준다.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
타이타닉 데이터의 경우 이미 train / test 데이터로 분리되어 있기 때문에 파일 경로만 복사해서 넣어주면 되었다.
train_df = pd.read_csv("C:/Users/jojoo/OneDrive/바탕 화면/sparta_python/titanic/train.csv", encoding = 'utf-8') test_df = pd.read_csv("C:/Users/jojoo/OneDrive/바탕 화면/sparta_python/titanic/test.csv", encoding = 'utf-8')
데이터를 분리해서 모델링을 진행하는 이유)
-> 데이터를 과도하게 학습하여 해당 데이터로만 예측/분류를 할 수 있는 과적합(overfitting) 문제 발생을 방지
train : 모델을 학습(fit) 시키기 위한 데이터
test : 모델을 평가 하기 위한 데이터
불충분한 데이터, 과도한 반복 학습(딥러닝), 데이터 불균형의 이유로도 과적합이 발생할 수 있음.
보통은 다음 그림과 같이 train과 test를 7:3 비율로 나눔.
위의 0.97 / 0.4 데이터의 경우 한 모델만 학습하여 과적합이 나오는 예시
train과 test로 데이터 분리
- sklearn.model_selection.train_test_split
함수 안의 파라미터
- test_size : 테스트 데이터 세트의 크기
- train_size : 학습 데이터 세트의 크기
- shuffle : 데이터 분리 시 섞기
- random_state : 호출할 때마다 동일 학습/테스트 데이터를 생성하기 위한 난수 값, 수행할 때마다 동일한 데이터 세트로 분리하기 위하여 숫자를 고정
반환 값(순서 중요함)
- X_train, X_test, y_train, y_test
2. train 데이터 EDA
먼저 train 데이터의 결측치와 이상치를 확인하기 위해 기술통계를 해보았다.
Age, Cabin, Embarked 컬럼에 결측치가 존재하고, Fare 컬럼에 512.329200의 이상치라고 판단되는 값이 들어있다.
SibSp, Parch를 합쳐 family라는 컬럼으로 만들어주었다.
# 2: 기초가공, Family 변수 생성
train_df_2 = train_df.copy()
def get_family(df):
df['family'] = df['SibSp'] + df['Parch'] + 1
return df
get_family(train_df_2).head(3)
+1을 해준 이유는 총 가족 수이기 때문에 본인도 합해주기 위함.
pairplot으로 숫자형 데이터들의 분포를 확인
sns.pairplot(train_df_2[['Age','Fare','family']])
3. train 데이터 전처리
1) Fare 컬럼 이상치 처리
대부분의 요금이 100 미만인 것에 비해 512는 너무 과도한 이상치라고 판단
# Fare 512 넘는 이상치 삭제
train_df_2 = train_df_2[train_df_2['Fare'] < 512]
train_df_2.shape
<888,13>
총 세개의 행이 삭제된 것을 볼 수 있음.
3개의 행은 데이터를 분석하는데 있어 큰 영향을 끼치지 않을 것이라 판단했기에 삭제.
다시 기술통계(describe)로 정보를 확인해보자.
train_df_2['Fare'].describe()
2) Age, Embarked 결측치 처리
Age의 경우 평균값으로 대치, Embarked의 경우 최빈값 S로 대치
def get_nan_missing(df):
Age_mean = train_df_2['Age'].mean()
#train 데이터에는 필요하지 않으나 test 데이터 결측치를 위해 추가
Fare_mean = train_df_2['Fare'].mean()
df['Age'] = df['Age'].fillna(Age_mean)
df['Fare'] = df['Fare'].fillna(Fare_mean)
df['Embarked'] = df['Embarked'].fillna('S')
return df
get_nan_missing(train_df_2)
train_df_2.info()
Age와 Embarked 의 결측치가 채워진 것을 확인할 수 있다.
Cabin은 결측치가 너무 많기때문에 결과에 영향을 줄 수 있기 때문에 제외.
3) 데이터 전처리(인코딩, 스케일링)
사용할 범주형, 숫자형 데이터에 대한 전처리를 진행
스케일링
먼저 수치형 데이터 스케일링을 해보자.
Fare 컬럼은 분포가 치우쳐져 있기때문에 StandardScaler, Age는 분포가 균일하기 때문에 MinMaxScaler, family는 분포가 균일하진 않지만, 값이 작기 때문에 MinMaxScaler
참고) 함수를 작성할 때, 학습은 train_df_2로 진행하고 실제 결과물의 저장은 df(인풋 데이터)로 되게 하는 것이 중요함.
test 학습 진행 때 함수를 똑같이 적용해야하기 때문
def get_numberic_sc(df):
# sd_sc : Fare, mm_sc = family, Age
from sklearn.preprocessing import StandardScaler, MinMaxScaler
sd_sc = StandardScaler()
mm_sc = MinMaxScaler()
sd_sc.fit(train_df_2[['Fare']])
df['Fare_sd_sc'] = sd_sc.transform(df[['Fare']])
mm_sc.fit(train_df_2[['Age', 'family']])
df[['Age__mm_sc', 'family_mm_sc']] = mm_sc.transform(df[['Age', 'family']])
return df
train_df_2 = get_numberic_sc(train_df_2)
데이터가 잘 변환돼서 들어갔는지 확인
인코딩
다음으로 범주형 데이터 전처리
Pclass는 순서형이기 때문에 LabelEncoder, Sex는 두 개기 때문에 LabelEncoder, Embarked는 순서형 데이터가 아니기 때문에 OneHotEncoder를 사용
def get_category(df):
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
le = LabelEncoder()
le2 = LabelEncoder()
oe = OneHotEncoder()
le.fit(train_df_2[['Pclass']])
df['Pclass_le'] = le.transform(df['Pclass'])
le2.fit(train_df_2[['Sex']])
df['Sex_le'] = le2.transform(df['Sex'])
#index reset을 하기위한 구문, test에서 오류 발생
df = df.reset_index()
oe.fit(train_df_2[['Embarked']])
Embarked_csr = oe.transform(df[['Embarked']])
Embarked_csr_df = pd.DataFrame(Embarked_csr.toarray(), columns = oe.get_feature_names_out())
df = pd.concat([df, Embarked_csr_df], axis = 1)
return df
train_df_2 = get_category(train_df_2)
OneHotEncoder 는 다른 것과 다르게 transform으로 적용시키기만 할 시 오류 발생.
함수 적용 후 array로 변환하여 DataFrame으로 저장해서 기존 데이터에 concat으로 붙여줘야 한다.
잘 들어간 것을 확인.
4. train 모델 학습
def get_model(df):
from sklearn.linear_model import LogisticRegression
model_lor = LogisticRegression()
X = df[['Age__mm_sc', 'Fare_sd_sc', 'family_mm_sc', 'Pclass_le', 'Sex_le', 'Embarked_C', 'Embarked_Q', 'Embarked_S']]
y = df[['Survived']] model_lor.fit(X,y)
return model_lor
model_output = get_model(train_df_2) # 모델훈련
y_pred = model_output.predict(X) # X예측값
5. train 평가
결과적으로 높은 정확도와 f1_score가 나옴.
from sklearn.metrics import accuracy_score, f1_score
print(accuracy_score(train_df_2['Survived'], y_pred))
print(f1_score(train_df_2['Survived'], y_pred))
이제 test 데이터로 모델 훈련과 평가를 진행해보자.
1. test 데이터 EDA
먼저 test 데이터를 확인해보자.
x 트레인 값을 eda 했을 경우,
x 테스트도 똑같이 했던 과정 다 진행해야함.
함수들을 적용해보자.
test_df_2 = get_family(test_df)
test_df_2 = get_nan_missing(test_df_2)
test_df_2 = get_numberic_sc(test_df_2)
test_df_2 = get_category(test_df_2)
2. test 데이터 모델 학습
test 데아터도 모델 훈련을 진행하고 예측값을 구한다.
y_test_pred는 최종 Survived에 대한 예측값이 0,1로 저장된 형태
즉, X의 컬럼들을 기반으로 Survived를 예측한 분석 결과
test_X = test_df_2[['Age__mm_sc', 'Fare_sd_sc', 'family_mm_sc', 'Pclass_le', 'Sex_le', 'Embarked_C', 'Embarked_Q', 'Embarked_S']]
y_test_pred = model_output.predict(test_X)
3. 예측값 대체 후 제출
해당 대회에서 제출할 파일인 gender_submission을 불러온다.
이때 Survived의 0,1은 성별을 기반으로 남자는 죽고 여자는 살았을 것이다. 라는 가설에 대해 입력된 값이다.
도출한 예측값으로 대치해주자.
sub_df = pd.read_csv("C:/Users/jojoo/OneDrive/바탕 화면/sparta_python/titanic/gender_submission.csv")
sub_df['Survived'] = y_test_pred # 대치
sub_df.to_csv('./result.csv', index=False) # 인덱스 제거
캐글 대회 페이지 우측 상단에 제출 파일 첨부하면 마무리.
'TIL > 머신러닝' 카테고리의 다른 글
비지도학습 K-Means Clustering 군집화 (0) | 2024.08.20 |
---|---|
의사결정나무, 랜덤포레스트, KNN, 부스팅 알고리즘 (1) | 2024.08.20 |
데이터 프로세스 : 데이터 전처리, EDA (0) | 2024.08.16 |
머신러닝 - 다중 로지스틱회귀 실습 (0) | 2024.08.13 |
머신러닝 - 로지스틱회귀 실습 (0) | 2024.08.13 |