# ===== 2. Preprocessing v2 =====
df_raw = df.copy() # 원본 보존
# 2-1. Embarked 결측치 → 최빈값으로 대체
if df['Embarked'].isnull().sum() > 0:
most_freq_embarked = df['Embarked'].mode()[0]
df['Embarked'] = df['Embarked'].fillna(most_freq_embarked)
# 2-2. CabinExist 생성 후 Cabin 컬럼 삭제
df['CabinExist'] = df['Cabin'].notnull().astype(int)
df = df.drop(columns=['Cabin'])
# 2-3. Name에서 Title 추출
df['Title'] = df['Name'].str.extract(r',\s*([^\.]+)\.', expand=False)
df['Title'] = df['Title'].str.strip() # 공백 제거
# 대표 타이틀만 남기고 나머지는 Rare로 통합
common_titles = ['Mr', 'Mrs', 'Miss', 'Master']
df['Title'] = df['Title'].apply(lambda x: x if x in common_titles else 'Rare')
# 2-4. FamilySize, IsAlone 생성
df['FamilySize'] = df['SibSp'] + df['Parch'] + 1
df['IsAlone'] = (df['FamilySize'] == 1).astype(int)
# 2-5. Age 결측치: Pclass + Sex(문자) 그룹 중앙값으로 대체
age_median_by_group = df.groupby(['Pclass', 'Sex'])['Age'].median()
def fill_age(row):
if pd.isnull(row['Age']):
return age_median_by_group.loc[row['Pclass'], row['Sex']]
return row['Age']
df['Age'] = df.apply(fill_age, axis=1)
# 2-6. Sex를 binary 인코딩 (female=1, male=0)
df['Sex'] = df['Sex'].map({'female': 1, 'male': 0})
# 2-7. Fare 로그 변환 (분포 완화용)
df['Fare_log'] = np.log1p(df['Fare'])
# 2-8. Embarked, Title 원-핫 인코딩 (0/1 타입으로 명시)
df = pd.get_dummies(df,
columns=['Embarked', 'Title'],
drop_first=True,
dtype=int)
# 2-9. 분석에 잘 안 쓰이는 Ticket, Name 삭제
drop_cols = []
for col in ['Ticket', 'Name']:
if col in df.columns:
drop_cols.append(col)
if drop_cols:
df = df.drop(columns=drop_cols)
print("Preprocessed shape:", df.shape)
df.head()