はじめに
こんにちは、新しい技術が大好きなsazanami5です。qiita初投稿ですのでお手柔らかにお願いします。ご意見、ご指摘等ありましたらぜひコメントいただけると嬉しいです。
流行りの深層学習に興味を持ち、「深層学習の教科書」という本を読んでからtensorflowで時々遊んでいます。最近、TensorFlowを使ってカテゴリー分類の機械学習を自前のCSVデータで動かしたのですが、データセットがうまく作れず、少し苦戦してしまいました。データセットを作る方法をまとめた記事があまりなく、TensorFlowチュートリアルも少し読みにくかったため、今回データセットの作り方を中心に投稿させていただくことにしました。
よくあるアヤメの分類のようなカテゴリー分類のためのデータセットを作っています。
環境
私はローカルの仮想環境で実行していますが、Google Colaboratoryを利用すれば環境構築の必要はありません。
python 3.8.6
tensorflow 2.4.1
numpy 1.19.5
pandas1.2.1
matplotlib 3.3.3
使用するCSVデータ
このデータは第二外国語を学習したことのある人を対象に行ったものです。
学習したことのある第二外国語(その他を含む8言語の中から選択)を最初に聞き、Q1~Q30では日常や生活習慣などに関する二択の質問を行っています。
それぞれの回答を数字に変換したデータは以下のようになっています。
language | Q1 | Q2 | Q3 | ... | Q30 |
---|---|---|---|---|---|
0 | 0 | 1 | 0 | ... | 1 |
1 | 0 | 0 | 0 | ... | 0 |
2 | 1 | 0 | 0 | ... | 1 |
6 | 0 | 0 | 0 | ... | 1 |
4 | 1 | 0 | 0 | ... | 1 |
2 | 1 | 0 | 0 | ... | 0 |
... | ... | ... | ... | ... | ... |
2 | 1 | 0 | 0 | ... | 1 |
#データセットを作る
ついに本題のデータセットの作り方について説明します。
上で用意したcsvデータを、分類するラベル(languageのカラム)と学習させるデータ(languageカラム以外の列)に分ける必要があります。
pandas等を使ってコードでも出来るのですが、今回はExcelを使い、以下の4つのファイルを作成しました。
訓練用データ(データの7割)
x_train.csv(languageカラム以外の列)
y_train.csv(languageカラムの列)
評価用データ(データの3割)
x_eval.csv(languageカラム以外の列)
y_eval.csv(languageカラムの列)
###ライブラリのインポート
必要なライブラリをインポートします。
データ処理は私が慣れているPandasを利用しました。
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation
from tensorflow.keras.optimizers import Adam
import numpy as np
import pandas as pd
変数のセット
tf.random.set_seed(0) #再現性を持たせるためにランダムの値を固定する
num_classes = 8 #ラベルの種類が8つ
batch_size = 5
epochs = 20
CSVデータの読み込み
pd.read_csvを使って読み込みます。windowsやmacのどちらのデータでも使えるようにするため、念の為エンコードをutf-8に指定しています。
データ構造
secondLanguageRecommend
├ secondLanguageRecommend.ipynb
└ data/
├ x_train.csv
├ x_eval.csv
├ y_train.csv
└ y_eval.csv
# データの読み込み
x_train = pd.read_csv("data/x_train.csv", encoding= "utf-8")
x_test = pd.read_csv("data/x_eval.csv", encoding= "utf-8")
y_train = pd.read_csv("data/y_train.csv", encoding= "utf-8")
y_test = pd.read_csv("data/y_eval.csv", encoding= "utf-8")
# 一行目のカラムの行を取り除き、数値部分のみにする
x_train = x_train.values
x_test = x_test.values
y_train = y_train.loc[:,"language"]
y_test = y_test.loc[:,"language"]
print(x_train[:10])
print(type(x_train))
出力
[[0 1 0 1 0 0 1 0 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1 0 1 0 1 1]
[0 0 0 0 0 0 1 1 0 0 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 0 1 1 0]
[1 0 0 1 0 1 0 0 0 0 0 0 0 1 1 1 1 1 0 1 1 0 1 1 1 0 1 0 0 1]
[0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 1 0 1 0 1 0 1 1]
[1 0 0 1 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 1 0 0 1 0 0 1 1]
[1 0 0 1 0 1 0 0 1 0 1 0 0 0 0 1 1 0 1 0 1 0 0 0 0 0 0 0 0 1]
[0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 1 1 1 0 1 1 0 0 0 0 1 1 1 0]
[0 0 0 0 0 1 1 0 1 1 0 1 0 1 0 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1]
[0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 1 1 1 0 1 1 0 1 0 0 1 0 0 1 0]
[0 1 0 1 0 0 1 1 1 1 1 0 0 1 1 0 1 1 1 0 0 1 1 1 0 1 0 0 1 1]]
<class 'numpy.ndarray'>
ここで型がnumpy.ndarrayになっていることが大事です。
自分はここでDataFrameやlistではできないことを知らなくてつまずきました。ぴえん。
全ての列のデータを取りたい時は.values
、特定の列のデータを取りたい時は.loc[:,"カラム名1","カラム名2"]
を使ってください。
ラベルをone-hotベクトルにする
one-hotベクトルとは
One-hot ベクトルとは、(0,1,0,0,0,0) のように、1つの成分が1で残りの成分が全て0であるようなベクトルのことです。
引用元:算数から高度な数学まで、網羅的に解説したサイト
今回は0〜7の8個のカテゴリーがあるので、[[0][4][3]]のようなデータを[[1,0,0,0,0,0,0,0][0,0,0,0,1,0,0,0][0,0,0,1,0,0,0,0]]にするということです。
kerasにあるto_categorical関数を使って変換します。
keras公式ドキュメント
# convert class vectors to binary class matrices
y_train = tf.keras.utils.to_categorical(y_train, num_classes)
y_test = tf.keras.utils.to_categorical(y_test, num_classes)
print(y_train[:10])
print(type(y_train))
出力
[[0. 1. 0. 0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0. 0. 0.]
[1. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 1. 0. 0. 0. 0.]
[1. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0. 0. 0.]
[0. 0. 0. 1. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0. 0. 0.]]
<class 'numpy.ndarray'>
変換できました。
これでデータセットは完成です。
これをそのままfitの引数に渡すことで学習できます。
まとめ
- 型はnumpy.ndarray
- カテゴリー分類はone-hotベクトルに変換
最後に
データセットの作り方は今回の方法の他にも様々なものがあり、どれが正解というものでもないと思います。
一つの選択肢として誰かの役に立てば幸いです。
また、今回のような0と1の回答だけではない場合は正規化という作業も必要ですので、時間があれば追記いたします。
ここまで読んでいただきありがとうございました。
最後に今回のコードを貼っておきます。
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation
from tensorflow.keras.optimizers import Adam
import numpy as np
import pandas as pd
tf.random.set_seed(0)
num_classes= 8
batch_size= 5
epochs= 20
#load data
x_train= pd.read_csv("data/x_train.csv", encoding= "utf-8")
x_test= pd.read_csv("data/x_eval.csv", encoding= "utf-8")
y_train= pd.read_csv("data/y_train.csv", encoding= "utf-8")
y_test= pd.read_csv("data/y_eval.csv", encoding= "utf-8")
y_train = y_train.loc[:,"language"]
y_test = y_test.loc[:,"language"]
x_train = x_train.values
print(x_train[:10])
print(type(x_train))
# convert class vectors to binary class matrices
y_train = tf.keras.utils.to_categorical(y_train, num_classes)
y_test = tf.keras.utils.to_categorical(y_test, num_classes)
print(y_train[:10])
print(type(y_train))
# モデル作成
model = Sequential()
model.add(Dense(32, activation='relu', input_shape=(30,)))
model.add(Dense(32, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
model.summary()
model.compile(loss='categorical_crossentropy',
optimizer="adam",
metrics=['accuracy'])
# モデルを学習
history = model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test))
# テストデータに対して誤差と精度を評価
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])