#importieren sie die Bibliothek pandas
import pandas as pd

#importieren sie matplotlib.pyplot as plt
import matplotlib.pyplot as plt
%matplotlib inline

#laden Sie die Datei "daten.csv" auf Ihren Hub
#laden Sie die Datei "daten.csv" in einen Datframe df
#Einlesen der Dateien mit pd.read_csv()
df=pd.read_csv("daten.csv")

#Betrachten Sie die ersten Daten des Dataframes df (default=5)
df.head()

#Betrachten Sie 20 Datensätze am Ende des DataFrames
df.tail(20)

#Erzeugen Sie eine Beschreibung der Statistischen Daten mit .describe()
df.describe()

#Erzeugen Sie einen einfachen Scatterplot
plt.scatter(df.x1,df.x2, c=df.label)

#importieren Sie tensorflow as tf
# Laden der Bibliotheken
import tensorflow as tf

#importieren Sie das keras.model Sequential()
from keras.models import Sequential


#importieren Sie die Keras Layer Dense und Activation
from keras.layers import Dense

#Auslesen der Daten und Labels aus dem Dataframe in ein array
x_input = df[['x1','x2']].values
y_input = df[['label']].values

#Ausgabe der Datenwerte
print(x_input)

#Ausgabe der labels
print(y_input)

"""
Explanation: <h1>ANN - Erstes arbeiten mit Tensorflow - Binäre Klassifikation</h1>
End of explanation
"""


#Initialisierung des Neuronalen Netzes nn
nn=Sequential()

#Hinzufügen eines Dense Layers mit einem Neuron (units = 1)
#Im ersten Layer geben eivel Features übergeben werden (input_dim=2)
#Als Aktivierungsfunktion verwenden wir die Sigmoid-Funktion
nn.add(Dense(units=1,input_dim=2,activation = 'sigmoid'))

# Compilieren des Modells.
# Wir verwenden den optimizer 'adam'.
# Es handelt sich um eine binäre Klassifikation, deshalb verwenden
# wir 'binary_crossentropy' als Loss-Funktion und
# betrachten als Qualitätsmaßstab die Accuracy
nn.compile(optimizer='adam',loss='binary_crossentropy',metrics=['accuracy'])


# Überprüfen der Konfiguration
nn.summary()


# Trainieren des Modells mit .fit
# eventuell validation_split = 0.1 einfügen, d.h. 10% der Daten, werden zur Validierung verwendet.
epoch_num = 1000
# batch_num = 56 eventuell als Beispiel ergänzen
history = nn.fit(x_input, y_input, epochs=epoch_num,validation_split=0.1, verbose = 1)

#Evaluierung der Ergebnisse
nn.evaluate(x_input,y_input)

#Test mit Daten
x_test=[[2,3],[6,4],[5,5],[4.321,2.657],[2.6487,4.5192],[1.5438,2.4443],[1.8991,4.2409],[6.1676,3.6457],[7.567,3.6381],[6.4321,5.4453]]
ergebnis = nn.predict(x_test)
print(ergebnis)

#Ausgabe der Anzahl der Werte in der Variablen ergebnis
len(ergebnis)

# Schleife zur Ausgabe der entsprechenden Labels
i = 0
while i< len(ergebnis):
    print("Das Wertepaar : " +str(x_test[i]) + "hat das Ergebnis " + str(ergebnis[i,0]))
    if ergebnis[i,0]>0.5:
        print("und damit das Label 1")
    else:
        print("und damit das Label 0")
    i +=1

history_dict = history.history
history_dict.keys()

