Skip to content

Commit

Permalink
Safe to demo (and awesome B)) Merge pull request #78 from ShaynAli/dev
Browse files Browse the repository at this point in the history
The awesome update B)
  • Loading branch information
ShaynAli authored Mar 22, 2019
2 parents a3696e4 + 7349c6f commit 3d2dde6
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 46 deletions.
5 changes: 2 additions & 3 deletions src/activities/stock_prediction/stock_arena.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from arena.arena import MachineLearningArena
from activities.stock_prediction.stock_prediction import FrankfurtStockPrediction
from activities.stock_prediction.stock_prediction_models import RandomRangePredictor
from activities.stock_prediction.stock_prediction_models import *
import pprint

if __name__ == '__main__':

arena = MachineLearningArena(model_pool=[RandomRangePredictor], activity=FrankfurtStockPrediction)
arena = MachineLearningArena(model_pool=[ShallowNeuralNetworkPredictor], activity=FrankfurtStockPrediction)
printer = pprint.PrettyPrinter()
for _ in range(10):
arena.auto_compete()
Expand Down
19 changes: 12 additions & 7 deletions src/activities/stock_prediction/stock_prediction.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from activities.activities import MachineLearningActivity
import quandl
from _datetime import date, timedelta
import pdb
import numpy as np
from datetime import date
from dateutil.relativedelta import relativedelta
Expand Down Expand Up @@ -196,6 +194,8 @@ class FrankfurtStockPrediction(MachineLearningActivity):

default_guess_tickers = ['CON_X']

n_days = 20

def __init__(self, tickers=default_tickers, guess_tickers=default_guess_tickers):
quandl.ApiConfig.api_key = 'z3rsXS2rz9ZXCe76xozE'
self.code = 'FSE'
Expand All @@ -204,11 +204,11 @@ def __init__(self, tickers=default_tickers, guess_tickers=default_guess_tickers)

@property
def x_shape(self):
return len(self.tickers), None
return FrankfurtStockPrediction.n_days, len(self.tickers)

@property
def y_shape(self):
return len(self.guess_tickers), None
return FrankfurtStockPrediction.n_days, len(self.guess_tickers)

def next_data(self):
from random import choice
Expand Down Expand Up @@ -237,13 +237,18 @@ def next_data(self):
except ValueError:
return self.next_data()

return tickers, guess_tickers
x = np.transpose(tickers)[:FrankfurtStockPrediction.n_days, :]
y = np.transpose(guess_tickers)[:FrankfurtStockPrediction.n_days, :]

return x, y

def get_ticker(self, ticker, start_date, end_date, field='Open'):
return quandl.get(f'{self.code}/{ticker}', returns='numpy', start_date=start_date, end_date=end_date)[field]


if __name__ == '__main__':
activity = FrankfurtStockPrediction()
data = [activity.next_data() for _ in range(3)]
pdb.set_trace()
while True:
x, y = activity.next_data()
from pdb import set_trace
set_trace()
89 changes: 88 additions & 1 deletion src/activities/stock_prediction/stock_prediction_models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from activities.stock_prediction.stock_prediction import FrankfurtStockPrediction
import numpy as np
from keras import Sequential
from keras.layers import Dense, Activation
from random import randint


class RandomRangePredictor(FrankfurtStockPrediction.Model):
Expand All @@ -18,4 +21,88 @@ def predict(self, x):

@staticmethod
def description():
return '''Predicts within a range range, which is updated base on y data.'''
return '''Predicts within a random range. The max and min of the range are updated based on y data.'''


class MeanPredictor(FrankfurtStockPrediction.Model):

def __init__(self, activity):
super().__init__(activity)

def train(self, x, y):
pass

def predict(self, x):
return np.full(shape=(self.y_shape[0], x.shape[1]), fill_value=np.mean(x))

@staticmethod
def description():
return '''Predicts that every stock will have the same mean price overall.'''


class MeanRowPredictor(FrankfurtStockPrediction.Model):

def __init__(self, activity):
super().__init__(activity)

def train(self, x, y):
pass

def predict(self, x):
n_y_cols = self.y_shape[1]
prediction = np.empty(shape=self.y_shape)
for row_i in range(x.shape[0]):
row_mean = np.mean(x[row_i, :])
prediction[:, row_i] = [row_mean] * n_y_cols
return prediction

@staticmethod
def description():
return '''Predicts that every stock will have the same mean price at every time interval.'''


class ShallowNeuralNetworkPredictor(FrankfurtStockPrediction.Model):

def __init__(self, activity):
super().__init__(activity)
self.neural_network = Sequential([
Dense(32, input_shape=(self.x_shape[1],)),
Dense(self.y_shape[1])
])
self.neural_network.compile(
optimizer='nadam',
loss='mse'
)

