アラカン"BOKU"のITな日常

文系システムエンジニアの”BOKU”が勉強したこと、経験したこと、日々思うことを書いてます。

入力データをCSVファイルから読む機能を実装する。:Tensorflow入門の入門4/文系向け

今回は、テキストデータのインプットをCSVファイルから読み込むようにしてみます。

 

前回からの続きなので、初めての方は、こちらの記事を先に読んでください。

 

ニューラルネットワークの部分は、前回のをそのまま使います。

 

だから、データは前のままです。

データ部:[1.2,2.3,5.4,2.4,1.6]

正解ラベル:[1.,0.]

 

これをCSVファイルから読み込むので、データ部と正解ラベルをくっつけて、5列目までがデータ部、6列目と7列目が正解ラベルみたいなデータ形式にします。 

1.2,2.3,5.4,2.4,1.6,1.0,0.0

 

これをEXCELの計算式を使って、0.3位ずつ増やしたり減らしたりして、60行くらいにして、それをCSVに保存しておきます。

 

注意点は、文字コードと改行コードですね。

 

今回は使わないですが、TensorflowのReaderを使う時に改行コードはUNIX形式(LFのみ)しか認識してくれなかったので、後ではまらないために、エディタ等を使って、文字コードは UTF-8、改行コードはUNIX形式(LF)に変換しておいた方が良いみたいです。

 

学習実行部の修正

前はこうでした。データはソースに手書きですね。

s.run(train_step,feed_dict={data:[[1.2,2.3,5.4,2.4,1.6],[9.2,8.3,7.4,6.5,5.6]],label:[[1.,0.],[0.,1.]]})

 

これを、CSVファイルからデータを読み込んで、pythonのリストにセットして、feed_dictに渡すように変更します。

 

こんな感じです。

s.run(train_step,feed_dict={data:data_body,label:label_body})

 

CSVファイルの読み込みと行列への変換

TensorflowにもCSVを読む機能はあります。

https://www.tensorflow.org/programmers_guide/reading_data

 

でも、今回は使いません。

 

理由は、TensorflowのCSVファイルを読む機能を使うと、取得できるのがTensorテンソル)型になってしまうからです。

 

それを整形して、feed_dictの部分に渡すと、Tensorテンソル)は駄目だよと怒られてしまいます。

 

なので、今回は普通にpythonの処理として、CSVファイルの読み込みと行列データへの変換を行います。

 

CSVファイルを読み込んで、行列データに変換する部分のソースコードです。

import csv

csv_obj = csv.reader(open("sample.csv", "r"))
dt = [ v for v in csv_obj]
dat = [[float(elm) for elm in v] for v in dt]
data_body = [[0 for n in range(5)] for m in range(len(dat))]
label_body = [[0 for nn in range(2)] for mm in range(len(dat))]
for i in range(len(dat)):
    for j in range(len(dat[i])):
         if j <= 4:
              data_body[i][j] = dat[i][j]
        else:
              label_body[i][j-5] = dat[i][j]

 

1行ずつ動きを確認していきます。 

csv_obj = csv.reader(open("sample.csv", "r"))

 データをsample.csvという名前で保存しているので、それを一旦読んでCSVオブジェクトというものに変換しています。

 

printすると、こんな感じで表示されます。わけわかりませんね。

<_csv.reader object at 0x0000016E8F6455F8>

 

このcsv_objectを、行列データに変換するのが次の行です。

dt = [ v for v in csv_obj]

 

python独特の「リスト内包表記」という記法です。これを通すことで以下のような行列データにファイルの中身を変換して書き出してくれます。

[['8.9 ', '8.0 ', '7.1 ', '6.2 ', '5.3 ', '0.0 ', '1.0 '], ['8.6 ', '7.7 ', '6.8 ', '5.9 ', '5.0 ', '0.0 ', '1.0 ']]

 

でも、これだと'(シングルコーテーション)がついて、文字列型になってますよね。

 

このまま、feed_dictに渡すと、数値じゃないと怒られます。

 

なので、これを”float"型に変換してやるコードです。

dat = [[float(elm) for elm in v] for v in dt]

 

これを通した結果はこうなります。

[[8.9, 8.0, 7.1, 6.2, 5.3, 0.0, 1.0], [8.6, 7.7, 6.8, 5.9, 5.0, 0.0, 1.0]]

 

バッチリです。

 

