質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.53%

  • Python

    7884questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

kerasを用いたRNNについてpredictがうまく機能しない

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 324

yohehe

score 19

kerasを用いたRNNのプログラミングを勉強しております。

RNNを用いて乗客数のグラフの予測をしているサイトがありましたので、それをkerasで行なってみたいと思って以下のプログラムを作ってみております。predictが全く予測していなく、困っております。
以下RNN学習のために試しておりますプログラムです。

df = pd.read_csv('international-airline-passengers.csv',skipfooter=3)

data=np.array(data)

sabun_data=[]
for i in range(len(data)-1):
    temp_sabun=data[i+1]-data[i]
    sabun_data.append(temp_sabun)
sabun_data=np.array(sabun_data)
data=sabun_data
#data.shapeは(143)です。

#sinwaveを予測するプログラミングを参考にしてます。

#5個ずつのデータサイズごとにX,yを作成する。
X_data=[]
target=[]

manabu_len=5
for i in range(0,len(data)-manabu_len):
    X_data.append(data[i:i+manabu_len])
    target.append(data[i+manabu_len])

from sklearn.model_selection import train_test_split
X=np.array(X_data).reshape(len(X_data),manabu_len,1)
y=np.array(target).reshape(len(X_data),1)
(train_X,test_X,train_y,test_y)=train_test_split(X,y,test_size=0.2)

from keras.layers import LSTM,SimpleRNN
from keras.models import Sequential
from keras.optimizers import Adam
from keras.layers import Dense,Activation

n_in=1
n_hidden=20
n_out=1
model=Sequential()
model.add(LSTM(n_hidden,input_shape=(manabu_len,n_in),kernel_initializer="random_normal"))
model.add(Dense(n_out))
model.add(Activation("linear"))
model.compile(loss="mean_squared_error",optimizer="Adam")
model.fit(X,y,batch_size=20,epochs=100,validation_data=(test_X,test_y))


#modelを参考にして、predictをグラフ化してみる。

#予測したデータをpredictに格納してグラフにしてみる。 
in_=X[:1]
predicted=[] 
for i in range(len(data)-manabu_len):
    out_=model.predict(in_)
    in_ = np.vstack( (in_.reshape(manabu_len,n_in)[1:], out_)).reshape(1, manabu_len, n_in)
    predicted.append(out_.reshape(-1))
plt.plot(data, label="original")
plt.plot(predicted, label="predicted")
plt.legend()
plt.show()
コード

イメージ説明

他のサイトでは、同じdata数でtensorflow,tflearnでグラフに近似したpredictを出せているみたいなのですが、自分のプログラミングの問題がどこにあるのかわからないでおります。SimpleRNNなどもためしてみましたが同じ状況でした。
RNNについて初心者ですが、アドバイスをいただけますと幸いです。よろしくお願いいたします。

==========================================================
追記

アドバイスをいただきまして差分データから特徴量と教師データにすることで予測できるようになってきました.
ありがとうございます。

差分データ予想

イメージ説明

差分データから得られた元データと予測の比較
イメージ説明
ただ、手法によるためか精度には課題が多いようです。進むにつれてかなりずれていきました。
精度を上げられるようにするにはどうすべきか、いろいろ調べてみます。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • mkgrei

    2018/07/13 20:23 編集

    他のサイトとは?同じデータを使っているんですか?

    キャンセル

  • yohehe

    2018/07/13 20:48

    ボストンの乗客数というデータを使用させていただき、RNNについて勉強しております。https://datamarket.com/data/set/22u3/international-airline-passengers-monthly-totals-in-thousands-jan-49-dec-60#!ds=22u3&display=line

    キャンセル

  • yohehe

    2018/07/13 20:56

    追記ですが、yを設定する際に使用しているinput_lenの数値を大きくしても同じようになってしまっています。

    キャンセル

回答 2

+2

解決済みですので、参考まで。
時系列データをモデル化する際、以下の考慮について事前分析する必要があります。
1.定常性の有無とその調整
定常性とはおおまかにいうと、一定の数値を中心に一定範囲内で安定的に振幅している状態のことをいいます。この条件を満たしていないと時系列モデルによる予測値がズレやすくなります。今回の場合、時間が進むにつれて振幅幅が大きいのでこれをうまく調整する必要があります。推測でしかありませんが、np.logを適用して振幅が小さくなるようにしたほうがいいかと思います。
2.モデルの構造
通常は自己相関(つまり、過去の値に係数をかけるイメージ)でうまくいくのですが、トレンドが含まれているようなデータの場合は、過去のデータに加算するようなモデルのほうがうまくいきます。mkgreiさんの指摘はこのケースで、本データの場合、右肩上がりというトレンドを含んでいるようなので階差を取るとうまくいきます。ただし、階差がひとつでいいのかそれ以上なのかはケースバイケースなので、事前分析をした上でどの程度の階差を取るべきかを検討したほうがいいでしょう。
3.季節周期性の有無
本データの内容次第のところがありますが、月単位や日単位の場合、観光シーズンや週末は値が大きくなるといった季節周期性があるケースも考慮するべきかと思います。必要に応じて月や曜日などをダミー変数化してモデルに組み込むといいでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/14 12:22

    R.shigemori様、アドバイス感謝致します。
    階差である差分をもとに学習させてみたのですが、 教えていただきましたlogなどで振幅を小さくするという手法なども試してみたいと思います。
    モデルの構造を事前に分析する際には、事前の分析が重要だとういうことが今回学べました。時系列分析について調べてみると、自己相関係数の推定などさまざまな手法があるのですね。
    ダミー変数などでデータを増やすような手法については今のところやり方がわからないため、教えていただいた方法を一つずつ勉強していこうと思います。
    ありがとうございます。

    キャンセル

