import numpy as np
from keras.models import Sequential
from keras.layers import Dense

np.random.seed(42)
fFloat  = open("BostonFeature.csv","r")
X = np.loadtxt(fFloat, delimiter=","); fFloat.close()
fFloat  = open("BostonTarget.csv","r")
Y = np.loadtxt(fFloat, delimiter=","); fFloat.close()
yMin = Y.min(axis=0); yMax = Y.max(axis=0) 
Y = (Y - yMin) / (yMax - yMin) 
TrainSet     = np.random.choice(X.shape[0],int(X.shape[0]*0.80), replace=False)
XTrain       = X[TrainSet,:] 
YTrain       = Y[TrainSet]
TestSet      = np.delete(np.arange(0, len(Y) ), TrainSet) 
XTest        = X[TestSet,:]
YTest        = Y[TestSet]

myANN = Sequential()
myANN.add(Dense(10,input_dim=13,kernel_initializer='normal',activation='relu',use_bias=False))
myANN.add(Dense(10,kernel_initializer='random_uniform',activation='relu',use_bias=False))
myANN.add(Dense(1,kernel_initializer='normal',activation='linear',use_bias=False))
myANN.compile(loss='mean_squared_error', optimizer='adam')
history = myANN.fit(XTrain,YTrain, epochs=1000, verbose=False)

yp = myANN.predict(XTest)
yp = yp.reshape(yp.shape[0])
errorT = (yMax - yMin)*(yp - YTest)
print(np.mean(np.abs(errorT)))

myANN = Sequential()
myANN.add(Dense(10,input_dim=13,kernel_initializer='normal',activation='relu',use_bias=False))
myANN.add(Dense(10,kernel_initializer='random_uniform',activation='relu',use_bias=False))
myANN.add(Dense(1,kernel_initializer='normal',activation='linear',use_bias=False))
myANN.compile(loss='mean_squared_error', optimizer='adam')

def divValTrainSet(X,Y):
    ValSet    = np.random.choice(X.shape[0],int(X.shape[0]*0.25),replace=False)
    TrainSet  = np.delete(np.arange(0, Y.shape[0] ), ValSet) 
    XVal     = X[ValSet,:]
    YVal     = Y[ValSet]
    X        = X[TrainSet,:]
    Y        = Y[TrainSet]
    return (XVal, YVal, X, Y)
(XVal, YVal, XTr, YTr) = divValTrainSet(XTrain,YTrain)

import keras
earlystop  = keras.callbacks.EarlyStopping(monitor='loss', patience=20, verbose=False)
checkpoint = keras.callbacks.ModelCheckpoint('bestW.h5', monitor='loss', verbose=False, save_weights_only=True, save_best_only=True)
callbacksList = [earlystop, checkpoint] 

history = myANN.fit(XTr,YTr, epochs=1000, validation_data=(XVal, YVal), callbacks=callbacksList, verbose=False)

import matplotlib.pyplot as plt
lossMonitor = np.array(history.history['loss'])
valLossMonitor = np.array(history.history['val_loss'])
counts = np.arange(lossMonitor.shape[0])
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(counts,lossMonitor,'k', label='Trainingsdaten')
ax.plot(counts,valLossMonitor,'r:', label='Validierungsdaten')
ax.set_xlabel('Lernzyklus')
ax.set_ylabel('Fehler')
ax.legend()

myANN.load_weights('bestW.h5')
yp = myANN.predict(XTest)
yp = yp.reshape(yp.shape[0])
errorT = (yMax - yMin)*(yp - YTest)
print(np.mean(np.abs(errorT)))

yp = myANN.predict(XTrain)
yp = yp.reshape(yp.shape[0])
error = (yMax - yMin)*(yp - YTrain)
print(np.mean(np.abs(error)))

fig = plt.figure()
ax = fig.add_subplot(1,2,1)
ax.set_title('Verteilung der Abweichungen auf der Trainingsmenge')
ax.hist(error,color='gray')
ax.set_xlabel('Abweichung in Tausenden')
ax.set_ylabel('Anzahl')
ax = fig.add_subplot(1,2,2)
ax.set_title('Verteilung der Abweichungen auf der Testmenge')
ax.hist(errorT,color='gray')
ax.set_xlabel('Abweichung in Tausenden')
ax.set_ylabel('Anzahl')

