[데이터분석] 타이타닉 데이터셋 전처리 실습

2024. 8. 13. 17:19AI & DS/머신러닝

타이타닉 데이터셋 전처리 실습

# 타이타닉 데이터셋 다운로드
!kaggle competitions download -c titanic

# 압축 해제
!unzip titanic.zip

데이터 병합

import pandas as pd

train_df = pd.read_csv("train.csv")

train_df.head()

 

test_df = pd.read_csv("test.csv")

test_df.head()
  • test.csv에 Survived column이 빠져있음
    • Survived 컬럼을 추가하고 NaN 값으로 채우고 두 데이터프레임을 결합

# test_df에 Survived 컬럼을 추가하고 NaN 값으로 채움
test_df['Survived'] = None

# 두 데이터프레임을 결합
titanic_df = pd.concat([train_df, test_df], ignore_index = True)

# 결과 출력
titanic_df

1. 변수 의미 파악하기

  • 전처리 하기 위한 첫번째 단계는 변수의 의미 파악하는 것이다!
  • 바로 전처리에 뛰어들면 과정에서 오류가 발생할 가능성이 높다 따라서 청사진을 그리는 것이 먼저이다. 따라서 변수의 의미를 먼저 파악해 주어야한다.
  • 해당 예제는 Kaggle이기 때문에, 변수명과 설명이 명확하고 변수의 수가 적지만, 실제 상황에서는 불명확하거나 변수가 많은 경우가 대부분이기 때문에 변수 의미 파악은 꼭 필요한 단계이다.

# 변수명 검색
titanic_df.columns
  • 변수의 의미를 파악한 후, 노트테이킹을 해주어야한다.
    • Survived: 탑승객 생존 여부. 0/1로 이미 인코딩 되어 있음.
    • Name: 탑승객의 이름.
    • Age: 탑승객의 나이.
    • Parch: 탑승객의 동승 부모/자녀 수
    • Fare: 승객 운임
    • Embarked: 승선 항구명 (C, Q, S)
    • Cabin: 선실 번호
    • Ticket: 티켓 번호
    • SibSp: 탑승객의 동승 배우자/형제자매 수
    • Sex: 탑승객의 성별.
    • Pclass: 탑승객 티켓의 Class. 1~3등석까지 되어 있음.
    • PassengerId: 탑승객의 고유 식별 번호.

2. 변수 정보 확인하기

# 변수 정보 확인하기
titanic_df.info()

  • 1309개의 엔트리, 12개의 컬럼
  • 각각의 컬럼에 대한 non-null의 개수와 타입이 나옴
    • not-null의 개수 파악을 통하여, 결측치가 필요한 데이터에 대한 노트테이킹을 진행한다.
    • Age, Fare, Cabin, Embarked: 결측치 처리 필요
    • 데이터 타입을 파악하여, 데이터 자료형 변환이 필요한 경우에 대한 노트테이킹을 진행한다.
    • Name, Sex, Ticket, Cabin, Embarked: object -> 데이터 확인하고 수치형 데이터로 변환 고려

3. 결측치 처리하기

Age의 경우

  • 몇 개나 결측인지 확인
#몇 개나 결측인지 확인
titanic_df['Age'].isna().sum()
  • 결측치를 어떻게 채우면 좋을 지 확인
    • ‘Age’가 결측치인 데이터를 앞에서부터 10개를 출력
    • 추출된 데이터를 통하여 “Name 에 성씨가 나오니까 가족 정보를 찾아볼 수 있지 않을까?”를 떠올릴 수 있다.
#결측치를 어떻게 채우면 좋을지 확인
titanic_df[titanic_df['Age'].isna()].head(10)

 

 

1. 가족 정보로 찾아보기

  • 이름에서 성과 이름을 추측
# 이름에서 성과 이름을 추출
titanic_df['LastName'] = titanic_df['Name'].apply(lambda x : x.split('.')[0].strip())
titanic_df['FirstNames'] =titanic_df['Name'].apply(lambda x : x.split('.')[1].strip())
  • 결측값이 있는 승객의 성을 가진 그룹 추출 및 출력
# 결측값이 있는 승객의 성을 가진 그룹 추출 및 출력
na_last_names = titanic_df[titanic_df['Age'].isna()]['LastName'].unique()

for last_name in na_last_names:
    subset = titanic_df[titanic_df['LastName'] == last_name].iloc[:, :-2]
    if len(subset) > 1:
      print(subset.to_string(index=False))
      print("\n" + "="*80 + "\n")

 