checkベストアンサー

+1

再現できません。

そもそも質問内のコードは正しく動くはずのないものです。
まず、データの形に問題があります。→エラーになる
そして、推定値の変数名が間違っています。→エラーになる

書き写したのですか?


とりあえず動くものを載せておくので参考にしてみてください。

import pandas as pd
import numpy as np
import keras
from keras.models import Sequential
from keras.layers import LSTM, Dense, Activation, Dropout
from keras.optimizers import Adagrad
import matplotlib.pyplot as plt
%matplotlib inline

data = pd.read_csv('international-airline-passengers.csv', skipfooter=3)
data = data.values[:, -1]
data = data[1:] - data[:-1]

inputdata = []
target = []
input_len = 5

for i in range(0, len(data)-input_len):
    inputdata.append(data[i:i+input_len])
    target.append(data[i+input_len])

from sklearn.model_selection import train_test_split

X = np.array(inputdata).reshape(-1, input_len, 1)
y = np.array(target).reshape(-1, 1)
(train_X, test_X, train_y, test_y) = train_test_split(X, y, test_size=0.2, shuffle=False)

n_in = 1
n_hidden = 50
n_out = 1
model = Sequential()
model.add(LSTM(n_hidden, input_shape=(input_len,n_in)))
model.add(Dense(100, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(5, activation='relu'))
model.add(Dense(100, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(n_out, activation='linear'))
opt = Adagrad()
model.compile(loss="mean_squared_error",optimizer=opt)

model.fit(train_X, train_y, batch_size=len(X)//10, epochs=50, validation_data=(test_X, test_y))

py = model.predict(train_X)
py_ = model.predict(test_X)

px = np.arange(predicted.shape[0])

fig, ax = plt.subplots(dpi=200)
ax.plot(y, label="original")
ax.plot(px[:len(py)], py, label="predicted_train", color='orange')
ax.plot(px[len(py):], py_, label="predicted_test", color='red')
plt.legend()
plt.grid()
plt.show()

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/13 21:28

    すみません。csvで読み込んで
    df = pd.read_csv('international-airline-passengers.csv',skipfooter=3)
    data=df['International airline passengers: monthly totals in thousands. Jan 49 ? Dec 60']
    で読み込んで、動作はしているのですが。
    epochs=1000以上にしたとしても損失係数が一定から低下しないため、手法自体がこれではいけないかもしれません。

    キャンセル

  • 2018/07/13 21:39

    X=np.array(inputdata).reshape(len(data),input_len,1)
    これ、エラーになりませんか?

    ...predicted.append(out_.reshape(-1))
    .
    .
    .
    plt.plot(predict, label="predicted")
    このプロットしているものはなんですか?

    もしjupyterなどを使用しているのであれば、過去の履歴から持ってきている可能性があるので、
    何を見ているのか定かではありませんよ。

    正しくコードを書き換えても今のままだとうまく学習できませんが、
    そもそも今はそれ以前の状態です。

    キャンセル

  • 2018/07/13 21:52 編集

    プログラム修正しました。変数が変わっていることは何度か試しているだけで、特に意味ありません。jupiternotebook上で動作しています。
    model.fitで学習させて、
    Xのデータ1つずつをpredictに入れて、predictで分類器が予想したデータをout_としてグラフに起こせていると思ったのですが,,,reshape(-1)は(141,1,1)の3次元になっているため、次元数を落とすために使用しています。
    そもそも全てがおかしいかもしれません。最初から検討してみます。。。

    キャンセル

  • 2018/07/13 21:55

    mkgrei様ありがとうございます。

    キャンセル

  • 2018/07/13 22:01

    ポイントは元のデータの差分を最初に取ることです。

    右肩上がりになってしまうので。

    キャンセル

  • 2018/07/13 22:06

    勉強になります。RNNなどではそのままのデータから学習させる方法は望ましくないのですね。元データの差分を分類器に学習させられるようにプログラムを大幅に変更してみます。

    キャンセル

  • 2018/07/15 02:11

    追記についてですが、
    この2枚めのグラフはどのようなものをプロットしているのでしょうか?
    もし差分データの予測を累積して処理しているのであれば、場合によっては問題設定に難があります。

    時系列データというのは未来を知ることはできませんが、過去を知ることができます。
    ですので、予測する際にも、過去の実データを使って予測に使っていて、過去の予測データを予測に使っていません。
    ですので、純粋な累計データではなく、1ステップ前の値と予測した差分値を算出する必要があります。
    任意の時点ではそれ以前の正解値を知ることができるという前提が今のモデルにはあります。

    ただ、上記を加味しても、今回のデータでは振幅が時間の経過に伴って増加しますので、振幅の増加率に対するモデルを追加するか、時間も特徴量として取り入れると良いかもしれません。
    この点に関してはR.Shigemoriさんの回答を参考にされるとよいかと。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.53%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python

    7884questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。