- 深度學習訓練營 21天實戰TensorFlow+Keras+scikit-learn
- 張強
- 1922字
- 2020-04-14 15:04:08
2.1 數據準備
數據集是公開的,讀者可以在前言中提供的下載鏈接找到。數據集文件包括train.csv、test.csv、gender_submission.csv,還有一個是titanic_dataset.csv(前3個數據集文件的合并)。為了方便數據清洗、缺失值處理和分割,我們就使用titanic_dataset.csv。本章主要使用pandas和sklearn作為數據預處理和訓練的庫,在數據可視化分析查看時使用的是seaborn和matplotlib庫。
2.1.1 環境準備
◇ numpy=1.14.5。
◇ pandas=0.22.0。
◇ sklearn=0.19.2。
◇ seaborn=0.7.1。
◇ matplotlib=2.1.2。
◇ keras=2.1.6。
2.1.2 預處理數據
加載titanic_dataset.csv數據集,這是泰坦尼克號公開數據集的完整數據,我們通過pandas的read_csv()方法獲取到了完整的csv數據,并且返回Pandas的DataFrame對象。因為我們的目標是預測該乘客的生還情況,所以Survived字段(列)就是y,即預測目標,而X就是特征值,根據這些特征值來預測y。drop()方法表示丟棄指定的字段,保留剩下的字段。
import pandas as pd features=pd.read_csv('titanic_dataset.csv') y_train=features['Survived'] X_train=features.drop('Survived',axis=1)
查看前5行特征數據,輸出如圖2.1所示。輸出顯示的列表中,不包含Survived字段,因為我們通過調用drop()函數將它移除了。
X_train.head()

圖2.1 前5行特征數據
查看X_train和y_train數據的大小。
print("X_train.shape={},y_train.shape={}".format(X_train.shape,y_train.shape))
輸出如下,變量features是有12列的,但是Survived字段分配給了y_train,所以X_train就剩下11列了。
X_train.shape=(1309,11),y_train.shape=(1309,)
通過調用info()函數查看X_train的基本信息,輸出如圖2.2所示。
X_train.info()

圖2.2 X_train的基本信息
我們從該輸出信息可以查看到,Age、Cabin、Embarked和Fare字段都有缺失值。接下來,將對這些缺失值進行處理,如果不處理將導致無法訓練。字段說明如下。
◇ Age:乘客年齡。
◇ Cabin:乘客的客艙號。
◇ Embarked:乘客的登船港(S表示Southampton(英國南安普敦),C表示Cherbourg-Octeville(法國瑟堡-奧克特維爾),Q表示Queenstown(愛爾蘭昆士敦))。
◇ Fare:乘客支付的票價。
◇ Name:乘客姓名。
◇ Parch:一起上船的父母和子女人數。
◇ PassengerId:乘客登記的ID。
◇ Pclass:社會階層(1表示上層,2表示中層,3表示底層)。
◇ Sex:乘客性別。
◇ SibSp:一起上船的兄弟姐妹和配偶人數。
◇ Ticket:乘客的船票號。
◇ Survived:生還情況(1表示生還,0表示未生還)。
2.1.3 缺失值處理
我們先查看X_train的缺失值合計數量,代碼如下,輸出如圖2.3所示。
X_train.isnull().sum()

圖2.3 查看X_train的缺失值數量合計
Age字段有263個有缺失值。我們導入Seaborn數據可視化模塊,通過以下代碼來查看Age字段的分布圖,輸出如圖2.4所示。
import seaborn as sns sns.distplot(X_train['Age'].dropna(),hist=True,kde=True)

圖2.4 Age字段的分布圖
使用中值來替換缺失值,這樣能保證分布圖的基本呈現是呈正態分布(Normal Distribution)的。調用replace()方法的第一個參數表示要替換的值,np.nan表示NaN數據,np.nanmedian()方法表示將NaN的值都替換成中值,inplace=True表示在原有的對象上修改且不會產生副本(原有對象的意思是X_train是一個類型為Pandas下的Series的變量,通過指定inplace參數的值為True后,直接在X_train對象上修改要替換的值)。代碼如下。
X_train['Age'].replace(np.nan,np.nanmedian(X_train['Age']),inplace=True)
我們再來看Age字段的分布圖,代碼如下,輸出結果如圖2.5所示。
sns.distplot(X_train['Age'],hist=True,kde=True)

