# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: 'Python 3.8.10 64-bit (''venv'': venv)'
#     name: python3
# ---

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.neural_network import MLPClassifier
from sklearn.linear_model import LogisticRegression
import pickle
from sklearn.metrics import confusion_matrix

# ## Download the dataset

# +
features = 'MFCCs'
dataset = 'MLS'

df = pd.read_csv(f'data/{dataset}_split_{features}_data.csv')
df.head()
# -

# ## Split the dataset into training and test data
# Let's use 20% of the database for testing.
#
# We also need to make sure the classes(Genders) are equally distributed between the classes.

# +
mydata_train, mydata_test = train_test_split(df, random_state=0, test_size=0.2)

print(f'Feminine voices in the training data: {len(mydata_train.Gender)- sum(mydata_train.Gender)}')
print(f'Masculine voices in the training data: {sum(mydata_train.Gender)}')
print(f'Feminine voices in the test data: {len(mydata_test.Gender)- sum(mydata_test.Gender)}')
print(f'Masculine voices in the test data: {sum(mydata_test.Gender)}')


# +
if features == 'MFCCs':
    data_x_train = mydata_train[['MFCC_1', 'MFCC_2', 'MFCC_3', 'MFCC_4', 'MFCC_5', 'MFCC_6', 'MFCC_7', 'MFCC_8', 'MFCC_9', 'MFCC_10',
                        'MFCC_11', 'MFCC_12', 'MFCC_13', 'MFCC_14', 'MFCC_15', 'MFCC_16', 'MFCC_17', 'MFCC_18', 'MFCC_19', 'MFCC_20']].copy()
    y_train = mydata_train[['Gender']].copy().values.ravel()
    data_x_test = mydata_test[['MFCC_1', 'MFCC_2', 'MFCC_3', 'MFCC_4', 'MFCC_5', 'MFCC_6', 'MFCC_7', 'MFCC_8', 'MFCC_9', 'MFCC_10',
                        'MFCC_11', 'MFCC_12', 'MFCC_13', 'MFCC_14', 'MFCC_15', 'MFCC_16', 'MFCC_17', 'MFCC_18', 'MFCC_19', 'MFCC_20']].copy()
    y_test = mydata_test[['Gender']].copy().values.ravel()

if features == 'Features':
    data_x_train = mydata_train[['nobs', 'mean', 'skew', 'kurtosis', 'median', 'mode', 'std', 'low', 'peak', 'q25', 'q75', 'iqr']].copy()
    y_train = mydata_train[['Gender']].copy().values.ravel()
    data_x_test = mydata_test[['nobs', 'mean', 'skew', 'kurtosis', 'median', 'mode', 'std', 'low', 'peak', 'q25', 'q75', 'iqr']].copy()
    y_test = mydata_test[['Gender']].copy().values.ravel()
# -

scaler = StandardScaler()
scaler.fit(data_x_train)
X_train = pd.DataFrame(scaler.transform(data_x_train), columns=data_x_train.columns)
X_test = pd.DataFrame(scaler.transform(data_x_test), columns=data_x_test.columns)
pickle.dump(scaler, open(f'models/{dataset}_{features}_scaler.pkl', 'wb'))

# +
#Train decision tree model
tree = DecisionTreeClassifier(random_state=0).fit(X_train, y_train)
filename = f'models/{dataset}_{features}_DecisionTree.sav'
pickle.dump(tree, open(filename, 'wb'))
print("\nDecision Tree")
print("Accuracy on training set: {:.3f}".format(tree.score(X_train, y_train)))
print("Accuracy on test set: {:.3f}".format(tree.score(X_test, y_test)))
print(f"Confusion Matrix:\n {confusion_matrix(y_test, tree.predict(X_test), labels=[1, 0])}")

#Train random forest model
forest = RandomForestClassifier(n_estimators=5, random_state=0).fit(X_train, y_train)
filename = f'models/{dataset}_{features}_RandomForest.sav'
pickle.dump(forest, open(filename, 'wb'))
print("\nRandom Forests")
print("Accuracy on training set: {:.3f}".format(forest.score(X_train, y_train)))
print("Accuracy on test set: {:.3f}".format(forest.score(X_test, y_test)))
print(f"Confusion Matrix:\n {confusion_matrix(y_test, forest.predict(X_test), labels=[1, 0])}")

#Train gradient boosting model
gbrt = GradientBoostingClassifier(random_state=0).fit(X_train, y_train)
filename = f'models/{dataset}_{features}_GradientBoosting.sav'
pickle.dump(gbrt, open(filename, 'wb'))
print("\nGradient Boosting")
print("Accuracy on training set: {:.3f}".format(gbrt.score(X_train, y_train)))
print("Accuracy on test set: {:.3f}".format(gbrt.score(X_test, y_test)))
print(f"Confusion Matrix:\n {confusion_matrix(y_test, gbrt.predict(X_test), labels=[1, 0])}")

# +
#Train logistic regression model
lgr = LogisticRegression(random_state=0).fit(X_train, y_train)
filename = f'models/{dataset}_{features}_LogisticRegression.sav'
pickle.dump(lgr, open(filename, 'wb'))
print("\nLogisticRegression")
print("Accuracy on training set: {:.3f}".format(lgr.score(X_train, y_train)))
print("Accuracy on test set: {:.3f}".format(lgr.score(X_test, y_test)))
print(f"Confusion Matrix:\n {confusion_matrix(y_test, lgr.predict(X_test), labels=[1, 0])}")

#Train support vector machine model
svm = SVC().fit(X_train, y_train)
filename = f'models/{dataset}_{features}_SVM.sav'
pickle.dump(svm, open(filename, 'wb'))
print("\nSupport Vector Machine")
print("Accuracy on training set: {:.3f}".format(svm.score(X_train, y_train)))
print("Accuracy on test set: {:.3f}".format(svm.score(X_test, y_test)))
print(f"Confusion Matrix:\n {confusion_matrix(y_test, svm.predict(X_test), labels=[1, 0])}")

#Train neural network model
mlp = MLPClassifier(random_state=0).fit(X_train, y_train)
filename = f'models/{dataset}_{features}_MLP.sav'
pickle.dump(mlp, open(filename, 'wb'))
print("\nMultilayer Perceptron")
print("Accuracy on training set: {:.3f}".format(mlp.score(X_train, y_train)))
print("Accuracy on test set: {:.3f}".format(mlp.score(X_test, y_test)))
print(f"Confusion Matrix:\n {confusion_matrix(y_test, mlp.predict(X_test), labels=[1, 0])}")


# -

def plot_feature_importances_mydata(model, c):
    n_features = len(X_train.columns)
    plt.figure(1,figsize=(18,10))
    plt.bar(range(n_features), model.feature_importances_, align='center', color=c)
    plt.xticks(np.arange(n_features), X_train.columns)
    plt.ylabel("Variable importance")
    plt.xlabel("Independent Variable")
    plt.title(model.__class__.__name__)
    plt.show()


plot_feature_importances_mydata(gbrt,'blue')

# +
import tensorflow as tf
from tensorflow import keras

NeuralNetwork = tf.keras.Sequential([
    tf.keras.layers.Dense(8, activation='relu', input_shape=(12,)),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax')
])

NeuralNetwork.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])
history = NeuralNetwork.fit(X_train, y_train,validation_split=0.2, epochs=100, verbose=4)

test_loss, test_acc = NeuralNetwork.evaluate(X_test,  y_test, verbose=0)


print('\nTest accuracy:', test_acc)
# -

plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'val'], loc='upper left')
plt.show()

plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()



StarcoderdataJupyterScriptsDedupFiltered