# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # ML Models on Raw Positions

import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt
# %matplotlib inline

# ## 1. Preprocessing

# ### a) Import data

df = pd.read_csv('workingDataset_timbrePosition.csv', encoding = 'latin1')
df.head()

popularity = df.popularity
df = df.drop(['Unnamed: 0', 'popularity'], axis = 1)

df_columns = list(df.columns)
df_columns

df.shape

features_startIndex = df_columns.index('acousticness')
output_startIndex = df_columns.index('pt_position')

# ### b) Define Output

Y = df.iloc[:, output_startIndex:]
Y.head()

# Number of nul values
df_isNull = Y.iloc[:, ].isnull().sum()
print(df.shape[0])
df_isNull

list_isNull = list(df_isNull)
threshold = df.shape[0]/2
print('Threshold: {}'.format(threshold))
toKeep = list()
for i in range(len(list_isNull)):
    if list_isNull[i]<threshold:
        toKeep.append(i)
print(toKeep)
print(len(toKeep))

Y = Y.iloc[:, toKeep]
Y.head()

Y.describe()

# Replace NaN Values by very low chart score: 
lowPos = 300 # set arbitrarily
var = 0.01
print('Before:')
print(Y.isnull().sum())
for i in range(Y.shape[0]):
    Y.iloc[i,:] = Y.iloc[i,:].fillna(lowPos)
    lowPos += var
print('After:')
print(Y.isnull().sum())

# Get binary values
Y_test = Y.copy()
for i in range(Y.shape[1]):
    Y_test.iloc[:,i] = pd.qcut(Y_test.iloc[:,i], 2, labels = False)

# ### c) Define Input/Features

X = df.iloc[:, features_startIndex:output_startIndex]
X.head()

from sklearn.preprocessing import normalize
X_norm = normalize(X)

# ### d) Constructs Dataframe

df_work = pd.concat([X,Y], axis=1)
df_work.head()

# ## 2. Perform Machine Learning

# ### Import packages/Define functions

# +
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC, LinearSVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import Perceptron
import xgboost as xgb

from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.metrics import roc_curve, auc

import operator

from sklearn.preprocessing import normalize


# +
# Confusion Matrix
def printConfusionMatrix (y_true, y_pred):
    cf=pd.DataFrame(confusion_matrix(y_true, y_pred))
    print(cf)

def plotROCCurve (y_true, y_pred):
    fpr, tpr, thresholds = roc_curve(y_true, y_pred)
    roc_auc = auc(fpr, tpr)
    
    plt.figure()
    lw = 2
    plt.plot(fpr, tpr, color='darkorange',
             lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
    plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.05])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('Receiver operating characteristic example')
    plt.legend(loc="lower right")
    plt.show()

def featureImportance(x_train, y_train, features):
    random_forest = RandomForestClassifier(n_estimators=190)
    random_forest.fit(x_train, y_train)
    values = random_forest.feature_importances_
    dict_featureImportance = dict(zip(features,values))
    sorted_dict = sorted(dict_featureImportance.items(), key=operator.itemgetter(1), reverse = True)
    return sorted_dict

def performsMLModelComparison(x_train, x_test, y_train, y_test, printing=True):
    '''Tries standard ML models, reports average accuracy and best model (with its accuracy and confusion matrix)'''
    MLModels = [LogisticRegression(), SVC(), Perceptron(), KNeighborsClassifier(n_neighbors = 3), xgb.XGBClassifier(n_estimators = 140), RandomForestClassifier(n_estimators = 140)]
    MLModelsStrings = ["Logistic Regression", "Support Vector Machine", "Perceptron", "KN Neighbors", "Gradient Boosting", "Random Forest"]
    nModels = len(MLModels)
    trainingAccuracy = list()
    testAccuracy = list()
    aucScore = list()

    # Train models
    for i in range(nModels):
        MLModels[i].fit(x_train, y_train)
        trainingAccuracy.append (MLModels[i].score(x_train, y_train))
        testAccuracy.append(MLModels[i].score(x_test, y_test))
        
        fpr, tpr, thresholds = roc_curve(y_test, MLModels[i].predict(x_test))
        roc_auc = auc(fpr, tpr)
        aucScore.append(roc_auc)
    
    # Report average test accuracy
    if (printing):
        '''print('Used the following models:')
        print(MLModelsStrings)
        print('Test Scores')
        print(testAccuracy)
        print('AUC Scores')
        print(aucScore)
        print('Average test accuracies of all models is: {}'.format(np.mean(testAccuracy)))'''
    
    # Find best model
    max_testAccuracy = max(testAccuracy)
    max_index = testAccuracy.index(max_testAccuracy)
    bestModel = MLModels[max_index]
    if (printing):
        print('{} is the best model'.format(MLModelsStrings[max_index]))
        print('Test Accuracy: {}'.format(max_testAccuracy))
        print('AUC Score: {}'.format(aucScore[max_index]))
        print('Confusion Matrix')
        printConfusionMatrix(y_test, bestModel.predict(x_test))
    
    return bestModel


