본문 바로가기

AI

[Kaggle] Titanic Competition 타이타닉 생존자 예측하기

예전에 해보다가 정리 못하고 남겨둔 notebook을 다시 열어보았다

분명 정리해둔줄 알았는데 필요해서 찾아보니까 없어서 이번 기회에 다시 정리!

리더보드 보면 점수 1 나온 사람들이 너무 많아 목표를 어느정도로 잡아야하나 어려웠는데 discussion을 보면 85~90% 이상의 정확도를 가진 사람들은 cheating일 것이라는 의견이 대부분이라 80%로 목표를 잡고 데이터 분석을 시작해보았다

 

train data는 아래와 같다

 

 

찾아야 할 값은 Survived 즉 해당 승객이 살았는지 죽었는지이다

 

처음에 감이 안잡혀서 다양한 그래프를 만들어보았다

 

 

나이에 따른 Survived의 분포

지금 생각하니 단순한 violinplot 보다는 살아남은 사람의 비율을 찾는 것이 더 좋았을 것 같다

 

 

부모나 자식의 숫자인데 가족이 없는 사람보다 있는 사람이 많이 생존한 것을 알 수 있었다

 

 

형제자매나 배우자의 수도 마찬가지로 없는 사람보다 있는 사람이 생존율이 높았다

 

 

어느 선착장에서 배를 탔는지에 따른 결과이다

어디서 탔느냐가 왜 결과에 영향을 미치게 되었는지는 잘 모르겠지만 S 선착장에서 탄 사람들이 사망률이 가장 높았다

 

 

비싼 표 값을 지불한 승객들이 생존율이 더 높았다

타이타닉 영화가 가물가물한데 돈 많은 사람들이 구명선을 먼저 탔었나...?

 

 

데이터는 모든 값이 채워져있지 않았는데 나이가 177개 Cabin이 687개 Embarked가 2개가 비어있었다

Embarked는 비어있는 행이 두개밖에 안되서 그 행은 그냥 버리기로 했다ㅎㅎ

feature를 고를때 사람 이름도 어떻게 써야 할지 생각이 안나서 사람이름도 버렸다

 

성별이 male,female로 저장되어 있어서 0,1로 바꾸어주었다

 

1
2
3
4
5
6
7
data_drop = data[pd.notnull(data['Embarked'])]
 