2. 직접 검색하기

 

  • 결측치 채우기
# 결측치 채우기
titanic_df.loc[titanic_df['PassengerId'] == 110, 'Age'] = 32
  • 확인하기
# 확인하기
titanic_df.loc[titanic_df['PassengerId'] == 110]

 

3. 이름에서 힌트 얻기

  • Mstr | Master : 남자아이의 경우를 말함
  • "Master" 호칭을 가진 승객들의 나이를 추출하여 중앙값을 계산 = 4.0
    • Age가 이산형 변수이기 때문에, 이산형으로 채워넣기 위해서 평균값이 아닌 중앙값을 사용하였다.
# "Master" 호칭을 가진 승객들의 나이를 추출하여 중앙값을 계산
master_ages = titanic_df[titanic_df['Name'].str.contains('Master')]['Age']
median_master_age = master_ages.median()
median_master_age
  • “Master”호칭을 가진, Age가 결측인 데이터를 추출
titanic_df[titanic_df['Name'].str.contains('Master') & titanic_df['Age'].isna()]

  • 중앙값으로 결측치를 채워넣기
titanic_df.loc[titanic_df['Name'].str.contains('Master') & titanic_df['Age'].isna(), 'Age'] = median_master_age

Fare의 경우

  • Fare가 결측치인 데이터 추출
titanic_df[titanic_df['Fare'].isna()]

  • 직접 검색하기

  • Fare를 정하는 기준을 분석하여 : 정박지, 동승인 수를 groupBy로 분석
    • Pclass가 높을 수록 가격이 높음
    • 같은 클래스 내부에서 SibSp가 높을 수록 가격이 높음
    • 정박지(Embarked)에 따라서 가격이 다름
    • 동승인(Parch)에 따라서 가격이 다름
    titanic_df.groupby(['Embarked', 'Pclass', 'SibSp'])['Fare'].mean()
    titanic_df.groupby(['Embarked', 'Pclass', 'Parch'])['Fare'].mean()
    
    # 통계치를 바탕으로 Storey, Mr. Thomas에 해당하는 데이터 값을 넣어서 meanFare 구함
    mean_fare = titanic_df[(titanic_df['Pclass']==3)&(titanic_df['SibSp']==0)&(titanic_df['Parch']==0)&(titanic_df['Embarked']=='$')]['Fare'].mean()
    titanic_df.loc[titanic_df['PassengerId']==1044, 'Fare'] = mean_fare
    

Embarked의 경우

titanic_df[titanic_df['Embarked'].isna()]
titanic_df.loc[titanic_df['Embarked'].isna(), 'Embarked'] = "S"

Cabin의 경우

titanic_df['Cabin'].unique()
titanic_df['Cabin'] = titanic_df['Cabin'].str.extract('([A-Za-z]+)', expand=False)
titanic_df['Cabin'].unique()
titanic_df.groupby(['Cabin', 'Pclass'])['Survived'].mean()
titanic_df[titanic_df['Cabin'] == 'T']
titanic_df[titanic_df['Cabin'].isna()]

수치형 데이터로 변환하기

  • Sex의 경우
titanic_df['Sex'].unique()
# map을 이용해 대응하기 
titanic_df['Sex']=titanic_df['Sex'].map({'male': 1, 'female': 0})
titanic_df['Sex'].unique()
  • Embarked의 경우
titanic_df['Embarked'].unique()
titanic_df = pd.get_dummies(titanic_df, columns=['Embarked'], prefix='Embarked')
titanic_df[['Embarked_C', 'Embarked_Q', 'Embarked_S']] = titanic_df[['Embarked_C', 'Embarked_Q', 'Embarked_S']].astype(int)
titanic_df

새로운 변수 생성하기

import re

# 타이틀을 추출하는 함수
def extract_title(name):
    title_search = re.search('([A-Za-z]+)\\.', name)
    if title_search:
        return title_search.group(1)
    return None

# 타이틀 추출
titanic_df['Title'] = titanic_df['Name'].apply(extract_title)
titanic_df['Title'].unique()
titanic_df.groupby('Title')['Pclass'].mean()
titanic_df.groupby('Title')['PassengerId'].count()
titanic_df.groupby('Title')['Survived'].mean()

정리하기

titanic_df.drop(['FirstNames','LastName','Ticket'], axis=1, inplace = True)
titanic_df.to_excel("titanic_preprocessed.xlsx")