结构化数据建模——titanic数据集的模型建立和训练(Pytorch版)
本文參考《20天吃透Pytorch》來實現(xiàn)titanic數(shù)據(jù)集的模型建立和訓(xùn)練
在書中理論的同時加入自己的理解。
一,準(zhǔn)備數(shù)據(jù)
數(shù)據(jù)加載
titanic數(shù)據(jù)集的目標(biāo)是根據(jù)乘客信息預(yù)測他們在Titanic號撞擊冰山沉沒后能否生存。
結(jié)構(gòu)化數(shù)據(jù)一般會使用Pandas中的DataFrame進(jìn)行預(yù)處理。
數(shù)據(jù)集字段如下:
字段說明:
Survived:0代表死亡,1代表存活【y標(biāo)簽】
Pclass:乘客所持票類,有三種值(1,2,3) 【轉(zhuǎn)換成onehot編碼】
Name:乘客姓名 【舍去】
Sex:乘客性別 【轉(zhuǎn)換成bool特征】
Age:乘客年齡(有缺失) 【數(shù)值特征,添加“年齡是否缺失”作為輔助特征】
SibSp:乘客兄弟姐妹/配偶的個數(shù)(整數(shù)值) 【數(shù)值特征】
Parch:乘客父母/孩子的個數(shù)(整數(shù)值)【數(shù)值特征】
Ticket:票號(字符串)【舍去】
Fare:乘客所持票的價格(浮點數(shù),0-500不等) 【數(shù)值特征】
Cabin:乘客所在船艙(有缺失) 【添加“所在船艙是否缺失”作為輔助特征】
Embarked:乘客登船港口:S、C、Q(有缺失)【轉(zhuǎn)換成onehot編碼,四維度 S,C,Q,nan】
加載數(shù)據(jù)集:
#數(shù)據(jù)讀取 train_data = pd.read_csv('./data/titanic/train.csv') test_data = pd.read_csv('./data/titanic/test.csv') test_datay = pd.read_csv('./data/titanic/titanic.csv') #print(train_data.head(10)) #打印訓(xùn)練數(shù)據(jù)前十個當(dāng)我們獲得數(shù)據(jù)集后,首先要查看數(shù)據(jù)中是否有缺失!!!這個很重要!
train_data.info() #查看訓(xùn)練數(shù)據(jù)有沒有未知的的 test_data.info() #查看測試數(shù)據(jù)有沒有未知的的
很明顯,Age和Cabin數(shù)據(jù)都有缺失
接下來,先利用Pandas的數(shù)據(jù)可視化分析數(shù)據(jù):
幸存情況
#幸存情況 ax = train_data['Survived'].value_counts().plot(kind = 'bar',figsize = (12,8),fontsize =15,rot = 0) #value_counts是查詢有多少個不同值且每個不同值有多少個重復(fù)的 ax.set_ylabel('Counts',fontsize = 15) ax.set_xlabel('Survived',fontsize = 15) plt.show()
年齡分布情況
年齡和label的相關(guān)性
數(shù)據(jù)預(yù)處理
這個步驟非常非常重要! 不僅要加載數(shù)據(jù)集,更重要的是如何處理NULL數(shù)據(jù)!
""" 數(shù)據(jù)預(yù)處理 """ def preprocessing(dfdata):dfresult = pd.DataFrame() #存儲結(jié)果#DataFrame是Python中Pandas庫中的一種數(shù)據(jù)結(jié)構(gòu),它類似excel,是一種二維表。#Pclass處理dfPclass = pd.get_dummies(dfdata['Pclass'])#對Pclass進(jìn)行g(shù)et_dummies,將該特征離散化dfPclass.columns = ['Pclass_'+str(x) for x in dfPclass.columns]dfresult = pd.concat([dfresult,dfPclass],axis=1)#concat函數(shù)是在pandas底下的方法,可以將數(shù)據(jù)根據(jù)不同的軸作簡單的融合,axis: 需要合并鏈接的軸,0是行,1是列#SexdfSex = pd.get_dummies(dfdata['Sex'])dfresult = pd.concat([dfresult, dfSex], axis=1)#Agedfresult['Age'] = dfdata['Age'].fillna(0)dfresult['Age_null'] = pd.isna(dfdata['Age']).astype('int32')#pandas.isna(obj)檢測array-like對象的缺失值# SibSp,Parch,Faredfresult['SibSp'] = dfdata['SibSp']dfresult['Parch'] = dfdata['Parch']dfresult['Fare'] = dfdata['Fare']# Carbindfresult['Cabin_null'] = pd.isna(dfdata['Cabin']).astype('int32')print(dfresult['Cabin_null'])# EmbarkeddfEmbarked = pd.get_dummies(dfdata['Embarked'], dummy_na=True)dfEmbarked.columns = ['Embarked_' + str(x) for x in dfEmbarked.columns]#DataFrame.columns屬性以返回給定 DataFrame 的列標(biāo)簽。dfresult = pd.concat([dfresult, dfEmbarked], axis=1)return dfresult#獲得訓(xùn)練x,y x_train = preprocessing(train_data).values y_train = train_data[['Survived']].values#獲得測試x,y x_test = preprocessing(test_data).values y_test = test_datay[['Survived']].values# print("x_train.shape =", x_train.shape ) # print("x_test.shape =", x_test.shape ) # print("y_train.shape =", y_train.shape ) # print("y_test.shape =", y_test.shape )這里重點講解一下對數(shù)據(jù)缺失部分的處理!
以Age字段,我們通過fillna(0),將Age字段中的NaN替換成0
然后通過 pd.isna將空值點的地方記錄下來(添加“年齡是否缺失”作為輔助特征)
這里我把測試數(shù)據(jù)中的Age部分除了前兩個后面全設(shè)置為NULL
然后把dfresult['Age'],dfresult['Age_null']打印出來:
可以看看下面這個文章,我收到了很多啟發(fā)。
data是一個pandas.DataFrame數(shù)據(jù)對象,是從mysql讀取的數(shù)據(jù)。由于有的列在數(shù)據(jù)庫是int類型,而且有空值(Null),因此在從數(shù)據(jù)庫抽取到df對象后,pandas自動將int轉(zhuǎn)成float,比如10變成了10.0,15902912345變成了1.5902912345E10,Null變成了NaN。這種列由于存在NaN,因此不能用DataFrame.astype()方法轉(zhuǎn)成int類型。
我們的目的就是盡量讓pandas抽取的數(shù)據(jù)跟數(shù)據(jù)庫“看上去”一致。比如原來是int類型的,如果被替換成float了,那么需要轉(zhuǎn)換回去,原來是Null的,被pandas改成NaN了,需要替換成空字符串。由于pandas列的int類型不能為空,所以需統(tǒng)一轉(zhuǎn)換成字符串類型。
為了達(dá)到將列轉(zhuǎn)換成int類型原來的展現(xiàn)形式(可以是object類型,相當(dāng)于str,此時10還是展示為10),且NaN轉(zhuǎn)換成空值這個目的,可以采取如下步驟:
1.生成新的df對象,保存data里為NaN的位置標(biāo)記
2.將data需要處理的列,NaN值替換為float能允許的類型,如0,下面會用到
3.將該列轉(zhuǎn)換成int類型,此時10.0轉(zhuǎn)換成10,1.5902912345E10轉(zhuǎn)換成15902912345
4.將該列轉(zhuǎn)換成object類型,此時所有數(shù)值按str類型原樣保存
5.用NaN位置標(biāo)記的df對象作為索引,替換原df對象中為0的值到空字符串
利用pandas.DataFrame.isna方法做替換(很棒的技巧)
進(jìn)一步使用DataLoader和TensorDataset封裝成可以迭代的數(shù)據(jù)管道。
""" 進(jìn)一步使用DataLoader和TensorDataset封裝成可以迭代的數(shù)據(jù)管道。 """ dl_train = DataLoader(TensorDataset(torch.tensor(x_train).float(),torch.tensor(y_train).float()),shuffle = True, batch_size = 8) dl_valid = DataLoader(TensorDataset(torch.tensor(x_test).float(),torch.tensor(y_test).float()),shuffle = False, batch_size = 8)# 測試數(shù)據(jù)管道 for features,labels in dl_train:print(features,labels)break二,定義模型
使用Pytorch通常有三種方式構(gòu)建模型:使用nn.Sequential按層順序構(gòu)建模型,繼承nn.Module基類構(gòu)建自定義模型,繼承nn.Module基類構(gòu)建模型并輔助應(yīng)用模型容器進(jìn)行封裝。
此處選擇使用最簡單的nn.Sequential,按層順序模型。
三,訓(xùn)練模型
""" 三,訓(xùn)練模型 """from sklearn.metrics import accuracy_scoreloss_func = nn.BCELoss() optimizer = torch.optim.Adam(params=net.parameters(),lr=0.01) metric_func = lambda y_pred,y_true:accuracy_score(y_true.data.numpy(),y_pred.data.numpy()>0.5) #lambda表達(dá)式是起到一個函數(shù)速寫的作用。允許在代碼內(nèi)嵌入一個函數(shù)的定義。 #accuracy_score是分類準(zhǔn)確率分?jǐn)?shù)是指所有分類正確的百分比。 metric_name = "accuracy" #metric就是準(zhǔn)確率epochs = 10 log_step_freq = 30 dfhistory = pd.DataFrame(columns = ["epoch","loss",metric_name,"val_loss","val_"+metric_name])for epoch in range(1,epochs+1):#開始訓(xùn)練net.train()loss_sum = 0.0metric_sum = 0.0step = 1for step,(features,labels) in enumerate(dl_train,1):optimizer.zero_grad()#正向傳播predictions = net(features)loss = loss_func(predictions,labels)metric = metric_func(predictions,labels)#反向傳播loss.backward()optimizer.step()#打印batch日志loss_sum += loss.item()metric_sum += metric.item()if step%log_step_freq == 0:print(("[step = %d] loss: %.3f, " + metric_name + ": %.3f") %(step, loss_sum / step, metric_sum / step))#驗證循環(huán)net.eval()val_loss_sum = 0.0val_metric_sum = 0.0val_step = 1for val_step, (features, labels) in enumerate(dl_valid, 1):predictions = net(features)val_loss = loss_func(predictions, labels)val_metric = metric_func(predictions,labels)val_loss_sum += val_loss.item()val_metric_sum += val_metric.item()#記錄日志info = (epoch, loss_sum / step, metric_sum / step,val_loss_sum / val_step, val_metric_sum / val_step)dfhistory.loc[epoch - 1] = info# 打印epoch級別日志print(("\nEPOCH = %d, loss = %.3f," + metric_name + " = %.3f, val_loss = %.3f, " + "val_" + metric_name + " = %.3f")% info)四,評估模型
""" 四,評估模型 """ def plot_metric(dfhistory, metric):train_metrics = dfhistory[metric]val_metrics = dfhistory['val_'+metric]epochs = range(1, len(train_metrics) + 1)plt.plot(epochs, train_metrics, 'bo--')plt.plot(epochs, val_metrics, 'ro-')plt.title('Training and validation '+ metric)plt.xlabel("Epochs")plt.ylabel(metric)plt.legend(["train_"+metric, 'val_'+metric])plt.show()plot_metric(dfhistory,"loss") plot_metric(dfhistory,"accuracy")這里補(bǔ)充一下 dfhistory
dfhistory來源于第三部分訓(xùn)練模型中:
dfhistory = pd.DataFrame(columns = ["epoch","loss",metric_name,"val_loss","val_"+metric_name])DataFrame是Python中Pandas庫中的一種數(shù)據(jù)結(jié)構(gòu),它類似excel,是一種二維表。
dfhistory的作用就是跟蹤數(shù)據(jù),在訓(xùn)練的過程中記錄每一步的訓(xùn)練結(jié)果。
通過在dfhistory調(diào)取訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)進(jìn)行對比繪圖!
結(jié)果展示:
五,使用模型
""" 五,使用模型 """ y_pred_probs = net(torch.tensor(x_test[0:10]).float()).data y_pred = torch.where(y_pred_probs>0.5,torch.ones_like(y_pred_probs),torch.zeros_like(y_pred_probs))六,保存模型
""" # 六,保存模型 """ #保存模型參數(shù)(推薦) print(net.state_dict().keys()) # 保存模型參數(shù) torch.save(net.state_dict(), "./data/net_parameter.pkl") net_clone = creat_net() net_clone.load_state_dict(torch.load("./data/net_parameter.pkl")) net_clone.forward(torch.tensor(x_test[0:10]).float()).data#保存完整模型(不推薦) torch.save(net, './data/net_model.pkl') net_loaded = torch.load('./data/net_model.pkl') net_loaded(torch.tensor(x_test[0:10]).float()).data完整代碼:
import torch import numpy as np import pandas as pd import matplotlib.pyplot as plt from torch import nn from torch.utils.data import Dataset,DataLoader,TensorDataset""" 一,準(zhǔn)備數(shù)據(jù) """#數(shù)據(jù)讀取 train_data = pd.read_csv('./data/titanic/train.csv') test_data = pd.read_csv('./data/titanic/test.csv') test_datay = pd.read_csv('./data/titanic/titanic.csv') #print(train_data.head(10)) #打印訓(xùn)練數(shù)據(jù)前十個train_data.info() #查看訓(xùn)練數(shù)據(jù)有沒有未知的的 test_data.info() #查看測試數(shù)據(jù)有沒有未知的的# #查看各部分分布情況 # # #幸存情況 # ax = train_data['Survived'].value_counts().plot(kind = 'bar',figsize = (12,8),fontsize =15,rot = 0) # #value_counts是查詢有多少個不同值且每個不同值有多少個重復(fù)的 # ax.set_ylabel('Counts',fontsize = 15) # ax.set_xlabel('Survived',fontsize = 15) # plt.show() # # #年齡分布情況 # ax = train_data['Age'].plot(kind = 'hist',bins = 20,color = 'purple',figsize = (12,8),fontsize = 15) # """ # hist方法常用的參數(shù)有以下幾個 # 1. bins,控制直方圖中的區(qū)間個數(shù) # 2. color,指定柱子的填充色 # 3. edgecolor, 指定柱子邊框的顏色 # 4. density,指定柱子高度對應(yīng)的信息,有數(shù)值和頻率兩種選擇 # 5. orientation,指定柱子的方向,有水平和垂直兩個方向 # 6. histtype,繪圖的類型 # """ # ax.set_ylabel('Frequency',fontsize = 15) # ax.set_xlabel('Age',fontsize = 15) # plt.show() # # #年齡和label的相關(guān)性 # ax = train_data.query('Survived == 0')['Age'].plot(kind = 'density',figsize = (12,8),fontsize = 15) # #使用python.query()函數(shù)對數(shù)據(jù)框進(jìn)行(挑選行)的操作 # train_data.query('Survived == 1')['Age'].plot(kind = 'density',figsize = (12,8),fontsize = 15) # ax.legend(['Survived ==0','Survived ==1'],fontsize = 12) # #plt.legend()函數(shù)主要的作用就是給圖加上圖例,plt.legend([x,y,z])里面的參數(shù)使用的是list的的形式將圖表的的名稱喂給這和函數(shù)。 # ax.set_ylabel('Density',fontsize = 15) # ax.set_xlabel('Age',fontsize = 15) # plt.show() # """ 數(shù)據(jù)預(yù)處理 """ def preprocessing(dfdata):dfresult = pd.DataFrame() #存儲結(jié)果#DataFrame是Python中Pandas庫中的一種數(shù)據(jù)結(jié)構(gòu),它類似excel,是一種二維表。#Pclass處理dfPclass = pd.get_dummies(dfdata['Pclass'])#對Pclass進(jìn)行g(shù)et_dummies,將該特征離散化dfPclass.columns = ['Pclass_'+str(x) for x in dfPclass.columns]dfresult = pd.concat([dfresult,dfPclass],axis=1)#concat函數(shù)是在pandas底下的方法,可以將數(shù)據(jù)根據(jù)不同的軸作簡單的融合,axis: 需要合并鏈接的軸,0是行,1是列#SexdfSex = pd.get_dummies(dfdata['Sex'])dfresult = pd.concat([dfresult, dfSex], axis=1)#Agedfresult['Age'] = dfdata['Age'].fillna(0)dfresult['Age_null'] = pd.isna(dfdata['Age']).astype('int32')#pandas.isna(obj)檢測array-like對象的缺失值# SibSp,Parch,Faredfresult['SibSp'] = dfdata['SibSp']dfresult['Parch'] = dfdata['Parch']dfresult['Fare'] = dfdata['Fare']# Carbindfresult['Cabin_null'] = pd.isna(dfdata['Cabin']).astype('int32')# EmbarkeddfEmbarked = pd.get_dummies(dfdata['Embarked'], dummy_na=True)dfEmbarked.columns = ['Embarked_' + str(x) for x in dfEmbarked.columns]#DataFrame.columns屬性以返回給定 DataFrame 的列標(biāo)簽。dfresult = pd.concat([dfresult, dfEmbarked], axis=1)return dfresult#獲得訓(xùn)練x,y x_train = preprocessing(train_data).values y_train = train_data[['Survived']].values#獲得測試x,y x_test = preprocessing(test_data).values y_test = test_datay[['Survived']].values# print("x_train.shape =", x_train.shape ) # print("x_test.shape =", x_test.shape ) # print("y_train.shape =", y_train.shape ) # print("y_test.shape =", y_test.shape ) # """ 進(jìn)一步使用DataLoader和TensorDataset封裝成可以迭代的數(shù)據(jù)管道。 """ dl_train = DataLoader(TensorDataset(torch.tensor(x_train).float(),torch.tensor(y_train).float()),shuffle = True, batch_size = 8) dl_valid = DataLoader(TensorDataset(torch.tensor(x_test).float(),torch.tensor(y_test).float()),shuffle = False, batch_size = 8) # # # #測試數(shù)據(jù)管道 # for features,labels in dl_valid: # print(features,labels) # break # """ 二,定義模型 """def creat_net():net = nn.Sequential()net.add_module("linear1",nn.Linear(15,20))net.add_module("relu1",nn.ReLU())net.add_module("linear2", nn.Linear(20, 15))net.add_module("relu2", nn.ReLU())net.add_module("linear3", nn.Linear(15, 1))net.add_module("sigmoid", nn.Sigmoid())return netnet = creat_net() #print(net)""" 三,訓(xùn)練模型 """from sklearn.metrics import accuracy_scoreloss_func = nn.BCELoss() optimizer = torch.optim.Adam(params=net.parameters(),lr=0.01) metric_func = lambda y_pred,y_true:accuracy_score(y_true.data.numpy(),y_pred.data.numpy()>0.5) #lambda表達(dá)式是起到一個函數(shù)速寫的作用。允許在代碼內(nèi)嵌入一個函數(shù)的定義。 #accuracy_score是分類準(zhǔn)確率分?jǐn)?shù)是指所有分類正確的百分比。 metric_name = "accuracy" #metric就是準(zhǔn)確率epochs = 10 log_step_freq = 30 dfhistory = pd.DataFrame(columns = ["epoch","loss",metric_name,"val_loss","val_"+metric_name])for epoch in range(1,epochs+1):#開始訓(xùn)練net.train()loss_sum = 0.0metric_sum = 0.0step = 1for step,(features,labels) in enumerate(dl_train,1):optimizer.zero_grad()#正向傳播predictions = net(features)loss = loss_func(predictions,labels)metric = metric_func(predictions,labels)#反向傳播loss.backward()optimizer.step()#打印batch日志loss_sum += loss.item()metric_sum += metric.item()if step%log_step_freq == 0:print(("[step = %d] loss: %.3f, " + metric_name + ": %.3f") %(step, loss_sum / step, metric_sum / step))#驗證循環(huán)net.eval()val_loss_sum = 0.0val_metric_sum = 0.0val_step = 1for val_step, (features, labels) in enumerate(dl_valid, 1):predictions = net(features)val_loss = loss_func(predictions, labels)val_metric = metric_func(predictions,labels)val_loss_sum += val_loss.item()val_metric_sum += val_metric.item()#記錄日志info = (epoch, loss_sum / step, metric_sum / step,val_loss_sum / val_step, val_metric_sum / val_step)dfhistory.loc[epoch - 1] = info# 打印epoch級別日志print(("\nEPOCH = %d, loss = %.3f," + metric_name + " = %.3f, val_loss = %.3f, " + "val_" + metric_name + " = %.3f")% info)""" 四,評估模型 """ def plot_metric(dfhistory, metric):train_metrics = dfhistory[metric]val_metrics = dfhistory['val_'+metric]epochs = range(1, len(train_metrics) + 1)plt.plot(epochs, train_metrics, 'bo--')plt.plot(epochs, val_metrics, 'ro-')plt.title('Training and validation '+ metric)plt.xlabel("Epochs")plt.ylabel(metric)plt.legend(["train_"+metric, 'val_'+metric])plt.show()plot_metric(dfhistory,"loss") plot_metric(dfhistory,"accuracy")""" 五,使用模型 """ y_pred_probs = net(torch.tensor(x_test[0:10]).float()).data y_pred = torch.where(y_pred_probs>0.5,torch.ones_like(y_pred_probs),torch.zeros_like(y_pred_probs))# """ # # 六,保存模型 # """ # #保存模型參數(shù)(推薦) # print(net.state_dict().keys()) # # 保存模型參數(shù) # torch.save(net.state_dict(), "./data/net_parameter.pkl") # net_clone = creat_net() # net_clone.load_state_dict(torch.load("./data/net_parameter.pkl")) # net_clone.forward(torch.tensor(x_test[0:10]).float()).data # # #保存完整模型(不推薦) # torch.save(net, './data/net_model.pkl') # net_loaded = torch.load('./data/net_model.pkl') # net_loaded(torch.tensor(x_test[0:10]).float()).data總結(jié)
以上是生活随笔為你收集整理的结构化数据建模——titanic数据集的模型建立和训练(Pytorch版)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到被追着跑预示着什么
- 下一篇: 《20天吃透Pytorch》Pytorc