상세 컨텐츠

본문 제목

[머신러닝] Titanic 데이터를 사용한 분류: Feature Engineering(파생변수 생성, 원핫인코딩,결측치 대체), Cross Validation

멋사 AISCOOL 7기 Python/INPUT

by dundunee 2022. 11. 17. 17:43

본문

 Feature engineering(파생변수 + 원핫인코딩 + 결측치대체) + Cross validation

1️⃣파생변수 만들기

1. 가족의 수 == Parch + SibSp + 1(나)

train["FamilySize"] = train["Parch"] + train["SibSp"] + 1
test["FamilySize"] = test["Parch"] + test["SibSp"] + 1

display(train[["Parch", "SibSp", "FamilySize"]].sample(3))
display(test[["Parch", "SibSp", "FamilySize"]].sample(3))

2. 성별

train["Gender"] = train["Sex"] == "female"
test["Gender"] = test["Sex"] == "female"

display(train[["Sex", "Gender"]].sample(5))
display(test[["Sex", "Gender"]].sample(5))

3. 호칭

# train
train["Title"] = train["Name"].split(",",expand="True")[0]
>>> Partner, Mr. Austen -> [Partner, Mr] 
train["Title"] = train["Title"].split(",",expand="True")[1]
>>> [Partner, Mr] -> [Mr]

#test
test["Title"] = test["Name"].str.split(".", expand=True)[0].str.strip()
test["Title"] = test["Title"].str.split(",", expand=True)[1].str.strip()
test[["Name","Title"]].sample(10)

train과 test의 호칭종류 및 개수가 다른 경우가 있을 수 있다. 따라서 공통된 부분을 제외하고 나머지 부분(개수가 작은 호칭들)의 경우 etc로 정리해준다.

# 호칭의 개수가 2개 이상인 값들만 들고오기
title_count = title["Name"].value_counts()
tc_under = title_count[title_count > 2].index

# train
train["TitleEtc"] = train["Title"]
train.loc(~train["Title"].isin(tc_under), "TitleEtc"] = "etc"

#test
test["TitleEtc"] = test["Title"]
test.loc[~test["Title"].isin(tc_under),"TitleEtc"] = "etc"

#확인
set(test["TitleEtc"].unique()) - set(train["TitleEtc"].unique())

2️⃣ 원핫 인코딩

  • pandas에서는 Ordinal Encoding을 category 타입에 대해 cat 속성의 codes 속성으로 지원하고 있습니다.
  • pandas에서는 One-Hot-Encoding을 get_dummies 메서드로 지원하고 있습니다.
  • sklearn에서는 Ordinal-Encoding을 OrdinalEncoder 객체로 지원하고 있습니다.
    • sklearn을 사용하게 되면 일단 학습을 해서 전처리를 하여 어떤 피처가 있는지 확인하게 된다.
  • test에 없는 값이라도 test에 해당 피처를 생성해준다.
  • 그런데 pandas의 get_dummies를 사용한다면 각각 전처리를 하기 때문에 다른 값이 있다면 다른 컬럼으로 생성하게 된다

💡 Pandas의 get_dummies를 사용한 One-Hot-Encoding

  • pandas를 사용하는 이유는 수치데이터와 범주형데이터를 함께 넣어주어도 알아서 인코딩이 진행된다는 장점이 있다.
pd.get_dummies(train[["Fare", "Age", "Embarked", "Cabin_initial"]])

3️⃣결측치 대체

1. 결측치를 문자열로 대체한 파생변수

  • 결측치에 의미를 부여하고 싶다면 없는 값은 이니셜 “n”으로 대체한다.
# train
train["Cabin_initial"] = train["Cabin"]
train["Cabin_initial"] = train["Cabin_initial"].fillna("N")
train["Cabin_initial"] = train["Cabin_initial"].str[0]

print(train["Cabin_initial"].unique())
train["Cabin_initial"].sample(5)