data_drop['Sex'].loc[data_drop.Sex == "male"= 0
data_drop['Sex'].loc[data_drop.Sex == "female"= 1
data_drop['Sex'= pd.to_numeric(data_drop['Sex'])
 
train_data = data_drop
cs

 

여기서 사용하기로 결정한 feature만 가져와서 x_train,x_test를 생성했다

 

1
2
3
4
5
y_train = train_data['Survived']
features = ['Pclass','Sex','Age','SibSp','Parch','Fare','Embarked','Cabin']
 
x_train = train_data[features]
x_test = test_data[features]
cs

 

Cabin은 C85,B42처럼 종류가 다 달라서 첫글자만 떼서 요금과 비교해보았다

 

 

같은 Cabin 내에서도 요금 분포가 다양하게 있었다

난 초보니까 하면서 그냥 Cabin도 버려버렸다...

 

1
2
x_train.drop(['Cabin'],axis=1,inplace=True)
x_test.drop(['Cabin'],axis=1,inplace=True)
cs

 

Cabin을 통째로 버려버려서 이제 Age만 채워주면 되었다

 

 

나이와 연관있어 보였던 feature는 위와 같다!

가족이 많으면 어릴 확률이 많았다

어린이 혼자서는 배를 탈 수 없으니까 그런것 같다

 

가족 수에 맞춘 평균 나이를 그냥 빈 칸에 넣어버렸다

 

1
2
3
4
5
6
7
8
assumed_age = x_age_not_null['Age'].groupby(x_age_not_null['SibSp']).mean()
 
for i,j in x_train.iterrows():
    if pd.isnull(j.Age):
        idx = j.SibSp
        if j.SibSp > 5 :
            idx = 5
        x_train['Age'][i] = assumed_age[idx]
cs

 

이 코드를 작성하고 나서 다른 사람들의 풀이도 찾아봤었는데 이렇게 그냥 평균 때리는 것보다 더 좋은 방법들이 많았던 것 같다

정리가 끝나고 다른 사람들의 풀이를 찾아보는 시간을 다시 가져봐야겠다

 

다음으로는 알파벳으로 저장된 Embarked를 One hot encoder를 사용해서 인코딩해주었다

 

1
2
3
4
5
6
7
8
9
OH_encoder = OneHotEncoder(handle_unknown='ignore', sparse=False)
OH_col = ['Embarked']
OH_cols_train = pd.DataFrame(OH_encoder.fit_transform(x_train[OH_col]))
x_train_drop = x_train.drop(OH_col,axis=1)
OH_cols_train.index = x_train.index
 
x_train_encoded = x_train_drop.join(
   pd.DataFrame(OH_cols_train, x_train_drop.index).add_prefix('embarked_')
)
cs

 

이렇게 인코딩을 시켜주면 데이터에 문자가 사라진다

 

 

Fare 요금 분포가 아래와 같이 너무 큰 값들이 몇개 있어서 조정해주었다

 

 

나이는 나이 그대로보다 카테고리로 나누어주었다

 

1
2
3
4
def age_category(x):
    return int(x/10)
 
x_train_encoded['Age_category'= x_train_encoded['Age'].apply(age_category)
cs

 

지금 생각해보니 단순히 10으로 나누는 것보다 어린이, 청년, 중년, 노인으로 나누는 것이 더 좋을 것 같다

나중에 바꾸어보아야겠다

 

테스트 데이터에서 빈 값이 있는 Fare는 하나밖에 없길래 그냥 평균으로..

1
x_final = x_test_encoded.apply(lambda row: row.fillna(row.mean()), axis=1)
cs

 

이렇게 데이터 전처리를 다 한 후에는 모델을 다양하게 사용해보려고했다

일단 잘 되는지 아래와 같이 naive하게 제출해보았다

 

1
2
3
4
5
model = RandomForestClassifier(random_state = 42)
model.fit(x_train_encoded,y_train)
preds = model.predict(x_final)
output = pd.DataFrame({'PassengerId': test_data.PassengerId, 'Survived': preds})
output.to_csv('my_submission.csv', index=False)
cs

 

cross validation이고 뭐고 그냥 바로 내버렸는데 생각보다 스코어가 잘 나왔다ㅋㅋㅋ

 

 

어떻게 해야 더 정확도를 높일 수 있을까 하여 일단 다양한 파라미터를 사용해보기로 했다

1
2
3
4
5
6
7
8
train_X, val_X, train_y, val_y = train_test_split(x_train_encoded, y_train, random_state = 0)
 
def get_mae(n, train_X, val_X, train_y, val_y):
    model = RandomForestClassifier(random_state = 42,max_depth=n)
    model.fit(train_X, train_y)
    preds_val = model.predict(val_X)
    mae = mean_absolute_error(val_y, preds_val)
    return(mae)
cs

 

이런 함수를 사용해서 적절한 max_depth 값을 찾아보니 정확도가 이렇게 증가하였다

이 때 예전에는 cross_val_score를 사용했는데 다시 실행해보면서 mae로 바꾸어보았다

cross_val_score로 측정했을때가 더 결과가 좋게 나와서 다음부터는 다시 cross_val_score를 써야겠다

개념이 덜 잡혀서 아직 차이를 잘 모르겠다ㅠㅠ

 

추가로 n_estimators까지 설정해주면 점수가 0.78947 까지 올랐다

 

다른 모델들도 이처럼 비슷한 방식으로 여러개 실험해보았다

XGBClassifier(max_depth = 2, learning_rate=0.2,n_estimators=70)

이렇게 하면 점수가 0.78229로 나왔다

 

lgb.LGBMClassifier(max_depth=2,num_leaves=4, min_data_in_leaf=30,max_bin=100,learning_rate=0.1)도 점수가 0.78229가 나왔는데 계속 점수가 같게 나오는게 파라미터가 의미가 없고 데이터를 더 잘 만들어야 정확도를 올릴 수 있을 것 같았다

 

다음에는 데이터를 조금 다르게 처리하여 정확도를 80 이상으로 올려보아야겠다

'AI' 카테고리의 다른 글

Activation Functions  (0) 2021.04.13
Logistic Regression  (0) 2021.04.07
Neural Networks  (1) 2020.10.03
Fisher Discriminant Analysis  (0) 2020.10.02
Online learning - Perceptron Algorithm  (0) 2020.10.01