update neural networks typing and add new preprocessing (add actual normalization and correctly rename nrormalization to mimax)

This commit is contained in:
Jamie
2021-05-05 11:04:28 -04:00
parent 380848c380
commit 08398163e1
7 changed files with 114 additions and 40 deletions

View File

@@ -23,7 +23,7 @@ MultiLayer_Perceptron = [
{"Dense": {"units": 100, "activation": "relu"}},
{"Dense": {"units": 80, "activation": "relu"}},
{"Dense": {"units": 30, "activation": "relu"}},
{"Dense": {"activation": "linear"}},
{"Dense": {"activation": "relu"}},
]
Recurrent_Neural_Network = [
@@ -31,11 +31,11 @@ Recurrent_Neural_Network = [
{"SimpleRNN": {"units": 50, "activation": "linear", "return_sequences": True}},
{"Dropout": {"rate": 0.2}},
{"SimpleRNN": {"units": 21, "activation": "linear", "return_sequences": False}},
{"Dense": {"activation": "linear"}},
{"Dense": {"activation": "relu"}},
]
Long_Short_Term_Memory = [
{"LSTM": {"units": 25, "activation": "tanh", "return_sequences": True}},
{"LSTM": {"units": 15, "activation": "tanh", "return_sequences": False}},
{"Dense": {"activation": "linear"}},
{"Dense": {"activation": "relu"}},
]

View File

@@ -153,7 +153,7 @@ Facebook's Prophet:
## mlp <a name="mlp"></a>
```
usage: mlp [-d N_DAYS] [-i N_INPUTS] [-j N_JUMPS] [--epochs N_EPOCHS] [-p {normalization,standardization,none}]
usage: mlp [-d N_DAYS] [-i N_INPUTS] [-j N_JUMPS] [--epochs N_EPOCHS] [-p {minmax, normalization,standardization,none}]
[-o {adam,adagrad,adadelta,adamax,ftrl,nadam,optimizer,rmsprop,sgd}] [-l {mae,mape,mse,msle}] [-e S_END_DATE] [--loops N_LOOPS]
```
MulitLayer Perceptron:
@@ -161,7 +161,7 @@ MulitLayer Perceptron:
* -i : number of days to use for prediction. Default 40.
* -j : number of jumps in training data. Default 1.
* --epochs : number of training epochs. Default 200.
* -p : pre-processing data. Default normalization.
* -p : pre-processing data. Default minmax.
* -o : optimization technique. Default adam.
* -l : loss function. Default mae.
* -e : end date (format YYYY-MM-DD) of the stock - Backtesting. Default None.
@@ -183,7 +183,7 @@ MultiLayer_Perceptron \
{'Dense':
{'units':30, 'activation':'relu'} },
{'Dense':
{'activation':'linear'} }]
{'activation':'relu'} }]
```
![mlp](https://user-images.githubusercontent.com/25267873/108604944-d2025400-73a8-11eb-9ab6-52972160cd2a.png)
@@ -220,7 +220,7 @@ Recurrent_Neural_Network \
{'SimpleRNN':
{'units':21, 'activation':'linear', 'return_sequences':False} },
{'Dense':
{'activation':'linear'} }]
{'activation':'relu'} }]
```
![rnn](https://user-images.githubusercontent.com/25267873/108604940-d0d12700-73a8-11eb-837e-a5aa128942d9.png)
@@ -260,7 +260,7 @@ Long_Short_Term_Memory \
{'LSTM':
{'units':15, 'activation':'tanh', 'return_sequences':False} },
{'Dense':
{'activation':'linear'} }]
{'activation':'relu'} }]
```
![lstm](https://user-images.githubusercontent.com/25267873/108604943-d2025400-73a8-11eb-83c5-edb4a2121cba.png)

View File

@@ -2,7 +2,7 @@
__docformat__ = "numpy"
import argparse
from typing import List
from typing import List, Union
import datetime
import matplotlib.pyplot as plt
import numpy as np
@@ -49,7 +49,7 @@ def check_valid_seasonal(seasonal: str) -> str:
)
def exponential_smoothing(other_args:List[str], s_ticker:str, df_stock:pd.DataFrame):
def exponential_smoothing(other_args: List[str], s_ticker: str, df_stock: pd.DataFrame):
"""
Perform exponential smoothing forecasting
Parameters
@@ -409,12 +409,14 @@ def exponential_smoothing(other_args:List[str], s_ticker:str, df_stock:pd.DataFr
print("")
def get_exponential_smoothing_model(data:pd.Series, trend, seasonal, seasonal_periods):
def get_exponential_smoothing_model(
data: Union[pd.Series, np.ndarray], trend, seasonal, seasonal_periods
):
"""
Perform exponential smoothing
Parameters
----------
data: pd.Series
data: Union[pd.Series, np.ndarray]
Series of closing values
trend: str
Trend component. One of [N, A, Ad]

View File

@@ -1,4 +1,8 @@
""" Neural Networks View"""
__docformat__ = "numpy"
import argparse
from typing import List, Any
import datetime
import os
import traceback
@@ -8,7 +12,7 @@ import matplotlib.pyplot as plt
import pandas as pd
from pandas.plotting import register_matplotlib_converters
from TimeSeriesCrossValidation import splitTrain
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.preprocessing import MinMaxScaler, StandardScaler, Normalizer
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, SimpleRNN, Dense, Dropout
@@ -44,7 +48,9 @@ ORIGINAL_TF_XLA_FLAGS = os.environ.get("TF_XLA_FLAGS")
ORIGINAL_TF_FORCE_GPU_ALLOW_GROWTH = os.environ.get("TF_FORCE_GPU_ALLOW_GROWTH")
def build_neural_network_model(Recurrent_Neural_Network, n_inputs, n_days):
def build_neural_network_model(
Recurrent_Neural_Network: List[Any], n_inputs: int, n_days: int
):
model = Sequential()
for idx_layer, d_layer in enumerate(Recurrent_Neural_Network):
@@ -91,9 +97,24 @@ def build_neural_network_model(Recurrent_Neural_Network, n_inputs, n_days):
return model
def _parse_args(prog, description, l_args):
"""Create an argparser and parse l_args. Will print help if user requests it.
:return: ns_parser"""
def _parse_args(prog: str, description: str, other_args: List[str]):
"""
Create an argparser and parse other_args. Will print help if user requests it.
Parameters
----------
prog: str
Program for argparser
description: str
Description for argparser
other_args
Argparse arguments to pass
Returns
-------
ns_parser: argparse.Namespace
Parsed argument parser
"""
parser = argparse.ArgumentParser(
prog=prog,
description=description,
@@ -140,8 +161,8 @@ def _parse_args(prog, description, l_args):
"--pp",
action="store",
dest="s_preprocessing",
default="normalization",
choices=["normalization", "standardization", "none"],
default="minmax",
choices=["normalization", "standardization", "minmax", "none"],
help="pre-processing data.",
)
parser.add_argument(
@@ -233,7 +254,7 @@ def _parse_args(prog, description, l_args):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return None
@@ -276,10 +297,27 @@ def _restore_env():
restore("TF_FORCE_GPU_ALLOW_GROWTH", ORIGINAL_TF_FORCE_GPU_ALLOW_GROWTH)
def _setup_backtesting(df_stock, ns_parser):
"""Set up backtesting if enabled
:return: (df_stock, df_future), where df_future is None if s_end_date is not set.
:raises Exception: if configuration is invalid"""
def _setup_backtesting(df_stock: pd.DataFrame, ns_parser: argparse.Namespace):
"""
Setup backtesting when end data is specified
Parameters
----------
df_stock: pd.DataFrame
Stock data
ns_parser: argparse.Namespace
Parsed arguments
Returns
-------
df_stock: pd.DataFrame
Data before end date
df_future: pd.DataFrame
Data after end date
Raises
-------
Exception
If configuration is invalid
"""
df_future = None
if ns_parser.s_end_date:
if ns_parser.s_end_date < df_stock.index[0]:
@@ -319,11 +357,16 @@ def _preprocess_split(df_stock, ns_parser):
stock_train_data = scaler.fit_transform(
np.array(df_stock["5. adjusted close"].values.reshape(-1, 1))
)
elif ns_parser.s_preprocessing == "normalization":
elif ns_parser.s_preprocessing == "minmax":
scaler = MinMaxScaler()
stock_train_data = scaler.fit_transform(
np.array(df_stock["5. adjusted close"].values.reshape(-1, 1))
)
elif ns_parser.s_preprocessing == "normalization":
scaler = Normalizer()
stock_train_data = scaler.fit_transform(
np.array(df_stock["5. adjusted close"].values.reshape(-1, 1))
)
else: # No pre-processing
stock_train_data = np.array(df_stock["5. adjusted close"].values.reshape(-1, 1))
@@ -343,8 +386,10 @@ def _preprocess_split(df_stock, ns_parser):
def _rescale_data(df_stock, ns_parser, scaler, yhat, idx_loop):
"""Re-scale the data back and return the prediction dataframe."""
if (ns_parser.s_preprocessing == "standardization") or (
ns_parser.s_preprocessing == "normalization"
if (
(ns_parser.s_preprocessing == "standardization")
or (ns_parser.s_preprocessing == "normalization")
or (ns_parser.s_preprocessing == "minmax")
):
y_pred_test_t = scaler.inverse_transform(yhat.tolist())
else:
@@ -699,10 +744,25 @@ def _plot_and_print_results(
print("")
def mlp(l_args, s_ticker, df_stock):
def mlp(other_args: List[str], s_ticker: str, df_stock: pd.DataFrame):
"""
Train a multi-layer perceptron model
Parameters
----------
other_args: List[str]
Argparse Arguments
s_ticker: str
Ticker
df_stock: pd.DataFrame
Loaded stock dataframe
Returns
-------
"""
try:
ns_parser = _parse_args(
prog="mlp", description="""Multilayer Perceptron. """, l_args=l_args
prog="mlp", description="""Multilayer Perceptron. """, other_args=other_args
)
if not ns_parser:
return
@@ -768,10 +828,12 @@ def mlp(l_args, s_ticker, df_stock):
_restore_env()
def rnn(l_args, s_ticker, df_stock):
def rnn(other_args: List[str], s_ticker, df_stock):
try:
ns_parser = _parse_args(
prog="rnn", description="""Recurrent Neural Network. """, l_args=l_args
prog="rnn",
description="""Recurrent Neural Network. """,
other_args=other_args,
)
if not ns_parser:
return
@@ -839,10 +901,12 @@ def rnn(l_args, s_ticker, df_stock):
_restore_env()
def lstm(l_args, s_ticker, df_stock):
def lstm(other_args: List[str], s_ticker, df_stock):
try:
ns_parser = _parse_args(
prog="lstm", description="""Long-Short Term Memory. """, l_args=l_args
prog="lstm",
description="""Long-Short Term Memory. """,
other_args=other_args,
)
if not ns_parser:
return

View File

@@ -15,7 +15,7 @@ from gamestonk_terminal.prediction_techniques import (
arima_view,
ets_view,
knn,
neural_networks,
neural_networks_view,
regression,
sma,
)
@@ -159,15 +159,15 @@ class PredictionTechniquesController:
def call_mlp(self, other_args: List[str]):
"""Process mlp command"""
neural_networks.mlp(other_args, self.ticker, self.stock)
neural_networks_view.mlp(other_args, self.ticker, self.stock)
def call_rnn(self, other_args: List[str]):
"""Process rnn command"""
neural_networks.rnn(other_args, self.ticker, self.stock)
neural_networks_view.rnn(other_args, self.ticker, self.stock)
def call_lstm(self, other_args: List[str]):
"""Process lstm command"""
neural_networks.lstm(other_args, self.ticker, self.stock)
neural_networks_view.lstm(other_args, self.ticker, self.stock)
if gtff.ENABLE_FBPROPHET:

View File

@@ -1,3 +1,6 @@
""" Prediction helper functions """
__docformat__ = "numpy"
import numpy as np
import pandas as pd
from colorama import Fore, Style
@@ -11,6 +14,7 @@ from gamestonk_terminal import feature_flags as gtff
def price_prediction_color(val: float, last_val: float) -> str:
"""Set prediction to be a colored string"""
if float(val) > last_val:
color = Fore.GREEN
else:
@@ -19,6 +23,7 @@ def price_prediction_color(val: float, last_val: float) -> str:
def print_pretty_prediction(df_pred: pd.DataFrame, last_price: float):
"""Print predictions"""
if gtff.USE_COLOR:
print(f"Actual price: {Fore.YELLOW}{last_price:.2f} ${Style.RESET_ALL}\n")
print("Prediction:")
@@ -44,12 +49,14 @@ def print_pretty_prediction_nn(df_pred: pd.DataFrame, last_price: float):
print(df_pred.to_string())
def mean_absolute_percentage_error(y_true, y_pred):
def mean_absolute_percentage_error(y_true: np.ndarray, y_pred: np.ndarray) -> np.number:
"""Calculate mean absolute percent error"""
y_true, y_pred = np.array(y_true), np.array(y_pred)
return np.mean(np.abs((y_true - y_pred) / y_true)) * 100
def print_prediction_kpis(real, pred):
def print_prediction_kpis(real: np.ndarray, pred: np.ndarray):
"""Print prediction statistics"""
print("KPIs")
print(f"MAPE: {mean_absolute_percentage_error(real, pred):.3f} %")
print(f"R2: {r2_score(real, pred):.3f}")
@@ -59,6 +66,7 @@ def print_prediction_kpis(real, pred):
def price_prediction_backtesting_color(val: list) -> str:
"""Add color to backtest data"""
err_pct = 100 * (val[0] - val[1]) / val[1]
if val[0] > val[1]:
s_err_pct = f" {Fore.GREEN} +{err_pct:.2f} %"

View File

@@ -2,7 +2,7 @@
import unittest
try:
from gamestonk_terminal.prediction_techniques.neural_networks import mlp
from gamestonk_terminal.prediction_techniques.neural_networks_view import mlp
except ModuleNotFoundError as e:
print("One of the optional packages seems to be missing")
print(e)