def train(self, x, y):
self.neural_network.fit(x=x, y=y)

def predict(self, x):
return self.neural_network.predict(x)

@staticmethod
def description():
return '''Uses a shallow, wide neural network.'''


class RandomDepthNeuralNetworkPredictor(FrankfurtStockPrediction.Model):

def __init__(self, activity):
super().__init__(activity)
self.neural_network = Sequential([Dense(8, input_shape=(self.x_shape[1],))] +
[Dense(8) for _ in range(randint(0, 8))] +
[Dense(self.y_shape[1])])
self.neural_network.compile(
optimizer='nadam',
loss='mse'
)

def train(self, x, y):
self.neural_network.fit(x=x, y=y)

def predict(self, x):
return self.neural_network.predict(x)

@staticmethod
def description():
return '''Creates a neural network of depth from 2-10.'''
15 changes: 8 additions & 7 deletions src/arena/arena.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
""" arena.py - Where ML and AI bots go to face off """
import evaluation
from random import choice

from pandas import isnull

class MachineLearningArena:

def __init__(self, model_pool, activity, generation_size=10):
def __init__(self, model_pool, activity, score_function=evaluation.DEFAULT_SCORE_FUNCTION, generation_size=10):
self.model_pool = model_pool
self.activity = activity()
self.score_function = score_function
self.models = list(self.new_models(n_models=generation_size))
self.score_history = []

Expand All @@ -17,8 +17,8 @@ def new_model(self):
def new_models(self, n_models):
return (self.new_model() for _ in range(n_models))

def compete(self, x, y, live_ratio=0.5, score_function=evaluation.DEFAULT_SCORE_FUNCTION):
model_score = {m: evaluation.score(m, x, y, score_function=score_function) for m in self.models}
def compete(self, x, y, live_ratio=0.5):
model_score = {m: evaluation.score(m, x, y, score_function=self.score_function) for m in self.models}
self.score_history.append(model_score)
score_ranking = sorted(model_score.keys(), key=lambda model: model_score[model], reverse=True)
from utilities import partition_indices
Expand All @@ -27,5 +27,6 @@ def compete(self, x, y, live_ratio=0.5, score_function=evaluation.DEFAULT_SCORE_

def auto_compete(self, live_ratio=0.5):
x, y = self.activity.next_data()
self.compete(x=x, y=y, live_ratio=live_ratio, score_function=evaluation.DEFAULT_SCORE_FUNCTION)

while isnull(x).any() or isnull(y).any():
x, y = self.activity.next_data()
self.compete(x=x, y=y, live_ratio=live_ratio)
17 changes: 14 additions & 3 deletions src/data_utils/visualization.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import bokeh
from bokeh.plotting import figure, output_file, show
import pdb
from random import choice

plot_dimensions = (1225, 600)

colors = {}


def random_color(k):
if k in colors:
return colors[k]
digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
new_color = f'#{choice(digits)}{choice(digits)}{choice(digits)}{choice(digits)}{choice(digits)}{choice(digits)}'
colors[k] = new_color
return new_color


def plot_line(data_class, x_label, y_label):
# Use hover tool
Expand Down Expand Up @@ -60,19 +71,19 @@ def multi_line(data, x_label="X", y_label="Y"):
for k, v in data.items():
generations = [e[0] for e in v]
scores = [e[1] for e in v]
p.line(generations, scores, line_width=2, legend=k[:8])
p.line(generations, scores, line_width=2, legend=k, line_color=random_color(k))
p.legend.click_policy = "hide"

p.plot_width, p.plot_height = plot_dimensions
p.toolbar.logo = "grey"
p.toolbar.autohide = True
p.legend.location = "top_left"
p.background_fill_color = "#dddddd"
p.hover.tooltips = [
(x_label, "@x"),
(y_label, "@y")
]

# Return the plot for display purposes
return p


Expand Down
2 changes: 1 addition & 1 deletion src/evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def complement_mean_pct_error(predicted, actual):

# region Model scoring

DEFAULT_SCORE_FUNCTION = inv_norm_err
DEFAULT_SCORE_FUNCTION = complement_mean_pct_error
DEFAULT_ERROR_FUNCTION = rms_error
DEFAULT_TRACK_FUNCTION = rms_error

Expand Down
9 changes: 6 additions & 3 deletions src/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
numpy
numpy==1.16
flask
bokeh
quandl
scikit-learn
flask
keras
tensorflow
quandl
pandas
Binary file added src/server/assets/favicon.ico
Binary file not shown.
Binary file modified src/server/assets/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/server/assets/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ table tr:nth-child(even) {
background: #23283C;
}

#leader-board table td {
font-size: 90%;
}

option {
font-size: 120%;
}

