資料集及代碼連結:https://github.com/CCH21/Lab_MLGroup_Tasks/tree/master/Task_Titanic
資料集概述
如下圖所示,Titanic資料集共包含有三個csv檔案,其中
train.csv
是訓練集,
test.csv
是待預測的測試集,
gender_submission.csv
是測試集的真實結果。
資料描述
import pandas as pd
from IPython.display import display
# 檢視訓練集和測試集
training_set = pd.read_csv('train.csv')
test_set = pd.read_csv('test.csv')
display(training_set)
display(test_set)
特征選擇與資料預處理
首先,我們需要檢視一下訓練集和測試集的特征值缺失情況。
# 檢視訓練集各特征的缺失情況
for column in training_set.columns:
print('%-15s%-10.4f%-3d' % (column, training_set[column].count() / len(training_set), training_set[column].count()))
# 檢視測試集各特征的缺失情況
for column in test_set.columns:
print('%-15s%-10.4f%-3d' % (column, test_set[column].count() / len(test_set), test_set[column].count()))
可以看出,在訓練集中,
Age
,
Cabin
和
Embarked
特征是有缺失值的,其中
Cabin
的缺失值占到了超過77%的比例。在測試集中,
Age
,
Fare
和
Cabin
特征有缺失值。
觀察資料。
Cabin
的缺失值過多,這時有兩種解決方案,一是給所有的缺失值标記上
Unknown
,二是直接删除這一特征。由于船艙号比較複雜,難以進行分析,是以選擇直接删除這一特征列。
PassengerID
肯定與最終的預測結果無關,是以删除此列。
Ticket
特征同樣難以分析,是以删掉。比較特殊的是
Name
一列,它其實包含了一些人物的性别、社會地位等資訊,可以保留但不易分析。其實,性别與社會地位這方面的資訊,我們可以從
Sex
和
Fare
等特征中得知,故删除
Name
列。
# 删除PassengerId, Name, Ticket, Cabin特征
training_set = training_set.drop(columns=['PassengerId', 'Name', 'Ticket', 'Cabin'])
test_set = test_set.drop(columns=['PassengerId', 'Name', 'Ticket', 'Cabin'])
display(training_set)
display(test_set)
接下來是對缺失值的處理。目前訓練集還有兩個特征值有缺失值,分别是
Age
和
Embarked
。對于
Age
特征,我們可以用訓練集中
Age
一列的平均值來填補完整。對于
Embarked
特征,由于隻有兩個樣本有缺失值,是以可以直接删除這兩個樣本。
# 用訓練集Age一列的平均數填補Age缺失值
training_set['Age'] = training_set['Age'].fillna(training_set['Age'].mean())
# 去除訓練集中有缺失值的樣本
training_set.dropna(axis=0,inplace=True)
display(training_set)
再次檢查訓練集,可以發現所有的樣本的特征值都是完整無空缺的。
# 檢查訓練集的缺失情況
for column in training_set.columns:
print('%-15s%-10.4f%-3d' % (column, training_set[column].count() / len(training_set), training_set[column].count()))
對于測試集的空缺值,我們不能選擇删除樣本的方式。通過觀察資料集可以發現,
Fare
一列有一個頻繁出現的
8.05
。由于
Fare
一列缺失值不多,是以選擇用衆數填補。
Age
一列的缺失值仍然選擇使用平均值填補。
# 處理測試集的缺失值
# 用測試集Fare一列的衆數填補Fare缺失值
test_set['Fare'] = test_set['Fare'].fillna(test_set['Fare'].dropna().mode()[0])
# 用測試集Age一列的平均數填補Age缺失值
test_set['Age'] = test_set['Age'].fillna(test_set['Age'].mean())
display(test_set)
# 檢查測試集的缺失情況
for column in test_set.columns:
print('%-15s%-10.4f%-3d' % (column, test_set[column].count() / len(test_set), test_set[column].count()))
接下來我們加載存活結果資料集,并且指定
X_train
,
X_test
,
y_train
,
y_test
。
# 加載存活結果資料集
result_set = pd.read_csv('gender_submission.csv')
display(result_set)
X_train = training_set.drop(columns=['Survived'])
y_train = training_set['Survived']
X_test = test_set
y_test = result_set.drop(columns=['PassengerId'])
display(X_train)
display(y_train)
display(X_test)
display(y_test)
下面我們利用
sklearn.feature_extraction
中的
DictVectorizer
特征轉換器,将不為數值型的特征進行轉換。轉換特征後,類别型特征都單獨剝離出來,獨成一列特征,數值型特征則保持不變。
# 使用特征轉換器
from sklearn.feature_extraction import DictVectorizer
vec = DictVectorizer(sparse=False)
X_train = vec.fit_transform(X_train.to_dict(orient='record'))
print(vec.feature_names_)
X_test = vec.transform(X_test.to_dict(orient='record'))
print(vec.feature_names_)
使用機器學習模型預測并且進行模型評估
這裡我選擇了兩個模型,分别是k-NN分類器和決策樹分類器。
# 使用決策樹分類器模型
from sklearn.tree import DecisionTreeClassifier
dtc = DecisionTreeClassifier()
dtc.fit(X_train, y_train)
y_predict = dtc.predict(X_test)
print(y_predict)
from sklearn.metrics import classification_report
print('Training set score: {:.2f}'.format(dtc.score(X_train, y_train)))
print('Test set score: {:.2f}'.format(dtc.score(X_test, y_test)))
# 輸出更加詳細的分類性能
print(classification_report(y_predict, y_test, target_names=['died', 'survived']))
決策樹分類器的預測準确度在77%左右,并且識别遇難者的準确率要優于識别幸存者。
# 使用k-NN分類器模型
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
training_accuracy = []
test_accuracy = []
neighbors_settings = range(1, 11)
for n_neighbors in neighbors_settings:
knn = KNeighborsClassifier(n_neighbors=n_neighbors)
knn.fit(X_train, y_train)
# 記錄訓練集精度
training_accuracy.append(knn.score(X_train, y_train))
# 記錄泛化精度
test_accuracy.append(knn.score(X_test, y_test))
plt.plot(neighbors_settings, training_accuracy, label='training accuracy')
plt.plot(neighbors_settings, test_accuracy, label='test accuracy')
plt.ylabel('Accuracy')
plt.xlabel('n_neighbors')
plt.legend()
通過改變
n_neighbors
的值(範圍為區間
[1, 10]
)建立不同的k-NN分類器,并且記錄其訓練集精度和泛化精度,繪制出折線圖。從折線圖中可以看出,當
n_neighbors = 5
時,泛化精度最高。
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
y_predict = knn.predict(X_test)
print(y_predict)
print('Training set score: {:.2f}'.format(knn.score(X_train, y_train)))
print('Test set score: {:.2f}'.format(knn.score(X_test, y_test)))
k-NN分類器的預測準确率大概在72%左右,稍遜于決策樹分類器。