acc = history_dict['accuracy']
val_acc = history_dict['val_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

# "bo" steht für "blue dot"
plt.plot(epochs, loss, 'b', label='Training loss')
plt.plot(epochs, acc, 'r', label='Training Accuracy')
# b is for "solid blue line"
plt.plot(epochs, val_loss, 'y', label='Validation loss')
plt.plot(epochs, val_acc, 'g', label='Validation Accuracy')
plt.title('Training/Validation loss und accuracy')
plt.xlabel('Epochs')
plt.ylabel('Loss / Accuracy')
plt.legend()

plt.show()

"""
Explanation: <h2> Erstes Neuronales Netz - Single Layer</h2>
End of explanation
"""


#Initialisieren eine neuen Netzwerkes nn2
nn2=Sequential()

#Hinzufügen der layer
nn2.add(Dense(units=100,input_dim=2,activation='relu'))
nn2.add(Dense(units=50,activation='relu'))
nn2.add(Dense(units=1,activation='sigmoid'))

# Kompilieren des neuen Modells
nn2.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

#Ausgabe der Modellstruktur
nn2.summary()

#Trainieren des Modells
epoch_num = 50
history = nn2.fit(x_input,y_input, epochs=epoch_num,validation_split=0.1, verbose=1)

#Evaluierung der Ergebnisse
nn2.evaluate(x_input, y_input)

history_dict = history.history
history_dict.keys()

acc = history_dict['accuracy']
val_acc = history_dict['val_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

# "bo" steht für "blue dot"
plt.plot(epochs, loss, 'b', label='Training loss')
plt.plot(epochs, acc, 'r', label='Training Accuracy')
# b,r steht für "solid blue or red line"
plt.plot(epochs, val_loss, 'y', label='Validation loss')
plt.plot(epochs, val_acc, 'g', label='Validation Accuracy')
plt.title('Training/Validation loss und accuracy')
plt.xlabel('Epochs')
plt.ylabel('Loss / Accuracy')
plt.legend()

plt.show()

"""
Explanation: <h2> Initialisierung eines zweiten Neuronalen Netzes - Multi Layer</h2>
End of explanation
"""


#Initialisieren eine neuen Netzwerkes nn3
nn3=Sequential()

#Hinzufügen der layer mit geäderter Aktivierungsfunktion
nn3.add(Dense(units=100,input_dim=2,activation='tanh'))
nn3.add(Dense(units=50,activation='tanh'))
nn3.add(Dense(units=1,activation='sigmoid'))

# Kompilieren des neuen Modells
nn3.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

#Ausgabe der Modellstruktur
nn3.summary()

#Trainieren des Modells nn3
epoch_num = 50
history = nn3.fit(x_input,y_input, epochs=epoch_num,validation_split=0.1, verbose=1)

#Evaluierung der Ergebnisse
nn2.evaluate(x_input, y_input)

history_dict = history.history
history_dict.keys()

acc = history_dict['accuracy']
val_acc = history_dict['val_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

# "bo" steht für "blue dot"
plt.plot(epochs, loss, 'b', label='Training loss')
plt.plot(epochs, acc, 'r', label='Training Accuracy')
# b,r steht für "solid blue or red line"
plt.plot(epochs, val_loss, 'y', label='Validation loss')
plt.plot(epochs, val_acc, 'g', label='Validation Accuracy')
plt.title('Training/Validation loss und accuracy')
plt.xlabel('Epochs')
plt.ylabel('Loss / Accuracy')
plt.legend()

plt.show()

"""
Explanation: <h2>Erzeugen von Varianten des Modells nn2</h2>
<br>
Wir verändern:<br>
Aktivierungsfunktion von 'relu' in 'tanh' in den ersten Layern<br>
Dieses Modell bekommt die Bezeichnung nn3
End of explanation
"""


#Initialisieren eine neuen Netzwerkes nn4
nn4=Sequential()

#Hinzufügen der layer mit der Aktivierungsfunktion tanh
nn4.add(Dense(units=100,input_dim=2,activation='tanh'))
nn4.add(Dense(units=50,activation='tanh'))
nn4.add(Dense(units=1,activation='sigmoid'))

# Kompilieren des neuen Modells
nn4.compile(optimizer='sgd', loss='binary_crossentropy', metrics=['accuracy'])

#Ausgabe der Modellstruktur
nn4.summary()

#Trainieren des Modells nn4
epoch_num = 50
history = nn4.fit(x_input,y_input, epochs=epoch_num,validation_split=0.1, verbose=1)

#Evaluierung der Ergebnisse
nn2.evaluate(x_input, y_input)

history_dict = history.history
history_dict.keys()

acc = history_dict['accuracy']
val_acc = history_dict['val_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

# "bo" steht für "blue dot"
plt.plot(epochs, loss, 'b', label='Training loss')
plt.plot(epochs, acc, 'r', label='Training Accuracy')
# b,r steht für "solid blue or red line"
plt.plot(epochs, val_loss, 'y', label='Validation loss')
plt.plot(epochs, val_acc, 'g', label='Validation Accuracy')
plt.title('Training/Validation loss und accuracy')
plt.xlabel('Epochs')
plt.ylabel('Loss / Accuracy')
plt.legend()

plt.show()

# Führen Sie weitere Veränderungen durch:
# 1.
# Verändern Sie in den Modellen nn2, nn3 und nn4 die Anzahl
# der epochs von 50 auf 100, epochs_num=100
# 2.
# Verändern Sie die Anzahl der Neuronen im ersten Layer auf 200
# und im zweiten Layer auf 100 
#
# Initialisieren Sie das Modell in der jeweiligen Zelle einfach neu
# und führen dann im Modell die Veränderungen durch.
#
# Ergeben sich Ergebnisverbesserungen
#
# Wie sie sehen wurde mit der einfachen Anweisung validation_split=0.1
# ein Teil der Daten zur Validierung verwendet. Variieren Sie doch auch
# einmal diesen Anteil auf 0.2 oder 0.3.
#


"""
Explanation: <h2>Erzeugen von Varianten des Modells nn2</h2>
<br>
Wir verändern:<br>
Den optimizer 'adam' in 'sgd' (Stochastisches Gradientenverfahren) bei der Kompilierung<br>
Dieses Modell bekommt die Bezeichnung nn4
End of explanation
"""