でも、CSVファイルから読んだだけで、前5列のデータ部と、後ろ2列の正解ラベル部がくっついているので、これをデータ用(data_body)と、ラベル用(label_body)に分解してやる必要があります。

 

それを行うコードです。まず、結果を格納する行列を作ります。

data_body = [[0 for n in range(5)] for m in range(len(dat))]
label_body = [[0 for nn in range(2)] for mm in range(len(dat))]

 上は5列分、下は2列分の行列を、ファイルの行数分<len(dat)>確保します。

 

注意点は、以下のように初期化したら駄目だということ。

 data_body = [[0] * 5 ] * len(dat)
label_body = [[0] * 2 ] * len(dat)

 こうすると、一見うまくいったように見えて、出力してみたら同じ値ばっかりがセットされた悲しい結果が生まれます。

 

理由に興味のある方は、こちらをどうぞ。

 

あとは、ループを回して突っ込むだけです。

for i in range(len(dat)):
     for j in range(len(dat[i])):
          if j <= 4:
               data_body[i][j] = dat[i][j]
          else:
               label_body[i][j-5] = dat[i][j]

 

データ部が前5列なんですが、添字は0から始まるので5列目の添字は4になります。 それで、単純に振り分けているだけですね。 

 

2017/5/30追記

上記CSVファイルの読み込み部分を関数化して、汎用的に使えるようにする方法については以下の記事の中で書いています。

arakan-pgm-ai.hatenablog.com

 

どうやら過学習がおきてるみたい・・

 

これでOKなんですけど、このまま60件くらいのデータで学習させると、未知のデータをテストデータに対して、正解率50.0%程度という悲惨な結果になりました。

 

どうやら過学習がおきてるみたいです。

 

ためしに、学習に使ったデータをそのままテストにも使ってみます。

 

100%・・。まさに、THE 過学習ですね。

f:id:arakan_no_boku:20170507175435j:plain

 

過学習は、過剰適合とも言うのですが、ようするに学習データに対して適合しすぎて、未知データ(テストデータ)に対して適合できない=一致しているという正しい判断ができなくなると言うことです。

 

過学習は、学習データの量が少ない時に発生しやすいと言われているので、過学習を防ぐ対策をしないまま、60件程度のほぼ類似データを学習させるというのは、「さあ、過学習してみやがれ・・」と宣言しているに等しいですからね。 

 

 まあ、しょうがないです。

 

今回は、CSVファイルから読む機能を実装するのが目的なので、過学習対策は宿題にしておきます。

 

最後に今回のソース全体を掲載しておきます。

import tensorflow as tf
import csv

csv_obj = csv.reader(open("sample.csv", "r"))
dt = [ v for v in csv_obj]
dat = [[float(elm) for elm in v] for v in dt]
data_body = [[0 for n in range(5)] for m in range(len(dat))]
label_body = [[0 for nn in range(2)] for mm in range(len(dat))]
print(data_body)
for i in range(len(dat)):
    for j in range(len(dat[i])):
        if j <= 4:
             data_body[i][j] = dat[i][j]
        else:
             label_body[i][j-5] = dat[i][j]
             
bias = tf.Variable(tf.zeros([2],dtype=tf.float32))
weight = tf.Variable(tf.random_uniform(shape=[5,2],minval=-1.0,maxval=1.0,dtype=tf.float32))
data = tf.placeholder(dtype=tf.float32,shape=[None,5])
label = tf.placeholder(dtype=tf.float32,shape=[None,2])
y = tf.nn.softmax(tf.matmul(data,weight) + bias)
cross_entropy = tf.reduce_mean(-tf.reduce_sum(label * tf.log(y), reduction_indices=[1]))
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(label,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
with tf.Session() as s:
    s.run(tf.global_variables_initializer())
    print(data_body)
    for k in range(10):
        s.run(train_step,feed_dict={data:data_body,label:label_body})
    acc = s.run(accuracy, feed_dict={data:data_body,label:label_body})
    print("結果:{:.2f}%".format(acc * 100))

 

 

2017/12/09追記

いちおう、tensorflow v1.4で動作確認しました。

 

2018/02/12追記

tensorflow v1.5で動作確認しました。

 


tensorflow入門の入門カテゴリの記事一覧はこちらです。arakan-pgm-ai.hatenablog.com

 

 

f:id:arakan_no_boku:20170404211107j:plain