Essayer d'utiliser TensorFlow pour prédire les données de séries chronologiques financières


10

Je suis nouveau sur ML et TensorFlow (j'ai commencé il y a quelques heures) et j'essaie de l'utiliser pour prédire les prochains points de données d'une série chronologique. Je prends ma contribution et je fais cela avec:

/----------- x ------------\
.-------------------------------.
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
'-------------------------------'
     \----------- y ------------/

Ce que je pensais faire, c'était utiliser x comme données d'entrée et y comme sortie souhaitée pour cette entrée, de sorte que, étant donné 0-6, je pouvais obtenir 1-7 (le 7 en particulier). Cependant, lorsque j'exécute mon graphique avec x comme entrée, ce que j'obtiens est une prédiction qui ressemble plus à x qu'à y .

Voici le code (basé sur ce post et ce post ):

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plot
import pandas as pd
import csv

def load_data_points(filename):
    print("Opening CSV file")
    with open(filename) as csvfile:
        print("Creating CSV reader")
        reader = csv.reader(csvfile)
        print("Reading CSV")
        return [[[float(p)] for p in row] for row in reader]

flatten = lambda l: [item for sublist in l for item in sublist]

data_points = load_data_points('dataset.csv')

print("Loaded")

prediction_size = 10
num_test_rows = 1
num_data_rows = len(data_points) - num_test_rows
row_size = len(data_points[0]) - prediction_size

# Training data
data_rows = data_points[:-num_test_rows]
x_data_points = np.array([row[:-prediction_size] for row in data_rows]).reshape([-1, row_size, 1])
y_data_points = np.array([row[prediction_size:] for row in data_rows]).reshape([-1, row_size, 1])

# Test data
test_rows = data_points[-num_test_rows:]
x_test_points = np.array([[data_points[0][:-prediction_size]]]).reshape([-1, row_size, 1])
y_test_points = np.array([[data_points[0][prediction_size:]]]).reshape([-1, row_size, 1])

tf.reset_default_graph()

num_hidden = 100

x = tf.placeholder(tf.float32, [None, row_size, 1])
y = tf.placeholder(tf.float32, [None, row_size, 1])

basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=num_hidden, activation=tf.nn.relu)
rnn_outputs, _ = tf.nn.dynamic_rnn(basic_cell, x, dtype=tf.float32)

learning_rate = 0.001

stacked_rnn_outputs = tf.reshape(rnn_outputs, [-1, num_hidden])
stacked_outputs = tf.layers.dense(stacked_rnn_outputs, 1)
outputs = tf.reshape(stacked_outputs, [-1, row_size, 1])

loss = tf.reduce_sum(tf.square(outputs - y))
optimizer = tf.train.AdamOptimizer(learning_rate)
training_op = optimizer.minimize(loss)

init = tf.global_variables_initializer()

iterations = 1000

with tf.Session() as sess:
    init.run()
    for ep in range(iterations):
        sess.run(training_op, feed_dict={x: x_data_points, y: y_data_points})
        if ep % 100 == 0:
            mse = loss.eval(feed_dict={x: x_data_points, y: y_data_points})
            print(ep, "\tMSE:", mse)

    y_pred = sess.run(stacked_outputs, feed_dict={x: x_test_points})

    plot.rcParams["figure.figsize"] = (20, 10)

    plot.title("Actual vs Predicted")
    plot.plot(pd.Series(np.ravel(x_test_points)), 'g:', markersize=2, label="X")
    plot.plot(pd.Series(np.ravel(y_test_points)), 'b--', markersize=2, label="Y")
    plot.plot(pd.Series(np.ravel(y_pred)), 'r-', markersize=2, label="Predicted")
    plot.legend(loc='upper left')
    plot.xlabel("Time periods")
    plot.tick_params(
        axis='y',
        which='both',
        left='off',
        right='off',
        labelleft='off')
    plot.show()

Le résultat indiqué dans le graphique ci-dessous est une prédiction qui suit x , plutôt que d'être décalée vers la gauche (et en incluant les points prédits à droite) comme il se doit pour ressembler à y . De toute évidence, le souhait est que la ligne rouge soit aussi proche que possible de la ligne bleue.

graphique

