기존 RandomForest를 사용한 Baseline 코드
# 필요한 라이브러리 임포트
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report
# 데이터 불러오기
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
# 데이터 전처리
def preprocess_data(df):
# 결측치 처리
df['Age'] = df['Age'].fillna(df['Age'].mean())
df['Embarked'] = df['Embarked'].fillna(df['Embarked'].mode()[0])
df['Fare'] = df['Fare'].fillna(df['Fare'].mean())
# 범주형 변수 처리
df['Sex'] = df['Sex'].map({'male': 0, 'female': 1})
df['Embarked'] = df['Embarked'].map({'S': 0, 'C': 1, 'Q': 2})
# 필요한 특성 선택
features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
return df[features]
# 학습 데이터 전처리
X = preprocess_data(train)
y = train['Survived']
# 학습 데이터와 검증 데이터 분리
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
# RandomForest #모델 생성 및 학습
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(X_train, y_train)
# 검증 데이터로 예측
val_pred = rf_model.predict(X_val)
# 모델 성능 평가
print('검증 데이터 정확도:', accuracy_score(y_val, val_pred))
print('\n분류 보고서:')
print(classification_report(y_val, val_pred))
# 테스트 데이터 예측
test_processed = preprocess_data(test)
test_pred = rf_model.predict(test_processed)
# 제출 파일 생성
submission = pd.DataFrame({
'PassengerId': test['PassengerId'],
'Survived': test_pred
})
submission.to_csv('submission.csv', index=False)
print('\n제출 파일이 생성되었습니다.')
GPT를 이용하여 Pytorch 버전으로 변환했다.
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 데이터 불러오기
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
# 데이터 전처리
def preprocess_data(df):
# 결측치 처리
df['Age'] = df['Age'].fillna(df['Age'].mean())
df['Embarked'] = df['Embarked'].fillna(df['Embarked'].mode()[0])
df['Fare'] = df['Fare'].fillna(df['Fare'].mean())
# 범주형 변수 처리
df['Sex'] = df['Sex'].map({'male': 0, 'female': 1})
df['Embarked'] = df['Embarked'].map({'S': 0, 'C': 1, 'Q': 2})
# 필요한 특성 선택
features = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']
return df[features]
# 커스텀 데이터셋 클래스
class TitanicDataset(Dataset):
def __init__(self, features, targets=None):
self.features = torch.FloatTensor(features)
self.targets = torch.FloatTensor(targets) if targets is not None else None
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
if self.targets is not None:
return self.features[idx], self.targets[idx]
return self.features[idx]
# 신경망 모델 정의
class TitanicNet(nn.Module):
def __init__(self, input_size):
super(TitanicNet, self).__init__()
self.layers = nn.Sequential(
nn.Linear(input_size, 64),
nn.ReLU(),
nn.BatchNorm1d(64),
nn.Dropout(0.3),
nn.Linear(64, 32),
nn.ReLU(),
nn.BatchNorm1d(32),
nn.Dropout(0.2),
nn.Linear(32, 1),
nn.Sigmoid()
)
def forward(self, x):
return self.layers(x)
# 데이터 전처리 및 스케일링
X = preprocess_data(train)
y = train['Survived']
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 학습/검증 데이터 분할
X_train, X_val, y_train, y_val = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
# 데이터셋 및 데이터로더 생성
train_dataset = TitanicDataset(X_train, y_train)
val_dataset = TitanicDataset(X_val, y_val)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=32)
# 디바이스 설정
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 모델 초기화
model = TitanicNet(input_size=X_train.shape[1]).to(device)
criterion = nn.BCELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 학습
num_epochs = 100
for epoch in range(num_epochs):
model.train()
for features, targets in train_loader:
features, targets = features.to(device), targets.to(device)
optimizer.zero_grad()
outputs = model(features)
loss = criterion(outputs.squeeze(), targets)
loss.backward()
optimizer.step()
# 검증
if (epoch + 1) % 10 == 0:
model.eval()
with torch.no_grad():
correct = 0
total = 0
for features, targets in val_loader:
features, targets = features.to(device), targets.to(device)
outputs = model(features)
predicted = (outputs.squeeze() >= 0.5).float()
total += targets.size(0)
correct += (predicted == targets).sum().item()
accuracy = correct / total
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}, Validation Accuracy: {accuracy:.4f}')
# 테스트 데이터 예측
test_processed = preprocess_data(test)
test_scaled = scaler.transform(test_processed)
test_dataset = TitanicDataset(test_scaled)
test_loader = DataLoader(test_dataset, batch_size=32)
model.eval()
predictions = []
with torch.no_grad():
for features in test_loader:
features = features.to(device)
outputs = model(features)
predicted = (outputs.squeeze() >= 0.5).float()
predictions.extend(predicted.cpu().numpy())
# 제출 파일 생성
submission = pd.DataFrame({
'PassengerId': test['PassengerId'],
'Survived': predictions
})
submission.to_csv('submission.csv', index=False)
print('\n제출 파일이 생성되었습니다.')
Kaggle 제출 결과
Score를 0.8 이상으로 튜닝하기 위해 몇가지 데이터 전처리 과정을 거쳐 보았다
df['Age'] = df['Age'].fillna(df['Age'].median())
df['Embarked'] = df['Embarked'].fillna(df['Embarked'].mode()[0])
df['Fare'] = df['Fare'].fillna(df['Fare'].mean())
결측치가 많은 Age, Embarked, Fare Feature는 median, s, mean 값으로 채웠다
df.loc[df['Age'] <= 10, 'Age_clean'] = 0
df.loc[(df['Age'] > 10) & (df['Age'] <= 16), 'Age_clean'] = 1
df.loc[(df['Age'] > 16) & (df['Age'] <= 20), 'Age_clean'] = 2
df.loc[(df['Age'] > 20) & (df['Age'] <= 26), 'Age_clean'] = 3
df.loc[(df['Age'] > 26) & (df['Age'] <= 30), 'Age_clean'] = 4
df.loc[(df['Age'] > 30) & (df['Age'] <= 36), 'Age_clean'] = 5
df.loc[(df['Age'] > 36) & (df['Age'] <= 40), 'Age_clean'] = 6
df.loc[(df['Age'] > 40) & (df['Age'] <= 46), 'Age_clean'] = 7
df.loc[(df['Age'] > 46) & (df['Age'] <= 50), 'Age_clean'] = 8
df.loc[(df['Age'] > 50) & (df['Age'] <= 60), 'Age_clean'] = 9
df.loc[df['Age'] > 60, 'Age_clean'] = 10
5세 단위로 자르고 50대는 10세단위 그리고 60세이상은 모두 묶음
# 정규 표현식 사용해서 추출
df['Title'] = df['Name'].str.extract(' ([A-Za-z]+)\.', expand=False)
# 직함 그룹화
rare_titles = ['Lady', 'Countess','Capt', 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir.', 'Jonkheer', 'Dona']
df.loc[df['Title'].isin(rare_titles), 'Title'] = 'Rare'
df['Title'] = df['Title'].replace(['Mlle', 'Ms', 'Mme'], ['Miss', 'Miss', 'Mrs'])
# 직함 매핑
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}
df['Title'] = df['Title'].map(title_mapping)
df['Title'] = df['Title'].fillna(0)
# Pclass를 기준으로 Cabin 데이터 처리
cabin_mapping = {
'A': 0, 'B': 1, 'C': 2, 'D': 3,
'E': 4, 'F': 5, 'G': 6, 'T': 7
}
df['Cabin_clean'] = df['Cabin'].str[:1]
df['Cabin_clean'] = df['Cabin_clean'].map(cabin_mapping)
df['Cabin_clean'] = df.groupby('Pclass')['Cabin_clean'].transform('median')
df['FamilySize'] = df['SibSp'] + df['Parch'] + 1
df['Sex'] = df['Sex'].map({'male': 0, 'female': 1})
df['Embarked'] = df['Embarked'].map({'S': 0, 'C': 1, 'Q': 2})
# 필요한 특성 선택
features = ['Pclass', 'Sex', 'Age_clean', 'SibSp', 'Parch',
'Fare', 'Embarked', 'FamilySize', 'Title',
'Cabin_clean']
데이터 전처리 후 제출 결과
1. 시간내에 정확도를 더 높이지 못함
2. 데이터에 대한 전체적인 이해
3. 각 필드에 어떤 특징이 있는지 고려하지 않고, 직관에 의존함
4. EDA를 제대로 하지 못해서 논리적으로 풀어나가지 못함
5. GPT 사용 과다
1. 각 필드간 상관관계를 분석하고 시각화하여 특징을 파악하기
2. 하이퍼 파라미터 튜닝도 시도해보기
[참고]
https://www.kaggle.com/code/ldfreeman3/a-data-science-framework-to-achieve-99-accuracy/notebook
https://www.kaggle.com/code/jiripodivin/titanic-with-keras