各列數(shù)據(jù)的意義:
- PassengerId:乘客id
- Survived:是否生還
- Pclass:船票等級
- Name:姓名
- Sex:性別
- Age:年齡
- SibSp:登船兄弟姊妹/配偶數(shù)量
- Parch:登船父母/子女?dāng)?shù)量
- Ticket:船票號碼
- Fare:船票價(jià)格
- Cabin:船艙
- Embarked:登船口
import pandas as pd
import numpy as np
# 加載訓(xùn)練數(shù)據(jù)
original_data = pd.read_csv("train.csv")
# 加載要預(yù)測的數(shù)據(jù)
original_predict_data = pd.read_csv("test.csv")
# 我們要預(yù)測的值是Survived律胀,所以將其取出來读第。
y = original_data.Survived
original_data_without_survived = original_data.drop(["Survived"], axis=1)
# 由于數(shù)據(jù)分為訓(xùn)練數(shù)據(jù)和預(yù)測數(shù)據(jù)兩個(gè)數(shù)據(jù)集咪橙,為了能以統(tǒng)一的方式處理數(shù)據(jù)野来,先將這兩個(gè)數(shù)據(jù)集合并。
data = pd.concat([original_data_without_survived, original_predict_data], ignore_index=True)
1. 處理屬性
有一些屬性需要處理后才能用于訓(xùn)練模型。
1.1 PassengerId
PassengerId僅代表數(shù)據(jù)集中乘客的順序,不影響乘客是否生還的結(jié)果祟滴,所以將其移除以防止影響預(yù)測結(jié)果。
data = data.drop(["PassengerId"], axis=1)
1.2 姓名
姓名屬于標(biāo)稱屬性歌溉,但每個(gè)人的姓名都不一樣垄懂,這樣并不好處理。檢查數(shù)據(jù)發(fā)現(xiàn)每個(gè)姓名中都帶有頭銜痛垛,頭銜的可能性較少草慧,可以將其提取出來作為一個(gè)獨(dú)立的屬性來處理。
import re
name_title_pattern = re.compile(r'\w+\.')
# NameTitle的可能性為18個(gè)匙头,與15相差不大漫谷,可適用one-hot編碼。
data["NameTitle"] = data.Name.apply(lambda n: name_title_pattern.search(n).group())
# 去除姓名屬性
data = data.drop(["Name"], axis=1)
1.3 性別
性別屬于二元屬性(只有男和女兩種可能性)蹂析,這里用“0”表示male抖剿,“1”表示female。
data["Sex"] = data.Sex.map({"male":0, "female":1})
1.4 船票號碼
大多數(shù)的船票號碼都是獨(dú)立的识窿,小部分號碼是重復(fù)的。猜測擁有相同船票號碼的乘客可能是同伴關(guān)系脑融,因此將號碼重復(fù)的次數(shù)作為一個(gè)獨(dú)立的屬性喻频。
ticket_map = {}
for ticket in data.Ticket:
if ticket in ticket_map:
ticket_map[ticket] += 1
else:
ticket_map[ticket] = 1
data["Ticket"] = data.Ticket.apply(lambda t: ticket_map[t])
1.5 船艙
類似船票號碼,大多數(shù)船艙都是獨(dú)立唯一的肘迎。檢查數(shù)據(jù)發(fā)現(xiàn)船艙首字母的重復(fù)性較高甥温,猜測其代表船艙的區(qū)域锻煌,所以將其提取出來作為獨(dú)立屬性。
data["Cabin"] = data.Cabin.apply(lambda c: np.NaN if pd.isnull(c) else c[0])
1.6 船票等級
雖然船票等級屬性為數(shù)值類型姻蚓,但是可以將其看作分類屬性宋梧。
pclass_names = ["A", "B", "C"]
data["PclassName"] = data.Pclass.apply(lambda x: pclass_names[x-1])
data = data.drop(["Pclass"], axis=1)
2. 處理缺失值
2.1 年齡
年齡丟失情況比較多,這里以pclass和性別進(jìn)行分組狰挡,并取其中位數(shù)作為缺失值捂龄。
def get_default_age(pclass_name, sex):
ages = data.Age[(data.PclassName == pclass_name) & (data.Sex == sex)]
return ages.quantile(0.5)
data["Age2"] = data.apply(lambda r: get_default_age(r.PclassName, r.Sex) if pd.isnull(r.Age) else r.Age, axis=1)
# 將填充年齡的位置標(biāo)記出來
data["AgeFill"] = data.apply(lambda r: 1 if pd.isnull(r.Age) else 0, axis=1)
# 將原本的年齡去除
data = data.drop(["Age"], axis=1)
2.2 船票價(jià)格
船票價(jià)格缺失值使用乘客所在等級的船票平均價(jià)格代替。
data["Fare"] = data.apply(lambda r: data.Fare[data.PclassName == r.PclassName].mean() if pd.isnull(r.Fare) else r.Fare, axis=1)
2.3 船艙
船艙缺失值太多加叁,強(qiáng)行補(bǔ)充數(shù)據(jù)可能會為模型引入不必要的影響倦沧,所以將缺失值用“unknown”代替。
data["Cabin"] = data.Cabin.apply(lambda x: "unknown" if pd.isnull(x) else x)
2.4 登船口
缺失值使用出現(xiàn)頻率最高的值代替它匕。
# 出現(xiàn)頻率最高的值是S
data["Embarked"] = data.Embarked.apply(lambda e: "S" if pd.isnull(e) else e)
3. one-hot編碼
數(shù)據(jù)集中包含object類型的數(shù)據(jù)展融,不能直接用來訓(xùn)練模型。one-hot編碼則是這種情況的常用解決方法豫柬,可以將object類型的數(shù)據(jù)轉(zhuǎn)變成數(shù)值類型的數(shù)據(jù)告希。
data = pd.get_dummies(data)
4. 建立模型
4.1 訓(xùn)練模型
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import make_pipeline
train_y = y
train_X = data[:len(train_y)]
my_pipeline = make_pipeline(RandomForestClassifier(max_depth=5,
n_estimators=120))
my_pipeline.fit(train_X, train_y)
Pipeline(steps=[('randomforestclassifier', RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=5, max_features='auto', max_leaf_nodes=None,
min_impurity_split=1e-07, min_samples_leaf=1,
min_samples_split=2, min_weight_fraction_leaf=0.0,
n_estimators=120, n_jobs=1, oob_score=False, random_state=None,
verbose=0, warm_start=False))])
4.2 預(yù)測并輸出結(jié)果
predict_X = data[len(y):]
predict_y = my_pipeline.predict(predict_X)
ids = original_predict_data.PassengerId
submission = pd.DataFrame({
"PassengerId": ids,
"Survived": predict_y
})
submission.to_csv('submission.csv', index=False)
最終結(jié)果:0.80382,排名前12%烧给。