koji/メガネ男の日誌

日々の学び、活動状況を記録します。仕事のことは少なめ。

Titanicのデータを使ってPytorchを試してみた

f:id:kj_man666:20200712182438j:plain

(9/23 修正)NetクラスのNNの数を圧縮
       評価基準を正解率、適合率、再現率、f1値に修正

note.nkmk.me

タイタニックのデータを使ってPyTorchの実装をしてみました。

なお、PyTorchのコードは、こちらのサイトから拝借させていただきました、ありがとうございます。

rf00.hatenablog.com

本ブログのコードはこちらからダウンロードできます。

タイタニックのデータについてはkaggleのタイタニックコンペを参照するとよいかと思います。

www.kaggle.com

import pandas as pd
import numpy as np

from IPython.display import display
from sklearn.model_selection import train_test_split

from sklearn.metrics import accuracy_score # 正解率
from sklearn.metrics import precision_score # 適合率
from sklearn.metrics import recall_score # 再現率
from sklearn.metrics import f1_score # F1値

# pytorch
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

pd.set_option('max_columns', 500)
pd.set_option('max_rows', 500)

# タイタニックのデータの読込
url = "https://raw.githubusercontent.com/mwaskom/seaborn-data/master/raw/titanic.csv"
df = pd.read_csv(url)

display(df.head())
display(df.tail())
display(df.shape)

f:id:kj_man666:20200712182314p:plain

# 特徴量を適当に指定
feature = ["pclass", "sibsp", "parch", "fare"]

X_train, X_test, y_train, y_test = train_test_split(df[feature], df["survived"], test_size=0.3, random_state=42)

display(X_train.shape) # (623, 4)

PyTorchのデータセットは、numpy型を取り込んで、tensor型でする必要があります。

そこで、.valuesを使ってDataFrame型からnumpy.ndarray型に変換して、torch.Tesor()、LongTensor()でtensor型に変換しています。

また、説明変数をTensor()、目的変数をLongTensor()で変換しないと、RuntimeErrorが発生しますので間違えないようにしましょう。

Longというのは、PyTorchで使われる64bitの整数の型のようです。

X_train = torch.Tensor(X_train.values)
X_test = torch.Tensor(X_test.values)
y_train = torch.LongTensor(y_train.values)
y_test = torch.LongTensor(y_test.values) 

# シードを固定
torch.manual_seed(42)

ニューラルネットの関数です。

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(4, 20)  # (X_train.shape[1], X)
        self.fc2 = nn.Linear(20, 10) # (X, Y)
        self.fc3 = nn.Linear(10, 2)   # (Y, Z)
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.relu(self.fc3(x))
        return F.log_softmax(x, dim = 1)

関数の中に設定されている数値が気になりますね。

self.fc1 = nn.Linear(4, 20)
self.fc2 = nn.Linear(20, 10)
self.fc3 = nn.Linear(10, 2)

self.fc1 の1番目の数値 X_trainの次元数 4
 (参考)X_train.shape → (623, 4)

self.fc1 の2番目の数値と、self.fc2 の1番目の数値を同じにする

self.fc2 の2番目の数値と、self.fc3 の1番目の数値を同じにする

2クラス分類なので、self.fc3 の2番目の数値を 2 にする

数学よわよわ勢なので間違っているかもしれませんが・・・行列の積ができるようにそろえているんでしょう。

model = Net()
print(model)

optimizer = optim.SGD(model.parameters(), lr=0.02)
train_loss = []
train_accu = []
i = 0

model.train() #学習モードに切り替え

for epoch in range(2000): # 数字は適当
    data, target = Variable(X_train), Variable(y_train)
    optimizer.zero_grad()
    output = model(data) 
        
    loss = F.nll_loss(output, target)
    loss.backward()
    train_loss.append(loss.data.item())
    optimizer.step()
        
    prediction = output.data.max(1)[1]
    accuracy = prediction.eq(target.data).sum().numpy() / len(X_train)
    train_accu.append(accuracy)
    
    if i % 10 == 0:
        print('Train Step: {}\tLoss: {:.3f}\tAccuracy: {:.3f}'.format(i, loss.data.item(), accuracy))
    i += 1

print('Train Step: {}\tLoss: {:.3f}\tAccuracy: {:.3f}'.format(i, loss.data.item(), accuracy))

model.eval() #推論モードに切り替え
outputs = model(Variable(X_test))
_, predicted = torch.max(outputs.data, 1)

# 誤差算定
print(f"正解率 :{accuracy_score(y_test, predicted)}")
print(f"適合率 :{precision_score(y_test, predicted)}")
print(f"再現率 :{recall_score(y_test, predicted)}")
print(f"F1スコア :{f1_score(y_test, predicted)}")

精度は以下のとおりでした。

正解率 :0.7238805970149254
適合率 :0.6907216494845361
再現率 :0.6036036036036037
F1スコア :0.6442307692307693

以上になります、最後までお読みいただきありがとうございました。