# -

def runsModel(x_train, x_test, y_train, y_test, model):

    # Train model
    model.fit(x_train, y_train)
    trainingAccuracy = (model.score(x_train, y_train))
    testAccuracy = (model.score(x_test, y_test))

    fpr, tpr, thresholds = roc_curve(y_test, model.predict(x_test))
    roc_auc = auc(fpr, tpr)
    aucScore = (roc_auc)
    
    print('Test Accuracy: {}'.format(testAccuracy))
    print('Training Accuracy: {}'.format(trainingAccuracy))
    print('AUC Score: {}'.format(aucScore))
    print('Confusion Matrix')
    printConfusionMatrix(y_test, model.predict(x_test))


# ### 1. Test out random models for all countries

a = list(df_work.columns)
index = a.index('pt_position')
output =a[index:]
print("Number of outputs: {}".format(len(output)))
print(output)

features = a[:index]
print("Number of features: {}".format(len(features)))
print(features)

testAccuracy = list()
Y = df_work[output]
for i in range(Y.shape[1]):
    print('Performs prediction at Country: {}'.format(Y_test.columns[i]))
    Y_curr = Y_test.iloc[:,i]
    x_train, x_test, y_train, y_test = train_test_split(X_norm,Y_curr, test_size=0.15, random_state=100)
    bestModel = performsMLModelComparison(x_train, x_test, y_train, y_test)
    testAccuracy.append(bestModel.score(x_test, y_test))

print(testAccuracy)
print(np.mean(testAccuracy))

# ### 2. Try with an gap in between

a = list(df_work.columns)
index = a.index('pt_position')
output =a[index:]
print("Number of outputs: {}".format(len(output)))
print(output)

features = a[:index]
print("Number of features: {}".format(len(features)))
print(features)

# Get binary values
gapSize = 0.2
binSize = (1-gapSize)/2.0
print(binSize)
testAccuracy = list()
for i in range(len(output)):
    print('Performs prediction at Country: {}'.format(output[i]))
    
    df_test = df_work.copy()
    df_test[output[i]] = pd.qcut(df_test[output[i]], [0, 0.3, 0.7,1], duplicates ='raise', labels=False)
    df_test = df_test[df_test[output[i]]!=1]
    df_test[output[i]] = df_test[output[i]].replace(2,1)
    print('Reduced data set to {} from {}:'.format(df_test.shape[0], df.shape[0]))

    X = df_test[features]
    X = normalize(X)
    Y = df_test[output[i]]
    x_train, x_test, y_train, y_test = train_test_split(X,Y, test_size=0.15, random_state=100)
    bestModel = performsMLModelComparison(x_train, x_test, y_train, y_test)
    testAccuracy.append(bestModel.score(x_test, y_test))
    

np.mean(testAccuracy)

# ### 3. Feature Importance

# #### a) Are those the same for all outputs?

Y = df_work[output]
X = df_work[features]
X_norm = normalize(X)

for i in range(Y.shape[1]):
    Y_curr = pd.qcut(Y.iloc[:, i], 2, labels= False)
    x_train, x_test, y_train, y_test = train_test_split(X,Y_curr, test_size=0.15, random_state=100)

    featureRanking = featureImportance(x_train, y_train, features) # List
    features_sorted = list()
    for j in range(len(featureRanking)):
        features_sorted.append(featureRanking[j][0])
    print('Top 5 features for output {}'.format(i))
    print(features_sorted[:6])

# #### b)Try to reduce features

features = features_sorted[:60]

testAccuracy = list()
Y = df_work[output]
X = df_work[features]
X_norm = normalize(X)
model = RandomForestClassifier(n_estimators=190)
for i in range(Y.shape[1]):
    Y_curr = pd.qcut(Y.iloc[:, i], 2, labels= False)

    print('Performs prediction at Country: {}'.format(Y_test.columns[i]))
    x_train, x_test, y_train, y_test = train_test_split(X_norm,Y_curr, test_size=0.15, random_state=100)
    bestModel = performsMLModelComparison(x_train, x_test, y_train, y_test)
    testAccuracy.append(bestModel.score(x_test, y_test))



StarcoderdataJupyterScriptsDedupFiltered