Je n'ai aucune idée de ce que je fais avec tout cela, alors s'il vous plaît ELI5.

Oh, aussi, mes points de données sont des nombres assez petits (ordre de 0,0001). Si je ne les multiplie pas par, disons, 1000000, les résultats sont si petits que la ligne rouge est presque plate au bas du graphique. Pourquoi? Je suppose que c'est à cause de la quadrature de la fonction fitness. Les données doivent-elles être normalisées avant utilisation, et si oui, à quoi? 0-1? Si j'utilise:

normalized_points = [(p - min_point) / (max_point - min_point) for p in data_points]

ma prédiction fluctue plus sauvagement au fur et à mesure qu'elle progresse: fluctuant

Edit: je suis stupide et je ne lui donne qu'un exemple pour apprendre, pas 500, n'est-ce pas? Je devrais donc lui donner plusieurs échantillons de 500 points, non?


J'ai le même problème - à savoir que la sortie du RNN suit l'entrée (X) et non la cible (Y). Curieusement, lorsque l'entrée du même RNN est une simple série sinusoïdale, il apprend correctement, c'est-à-dire prédit le Y.
Ryszard Cetnarski

Veuillez partager votre fichier dataset.csv
Ashwin Tomar

Réponses:


2

Ok, allons partie par partie. Il y a pas mal de parties ici où vous ne tenez pas compte du biais de votre réseau.

Choisir vos entrées et sorties

Si le vecteur 0-6 est déterminé, il n'est vraiment pas nécessaire de sortir 1-7. Le 1-6 est déjà connu et l'ajout de sorties supplémentaires ne fera qu'ajouter de la complexité à votre modèle. Sauf si vous avez des quantités importantes de données, vous souhaitez garder votre modèle aussi simple que possible afin d'obtenir de bonnes performances. Ainsi, je produirais un neurone simple avec une valeur continue. Vous pouvez utiliser RMSE comme fonction de perte avec une sortie de régression de votre réseau neuronal.

En outre, vous devez compléter les échantillons que vous placez dans votre espace de saisie avec des informations supplémentaires qui, selon vous, pourraient contenir des informations sur la ligne de tendance. Par exemple, si j'avais 2 produits différents, le bitcoin et l'or, et que leur vecteur d'entrée était le même, je pourrais m'attendre à ce que l'or ait très peu de fluctuations mais que le bitcoin ait des fluctuations très élevées.

Vos fonctionnalités d'entrée sur votre réseau contiennent toutes les informations dont votre réseau tirera parti. Ainsi, vous voulez vous assurer que vous fournissez suffisamment d'informations pour avoir une prédiction significative.

L'apprentissage en profondeur est gourmand en données

Vous aurez besoin d'environ 100 000+ instances. Chaque instance est un ensemble de fonctionnalités. Celles-ci doivent être dessinées indépendamment et telles qu'elles soient distribuées de manière identique. En d'autres termes, vous souhaitez obtenir plusieurs lignes de tendance à partir d'une source de données variée avec laquelle vous souhaitez utiliser votre réseau, puis vous tirerez au hasard 0-6 points, c'est-à-dire vos fonctionnalités, et 7 qui sera votre étiquette.

Considérez la distribution des données que vous essayez d'apprendre. Si vous souhaitez que votre réseau classe les chats / chiens, vous devez fournir un large éventail de chats et de chiens d'aspect différent afin que le réseau puisse identifier la variance qui existe dans ces deux classes. Si vous limitez trop la source de données, elle aura un biais élevé et ne généralisera pas de nouvelles données que vous y alimenterez ultérieurement.


Essayez ces choses et faites-nous savoir ce qui se passe.


2

Peut-être que la prédiction étant la même que l'entrée indique que votre réseau est sous-formé. Ce qu'on appelle le modèle de persistance pour la prédiction de séries chronologiques est souvent utilisé comme référence pour d'autres modèles. Le modèle de persistance utilise la dernière observation comme prédiction. Il est simple et donne souvent une précision raisonnable. Je suppose que votre réseau commence par apprendre le modèle de persistance, et seulement si vous le formez davantage et qu'il est possible de faire un meilleur modèle, il l'apprendra - mais cela nécessite beaucoup de formation.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.