#test
test["Cabin_initial"] = test["Cabin"]
test["Cabin_initial"] = test["Cabin_initial"].fillna("N")
test["Cabin_initial"] = test["Cabin_initial"] .str[0]

print(test["Cabin_initial"].unique())
test["Cabin_initial"].sample(5)

['N' 'C' 'E' 'G' 'D' 'A' 'B' 'F' 'T']

Out[22]:

PassengerId 661 N 280 N 869 N 442 N 542 N Name: Cabin_initial, dtype: object

['N' 'B' 'E' 'A' 'C' 'D' 'F' 'G']

Out[23]:

PassengerId 1087 N 1120 N 1074 D 1117 N 1163 N Name: Cabin_initial, dtype: object

 

train에만 “T”값이 들어있는데, 이를 추출해보면 값이 하나임을 알 수 있다. 따라서 각 객실별 운임요금의 평균을 추출해 “T”와 가까운 객실로 대체해주는 방법을 쓰기로 한다.

train["Cabin_initial"] = train["Cabin_initial"].relace("T", "A")

#확인
set(train["Cabin_initial"].unique()) - set(test["Cabin_initial"].unique())
>>> set()

2. 성별에 따른 나이(Age) 결측치 채워 넣기

age_f = train.loc[train["Sex"] == "female", "Age"].mean()
age_m = train.loc[train["Sex"] == "male", "Age"].mean()

train["Age_fill"] = train["Age"]
train.loc[(train["Age_fill"].isnull())&(train["Sex"] == "female"), "Age_fill"] = age_f
train.loc[(train["Age_fill"].isnull())&(train["Sex"] == "male"), "Age_fill"] = age_m

4️⃣모델링

💡cross validation

  • cross_validate
    • Evaluate metric(s) by cross-validation and also record fit/score times.
    • 학습 결과에 대한 결과와 시간 공유
    • 점수를 보고자 할때는 편리하지만 커스텀하게 스코어를 지정한 metric에 의해서만 점수가 계산된다.
  • cross_val_score
    • Evaluate a score by cross-validation
    • 학습 결과에 대한 점수
  • cross_val_predict
    • Generate cross-validated estimates for each input data point.
    • 예측 값이 그대로 나와서 직접 계산해볼 수 있다.
    • 직접 다양한 측정 공식으로 결과값을 비교해 볼 수 있다.
label_name = "Survived"
feature_names = ['Pclass', 'Fare', 'Embarked',
        'FamilySize', 'Gender', 
       'TitleEtc', 'Cabin_initial',
       'Age_fill']

X_train = pd.get_dummies(train[feature_names])
X_test = pd.get_dummies(test[feature_names])
y_train = train[label_name]

from sklearn.tree import DecisionTreeClassifier

model = DecisionTreeClassifier(random_state=42,
																max_depth=5,max_features=0.9)

cross valiidate

#cross valiidate
from sklearn.model_selection import cross_validate
y_validate = cross_validate(model, X_train, y_train, cv = 5, n_jobs=-1)
pd.DataFrame(y_validate) #실행, 점수 계산 시간, 점수가 도출

cross_cal_score

from sklearn.model_selection import cross_val_score
y_valid_score = cross_val_score(model, X_train, y_train, cv = 5, n_jobs=-1)
y_valid_score # 각 조각에 대한 점수
>>> array([0.8603352 , 0.79775281, 0.82022472, 0.79213483, 0.85393258])

cross_val_predict

from sklearn.model_selection import cross_val_predict

y_valid_predict = cross_val_predict(model, X_train, y_train, cv = 5, n_jobs=-1)
y_valid_predict[:5] #예측 결과 값이 나와서 직접 계산해 볼 수 있다
>>> array([0, 1, 1, 1, 0], dtype=int64)

5️⃣ 학습 및 제출

model.fit(X_train, y_train)
y_predict = model.predict(X_test)

sns.barplot(x = model.feature_importances_, y = model.feature_names_in_)

관련글 더보기