%matplotlib inline

import pandas as pd
import matplotlib.pyplot as plt
import os
import sys
import numpy as np
import math

"""
Explanation: Binary Classifier on Particle Track Data
End of explanation
"""


track_params = pd.read_csv('../TRAIN/track_parms.csv')

track_params.tail()

"""
Explanation: Get angle values and cast to boolean
End of explanation
"""


# Create binary labels
track_params['phi_bool'] = track_params.phi.apply(lambda x: "+" if x > 0 else "-")

"""
Explanation: Create our simple classification target
End of explanation
"""


track_params[['phi', 'z']].hist()

track_params.plot(x='z', y='phi', kind='hexbin', sharex=False, cmap="Blues")

"""
Explanation: Look at the distributions to see if we have any imbalances
End of explanation
"""


track_params.head()

"""
Explanation: looks like a perfectly balanced dataset to me, so we don't have to worry about the type of complications that arise from am imbalanced set.
End of explanation
"""


from tensorflow.keras.preprocessing.image import ImageDataGenerator

DATAGEN = ImageDataGenerator(rescale=1./255.,
                             validation_split=0.25)

height = 100
width = 36

def create_generator(target, subset, class_mode,
                     idg=DATAGEN, df=track_params, N=1000):
    
    return idg.flow_from_dataframe(
        dataframe=track_params.head(N),
        directory="../TRAIN",
        x_col="filename",
        y_col=target,
        subset=subset,
        target_size=(height, width),
        batch_size=32,
        seed=314,
        shuffle=True,
        class_mode=class_mode,
    )

binary_train_generator = create_generator(
    target="phi_bool",
    subset="training",
    class_mode="binary"
)
binary_val_generator = create_generator(
    target="phi_bool",
    subset="validation",
    class_mode="binary"
)

"""
Explanation: Create an image generator from this dataframe
End of explanation
"""


from tensorflow.keras import Sequential, Model
from tensorflow.keras.layers import (
    Conv2D, Activation, MaxPooling2D,
    Flatten, Dense, Dropout, Input
)

"""
Explanation: Create a very simple convolutional model from scratch
End of explanation
"""


width  = 36
height = 100
channels = 3

def binary_classifier():
    model = Sequential()

    # Convolutional Block Layer
    model.add(Conv2D(32, (3, 3), input_shape=(height, width, channels)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))

    # Dense, Classification Layer
    model.add(Flatten())
    model.add(Dense(32))
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))

    model.compile(loss='binary_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])
    
    return model

"""
Explanation: Model Definition
End of explanation
"""


STEP_SIZE_TRAIN = binary_train_generator.n//binary_train_generator.batch_size
STEP_SIZE_VAL = binary_val_generator.n//binary_val_generator.batch_size

binary_model = binary_classifier()
binary_history = binary_model.fit_generator(
    generator=binary_train_generator,
    steps_per_epoch=STEP_SIZE_TRAIN,
    validation_data=binary_val_generator,
    validation_steps=STEP_SIZE_VAL,
    epochs=5
)

plt.plot(binary_history.history['accuracy'], label="Train Accuracy")
plt.plot(binary_history.history['val_accuracy'], label="Validation Accuracy")
plt.legend()
plt.show()

"""
Explanation: Train this model
End of explanation
"""