.preview {
background-color: #23283C;
font-family: 'Ubuntu Mono', monospace;
Expand Down
29 changes: 16 additions & 13 deletions src/server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import data_utils.visualization as vs
import os
from uuid import uuid4
from activities.stock_prediction.stock_prediction import FrankfurtStockPrediction
from activities.stock_prediction.stock_prediction_models import RandomRangePredictor
from activities.stock_prediction.stock_prediction import *
from activities.stock_prediction.stock_prediction_models import *
from arena.arena import MachineLearningArena
from collections import defaultdict
from itertools import count, chain
Expand All @@ -18,18 +18,21 @@
}

activity_descriptions = {
FrankfurtStockPrediction: '''
Use the opening price of a few stocks from the Frankfurt Exchange to anticipate the price of a few other
stocks.\n
'''
FrankfurtStockPrediction: "Use the opening price of a few stocks from the Frankfurt Exchange to anticipate the "
"price of a few other stocks.\n"
}

activities_to_models = {
FrankfurtStockPrediction: [RandomRangePredictor]
FrankfurtStockPrediction: [RandomRangePredictor, MeanPredictor, MeanRowPredictor, ShallowNeuralNetworkPredictor,
RandomDepthNeuralNetworkPredictor]
}

model_names = {
RandomRangePredictor: 'Random Range Predictor'
RandomRangePredictor: 'Random Range Model',
MeanPredictor: 'Mean Model',
MeanRowPredictor: 'Mean Row Model',
ShallowNeuralNetworkPredictor: 'Shallow Neural Network',
RandomDepthNeuralNetworkPredictor: 'Random Depth Neural Network'
}

# endregion
Expand Down Expand Up @@ -104,7 +107,7 @@ def new_arena():
activity_id = request.json['activity']
activity = id_to_activity[activity_id]

arena = MachineLearningArena(model_pool=models, activity=activity)
arena = MachineLearningArena(model_pool=models, activity=activity, generation_size=20)

arena_id = new_uuid()
id_to_arena[arena_id] = arena
Expand Down Expand Up @@ -176,16 +179,16 @@ def arena_generation_plot_update(arena_id, start, end):
start = 0
if end == 'end' or end == 'END':
end = len(arena.score_history)
models_scores = defaultdict(list)
plot_dict = defaultdict(list)
for generation_no, generation in zip(count(start), arena.score_history[start:end]):
for model, score in generation.items():
model_id = model_instance_id[model]
models_scores[model_id].append((generation_no, score))
plot_dict[f'{model.__class__.__name__}-{model_id[:8]}'].append((generation_no, score))

if not models_scores.keys():
if not plot_dict.keys():
return render_template('plot.html', **elements)

new_plot = vs.multi_line(models_scores, "Generation", "Score")
new_plot = vs.multi_line(plot_dict, "Generation", "Score")

new_script, new_view = components(new_plot)

Expand Down
11 changes: 5 additions & 6 deletions src/server/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<style> {{style|safe}} </style>

<title>Aipen</title>
<link rel="icon" href="https://i.imgur.com/wLQLQpC.png">
</head>

<body onload="init()">
Expand All @@ -24,15 +25,14 @@
<h1>ACTIVITIES</h1>
<div>
<div id="activities">
<select id="activity-selection" size="10" onchange="activity_select()">
<option value="Test" id="activity-1"></option>
<select id="activity-selection" size="16" onchange="activity_select()">
<option id="activity-1"></option>
<option>Battleship</option>
<option>Weather Forecast</option>
<option>Sports Prediction</option>
<option>Mario</option>
<option>Racing</option>
<option>File Carving (NYI)</option>
<option>..................................................................</option>
<option>File Carving</option>
<option>More Coming Soon!</option>

</select>
Expand Down Expand Up @@ -83,8 +83,7 @@ <h1>STATISTICS</h1>
<button id="start-button" onclick="start()">&#9658 Start</button>
<button id="stop-button" onclick="stop()" disabled>&#9724 Stop</button>
<button id="get-generation" onclick="get_generation()" disabled>Get Generation</button>
<input id="generation-entry" type="text" onfocus="this.value=''" value="Enter the generation number">
<br>
<input id="generation-entry" type="text" onfocus="this.value=''" value="Enter generation number">
<br>
<br>
<table id="leader-table" hidden>
Expand Down
4 changes: 2 additions & 2 deletions src/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
requirements = requirements_file.read().splitlines()

setup(
name='Aipen',
version='0.4.3',
name='aipen',
version='0.5.2',
url='https://github.com/ShaynAli/Aipen',
author='Shayaan Syed Ali',
author_email='[email protected]',
Expand Down

0 comments on commit 3d2dde6

Please sign in to comment.