LoginSignup
3
2

More than 1 year has passed since last update.

Tensorflowによるカテゴリー分類の、CSVデータのデータセットの作り方

Last updated at Posted at 2021-04-11

はじめに

 こんにちは、新しい技術が大好きな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では日常や生活習慣などに関する二択の質問を行っています。

質問の内容とラベルの内容 みづらくてゴメンなさい:confounded:

image.png

それぞれの回答を数字に変換したデータは以下のようになっています。

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を利用しました。

secondLanguageRecommend.ipynb

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

変数のセット

secondLanguageRecommend.ipynb

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
secondLanguageRecommend.ipynb

# データの読み込み
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))

出力

out

[[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公式ドキュメント

secondLanguageRecommend.ipynb

# 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))

出力

out
[[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の回答だけではない場合は正規化という作業も必要ですので、時間があれば追記いたします。
ここまで読んでいただきありがとうございました。

最後に今回のコードを貼っておきます。

secondLanguageRecommend.ipynb

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])
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2