LoginSignup
5
2

More than 5 years have passed since last update.

【Python】ニューラルネットによるサザエさんのじゃんけん予想

Last updated at Posted at 2018-08-18

目次

はじめに

LSTMによるサザエさんのじゃんけん予想」という記事を書いたばかりなのですが、早速違うモデルでも試してみたのでその結果を書き留めておきます。

ソースコード

import numpy as np
import pandas as pd
from keras.layers import Activation, Dense
from keras.models import Sequential

data_file = 'サザエさんじゃんけん.tsv'
res_file = 'small_neural'


def shuffle_lists(list1, list2):
    '''リストをまとめてシャッフル'''
    seed = np.random.randint(0, 1000)
    np.random.seed(seed)
    np.random.shuffle(list1)
    np.random.seed(seed)
    np.random.shuffle(list2)


def get_data():
    '''データ作成'''
    df = pd.read_csv(data_file, sep='\t',
                     usecols=['rock', 'scissors', 'paper'])
    X_data = [[0, 0, 0]]
    for row in df.values:
        data = [d + 1 for d in X_data[-1]]
        data[row.argmax()] = 0
        X_data.append(data)

    # numpy.array型に変換
    # X_data = np.array(X_data[:-1])
    # y_data = np.array(df.values)
    X_data = np.array(X_data[-501:-1])
    y_data = np.array(df.values[-500:])

    last_data = np.array(X_data[-1:])

    # 正規化
    X_data = X_data.astype(np.float32)
    last_data = last_data.astype(np.float32)
    X_data /= 255.0
    last_data /= 255.0

    # シャッフル
    shuffle_lists(X_data, y_data)

    return X_data, y_data, last_data


def get_model():
    '''モデルを構築'''
    model = Sequential()
    model.add(Dense(32, input_shape=(3,)))
    model.add(Activation('relu'))
    model.add(Dense(32))
    model.add(Activation('relu'))
    model.add(Dense(32))
    model.add(Activation('relu'))
    model.add(Dense(3))
    model.add(Activation('softmax'))
    model.compile(optimizer='adam',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    return model


def pred(model, X, Y, label):
    '''正解率 出力'''
    predictX = model.predict(X)
    correct = 0
    for real, predict in zip(Y, predictX):
        if real.argmax() == predict.argmax():
            correct += 1
    correct = correct / len(Y)
    print(label + '正解率 : %02.2f ' % correct)


def main():
    X_data, y_data, last_data = get_data()

    # データ分割
    mid = int(len(y_data) * 0.7)
    train_X, train_y = X_data[:mid], y_data[:mid]
    test_X, test_y = X_data[mid:], y_data[mid:]

    # 学習
    model = get_model()
    hist = model.fit(train_X, train_y, epochs=1000, batch_size=8,
                     validation_data=(test_X, test_y))

    # 正解率出力
    pred(model, train_X, train_y, 'train')
    pred(model, test_X, test_y, 'test')

    # 来週の手
    next_hand = model.predict(last_data)
    print(next_hand[0])
    hands = ['グー', 'チョキ', 'パー']
    print('来週の手 : ' + hands[next_hand[0].argmax()])


if __name__ == '__main__':
    main()

簡単に解説

今回は簡単なニューラルモデルで学習してみました。
データは、それぞれの手が出てない回数にしました。

サザエさんじゃんけん.tsv には以下の形式でデータをまとめてあります。

サザエさんじゃんけん.tsv
year    month   day rock    scissors    paper
1991    11  10  0   1   0
1991    11  17  1   0   0
1991    11  24  1   0   0
...

そこから, データを以下のように整形

[[0 0 0] <- 最初はすべて0
 [1 0 1] <- チョキが出たので1番目を0に。ほかは+1
 [0 1 2] <- グーが出たので0番目を0に。ほかは+1
 ...

データをすべて使うとなぜか精度が精度が落ちるので、ここでは直近の100回分のみ使用しています。

結果

パラメータや層数を変えてみて一番良かった結果がこちらです。

  • 出力
train正解率 : 0.61
test正解率 : 0.58
[0.17965864 0.07733747 0.7430039 ]
来週の手 : パー
  • グラフ

neural.png

最後に

精度はLSTMのときとたいして変りませんでしたが、来週の手が「パー」になりました。ただ、パラメータをいじっているとちょいちょい「グー」も出ます。(どちらを信じたらいいんだorz)

使用する素性次第でまだまだ改善の余地があるかと思いますので、皆さんも是非チャレンジしてみてください。

とりあえず、今週のサザエさんを楽しみにしてます。

追記

(18/08/19)
残念ながら今回は外れてしまいました。(正解はグーでした)

参考リンク

LSTMによるサザエさんのじゃんけん予想

5
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
5
2