圖2.5 Age字段里無NaN數據的分布圖
Cabin字段有1014個缺失值,因為缺失值太多,而且該字段不會影響預測結果,所以刪掉就好。
X_train.drop("Cabin",axis=1,inplace=True)
Embarked字段有2個缺失值。我們先來看Embarked字段的直方圖情況,代碼如下,輸出結果如圖2.6所示。
sns.countplot(x='Embarked',data=X_train)

圖2.6 乘客的登船港直方圖
大部分乘客的登船港都是英國南安普敦,因此假設缺失值所代表的兩位乘客也是從英國南安普敦登船較為合適。我們可以通過調用replace()函數來替換缺失值,代碼如下。
X_train['Embarked'].replace(np.nan,'S',inplace=True)
Fare字段有1個缺失值。我們先查詢是缺了哪位乘客的票價數據。np.isnan()方法是從指定的數組中查詢有NaN值的行,然后返回有帶NaN值的True或False的數組,再通過X_train的切片索引獲取值,代碼如下。在輸出中我們可以看到只有一行數據,如圖2.7所示。
X_train[np.isnan(X_train["Fare"])]

圖2.7 Fare字段有缺失值的乘客數據
我們可以看到該乘客是從英國南安普敦登船,社會階層是3。那我們可以查詢Embarked等于S、Pclass等于3的所有乘客支付的票價,并且以類型為DataFrame的對象返回。使用query()方法來查詢,代碼如下。
pclass3_fares=X_train.query('Pclass==3&Embarked=="S"')['Fare']
然后將變量pclass3_fares中的NaN值修改為0,代碼如下。
pclass3_fares=pclass3_fares.replace(np.nan,0)
再對pclass3_fares取中值,代碼如下。
median_fare=np.median(pclass3_fares)
最后將該中值變量median_fare更新到X_train中缺失值的位置。通過loc來指定條件以進行賦值,該缺失值對應的乘客的PassengerId等于1044,所以他在Fare字段處的值就更新為剛剛計算出的中值了,代碼如下。
X_train.loc[X_train['PassengerId']==1044,'Fare']=median_fare
對于Sex字段,我們也需進行處理,雖然它沒有缺失值,但是處理后可以更好地擬合數據。我們將男性(male)賦值為1,女性(female)賦值為0,代碼如下。
X_train['Sex'].replace(['male','female'],[1,0],inplace=True)
最后,我們來看X_train的缺失值情況,代碼如下,輸出如圖2.8所示。
X_train.isnull().sum()

圖2.8 處理后的X_train缺失值數量合計
2.1.4 數據清洗與分割
數據清洗與分割需用到sklearn的train_test_split()方法。在分割數據前,我們先對X_train的特征數據進行獨熱編碼(one-hot encoding)。而pandas下的get_dummies()函數就是將類別變量轉換成虛擬變量(也稱為啞變量);簡單地說,就是將類別的變量值轉換成0和1,并且最終形成一個矩形表。在該矩形表的同一個類別下,自身的類別用1表示,其他的類別用0表示。
X_train=pd.get_dummies(X_train)
然后再次輸出X_train和y_train的shape,代碼如下。
print("X_train.shape={},y_train.shape={}".format(X_train.shape,y_train.shape))
輸出如下。
X_train.shape=(1309,2246),y_train.shape=(1309,)
然后清洗與分割數據。test_size=0.2表示給測試數據集分配0.2的數據,也就是20%的數據用于測試,80%的數據用于訓練。random_state表示給隨機數生成器使用的種子數。
Shuffle=True表示清洗數據。
from sklearn.model_selection import train_test_split train_X,test_X,train_y,test_y=train_test_split(X_train,y_train,test_size=0.2,rando m_state=42,shuffle=True)
通過train_test_split()方法,我們就得到train_X和train_y的訓練集,test_X和test_y的測試集。我們再看訓練集和測試集各自分配了多少數據,代碼如下。
print("train_X.shape={},train_y.shape={}".format(train_X.shape,train_y.shape)) print("test_X.shape={},test_y.shape={}".format(test_X.shape,test_y.shape))
輸出如下。
train_X.shape=(1047,2246),train_y.shape=(1047,) test_X.shape=(262,2246),test_y.shape=(262,)