结构化数据建模——titanic数据集的模型建立和训练(Pytorch版)
本文參考《20天吃透Pytorch》來實現titanic數據集的模型建立和訓練
在書中理論的同時加入自己的理解。
一,準備數據
數據加載
titanic數據集的目標是根據乘客信息預測他們在Titanic號撞擊冰山沉沒后能否生存。
結構化數據一般會使用Pandas中的DataFrame進行預處理。
數據集字段如下:
字段說明:
Survived:0代表死亡,1代表存活【y標簽】
Pclass:乘客所持票類,有三種值(1,2,3) 【轉換成onehot編碼】
Name:乘客姓名 【舍去】
Sex:乘客性別 【轉換成bool特征】
Age:乘客年齡(有缺失) 【數值特征,添加“年齡是否缺失”作為輔助特征】
SibSp:乘客兄弟姐妹/配偶的個數(整數值) 【數值特征】
Parch:乘客父母/孩子的個數(整數值)【數值特征】
Ticket:票號(字符串)【舍去】
Fare:乘客所持票的價格(浮點數,0-500不等) 【數值特征】
Cabin:乘客所在船艙(有缺失) 【添加“所在船艙是否缺失”作為輔助特征】
Embarked:乘客登船港口:S、C、Q(有缺失)【轉換成onehot編碼,四維度 S,C,Q,nan】
加載數據集:
#數據讀取 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)) #打印訓練數據前十個當我們獲得數據集后,首先要查看數據中是否有缺失!!!這個很重要!
train_data.info() #查看訓練數據有沒有未知的的 test_data.info() #查看測試數據有沒有未知的的
很明顯,Age和Cabin數據都有缺失
接下來,先利用Pandas的數據可視化分析數據:
幸存情況
#幸存情況 ax = train_data['Survived'].value_counts().plot(kind = 'bar',figsize = (12,8),fontsize =15,rot = 0) #value_counts是查詢有多少個不同值且每個不同值有多少個重復的 ax.set_ylabel('Counts',fontsize = 15) ax.set_xlabel('Survived',fontsize = 15) plt.show()
年齡分布情況
年齡和label的相關性
數據預處理
這個步驟非常非常重要! 不僅要加載數據集,更重要的是如何處理NULL數據!
""" 數據預處理 """ def preprocessing(dfdata):dfresult = pd.DataFrame() #存儲結果#DataFrame是Python中Pandas庫中的一種數據結構,它類似excel,是一種二維表。#Pclass處理dfPclass = pd.get_dummies(dfdata['Pclass'])#對Pclass進行get_dummies,將該特征離散化dfPclass.columns = ['Pclass_'+str(x) for x in dfPclass.columns]dfresult = pd.concat([dfresult,dfPclass],axis=1)#concat函數是在pandas底下的方法,可以將數據根據不同的軸作簡單的融合,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 的列標簽。dfresult = pd.concat([dfresult, dfEmbarked], axis=1)return dfresult#獲得訓練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 )這里重點講解一下對數據缺失部分的處理!
以Age字段,我們通過fillna(0),將Age字段中的NaN替換成0
然后通過 pd.isna將空值點的地方記錄下來(添加“年齡是否缺失”作為輔助特征)
這里我把測試數據中的Age部分除了前兩個后面全設置為NULL
然后把dfresult['Age'],dfresult['Age_null']打印出來:
可以看看下面這個文章,我收到了很多啟發。
data是一個pandas.DataFrame數據對象,是從mysql讀取的數據。由于有的列在數據庫是int類型,而且有空值(Null),因此在從數據庫抽取到df對象后,pandas自動將int轉成float,比如10變成了10.0,15902912345變成了1.5902912345E10,Null變成了NaN。這種列由于存在NaN,因此不能用DataFrame.astype()方法轉成int類型。
我們的目的就是盡量讓pandas抽取的數據跟數據庫“看上去”一致。比如原來是int類型的,如果被替換成float了,那么需要轉換回去,原來是Null的,被pandas改成NaN了,需要替換成空字符串。由于pandas列的int類型不能為空,所以需統一轉換成字符串類型。
為了達到將列轉換成int類型原來的展現形式(可以是object類型,相當于str,此時10還是展示為10),且NaN轉換成空值這個目的,可以采取如下步驟:
1.生成新的df對象,保存data里為NaN的位置標記
2.將data需要處理的列,NaN值替換為float能允許的類型,如0,下面會用到
3.將該列轉換成int類型,此時10.0轉換成10,1.5902912345E10轉換成15902912345
4.將該列轉換成object類型,此時所有數值按str類型原樣保存
5.用NaN位置標記的df對象作為索引,替換原df對象中為0的值到空字符串
利用pandas.DataFrame.isna方法做替換(很棒的技巧)
進一步使用DataLoader和TensorDataset封裝成可以迭代的數據管道。
""" 進一步使用DataLoader和TensorDataset封裝成可以迭代的數據管道。 """ 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)# 測試數據管道 for features,labels in dl_train:print(features,labels)break二,定義模型
使用Pytorch通常有三種方式構建模型:使用nn.Sequential按層順序構建模型,繼承nn.Module基類構建自定義模型,繼承nn.Module基類構建模型并輔助應用模型容器進行封裝。
此處選擇使用最簡單的nn.Sequential,按層順序模型。
三,訓練模型
""" 三,訓練模型 """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表達式是起到一個函數速寫的作用。允許在代碼內嵌入一個函數的定義。 #accuracy_score是分類準確率分數是指所有分類正確的百分比。 metric_name = "accuracy" #metric就是準確率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):#開始訓練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))#驗證循環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")這里補充一下 dfhistory
dfhistory來源于第三部分訓練模型中:
dfhistory = pd.DataFrame(columns = ["epoch","loss",metric_name,"val_loss","val_"+metric_name])DataFrame是Python中Pandas庫中的一種數據結構,它類似excel,是一種二維表。
dfhistory的作用就是跟蹤數據,在訓練的過程中記錄每一步的訓練結果。
通過在dfhistory調取訓練數據和測試數據進行對比繪圖!
結果展示:
五,使用模型
""" 五,使用模型 """ 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))六,保存模型
""" # 六,保存模型 """ #保存模型參數(推薦) print(net.state_dict().keys()) # 保存模型參數 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""" 一,準備數據 """#數據讀取 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)) #打印訓練數據前十個train_data.info() #查看訓練數據有沒有未知的的 test_data.info() #查看測試數據有沒有未知的的# #查看各部分分布情況 # # #幸存情況 # ax = train_data['Survived'].value_counts().plot(kind = 'bar',figsize = (12,8),fontsize =15,rot = 0) # #value_counts是查詢有多少個不同值且每個不同值有多少個重復的 # 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方法常用的參數有以下幾個 # 1. bins,控制直方圖中的區間個數 # 2. color,指定柱子的填充色 # 3. edgecolor, 指定柱子邊框的顏色 # 4. density,指定柱子高度對應的信息,有數值和頻率兩種選擇 # 5. orientation,指定柱子的方向,有水平和垂直兩個方向 # 6. histtype,繪圖的類型 # """ # ax.set_ylabel('Frequency',fontsize = 15) # ax.set_xlabel('Age',fontsize = 15) # plt.show() # # #年齡和label的相關性 # ax = train_data.query('Survived == 0')['Age'].plot(kind = 'density',figsize = (12,8),fontsize = 15) # #使用python.query()函數對數據框進行(挑選行)的操作 # train_data.query('Survived == 1')['Age'].plot(kind = 'density',figsize = (12,8),fontsize = 15) # ax.legend(['Survived ==0','Survived ==1'],fontsize = 12) # #plt.legend()函數主要的作用就是給圖加上圖例,plt.legend([x,y,z])里面的參數使用的是list的的形式將圖表的的名稱喂給這和函數。 # ax.set_ylabel('Density',fontsize = 15) # ax.set_xlabel('Age',fontsize = 15) # plt.show() # """ 數據預處理 """ def preprocessing(dfdata):dfresult = pd.DataFrame() #存儲結果#DataFrame是Python中Pandas庫中的一種數據結構,它類似excel,是一種二維表。#Pclass處理dfPclass = pd.get_dummies(dfdata['Pclass'])#對Pclass進行get_dummies,將該特征離散化dfPclass.columns = ['Pclass_'+str(x) for x in dfPclass.columns]dfresult = pd.concat([dfresult,dfPclass],axis=1)#concat函數是在pandas底下的方法,可以將數據根據不同的軸作簡單的融合,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 的列標簽。dfresult = pd.concat([dfresult, dfEmbarked], axis=1)return dfresult#獲得訓練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 ) # """ 進一步使用DataLoader和TensorDataset封裝成可以迭代的數據管道。 """ 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) # # # #測試數據管道 # 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)""" 三,訓練模型 """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表達式是起到一個函數速寫的作用。允許在代碼內嵌入一個函數的定義。 #accuracy_score是分類準確率分數是指所有分類正確的百分比。 metric_name = "accuracy" #metric就是準確率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):#開始訓練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))#驗證循環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))# """ # # 六,保存模型 # """ # #保存模型參數(推薦) # print(net.state_dict().keys()) # # 保存模型參數 # 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總結
以上是生活随笔為你收集整理的结构化数据建模——titanic数据集的模型建立和训练(Pytorch版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到被追着跑预示着什么
- 下一篇: 梦到陌生的地方预示什么