# Define classification algorithem


from sklearn.ensemble import AdaBoostClassifier, GradientBoostingClassifier
def train_lda(tr_X, tr_y_cat, va_X):
    from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
    classifier = LDA(n_components=1)
    classifier.fit(tr_X, tr_y_cat)
    rf_tr_pred = classifier.predict(tr_X)
    rf_va_pred = classifier.predict(va_X)


    return rf_tr_pred, rf_va_pred

def train_Grbagg(tr_X, tr_y_cat, va_X):
  rf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,max_depth=1, random_state=0)
  rf.fit(tr_X, tr_y_cat)
  rf_tr_pred = rf.predict(tr_X)
  rf_va_pred = rf.predict(va_X)

  return rf_tr_pred, rf_va_pred#, rf_te_pred

def train_bagg(tr_X, tr_y_cat, va_X):
    rf = AdaBoostClassifier(n_estimators=100)
    rf.fit(tr_X, tr_y_cat)
    rf_tr_pred = rf.predict(tr_X)
    rf_va_pred = rf.predict(va_X)

    return rf_tr_pred, rf_va_pred#, rf_te_pred

def train_rf(tr_X, tr_y_cat, va_X):
    rf = RandomForestClassifier(n_estimators=500, n_jobs=-1)
    rf.fit(tr_X, tr_y_cat)
    rf_tr_pred = rf.predict(tr_X)
    rf_va_pred = rf.predict(va_X)

    return rf_tr_pred, rf_va_pred#, rf_te_pred


def train_svm(tr_X, tr_y_cat, va_X):
    clf = svm.SVC()
    clf.fit(tr_X, tr_y_cat)
    rf_tr_pred = clf.predict(tr_X)
    rf_va_pred = clf.predict(va_X)

    return rf_tr_pred, rf_va_pred


from sklearn.neighbors import KNeighborsClassifier

def train_KNN(tr_X, tr_y_cat, va_X):
    classifier = KNeighborsClassifier(n_neighbors=1)
    classifier.fit(tr_X, tr_y_cat)
    rf_tr_pred = classifier.predict(tr_X)
    rf_va_pred = classifier.predict(va_X)


    return rf_tr_pred, rf_va_pred


def train_models(X, y, y_cat,no):

    #holdout Validation (split the dataset)
    tr_X, va_X, tr_y_cat, va_y_cat = model_selection.train_test_split(X, y_cat, test_size=0.2,
                                                                               random_state=77)
     #for 1 and 12 Normalization - scale to 0,1
    min_max_scaler = MinMaxScaler()
    tr_X = min_max_scaler.fit_transform(tr_X)
    va_X = min_max_scaler.transform(va_X)

    tr_y = np.eye(no)[np.array(tr_y_cat,dtype=int)]
    va_y = np.eye(no)[np.array(va_y_cat,dtype=int)]


  lda_tr_pred, lda_va_pred = train_lda(tr_X, tr_y_cat, va_X)#, te_X)
    print('\n\nLDA Result\n')
    print('\n accuracy: {}'.format(accuracy_score(va_y_cat, lda_va_pred)))
    print('Recall: {}'.format(recall_score(va_y_cat, lda_va_pred, average=average)))
    print('Precision: {}'.format(precision_score(va_y_cat, lda_va_pred, average=average)))
    cm_display = (confusion_matrix(va_y_cat, lda_va_pred))
    plot_cf(cm_display)
    print('Confusion matrix:\n {}'.format(cm_display))

    auc = round(roc_auc_score(va_y_cat, lda_va_pred), 4)
    label = "LDA, AUC="+str(auc)
    print(f'model 1 AUC score: {auc}')
    plot_roc_curve(va_y_cat, lda_va_pred,label)


    rf_tr_pred, rf_va_pred = train_KNN(tr_X, tr_y_cat, va_X)
    print('\n KNN Result\n')
    print('\n Accuracy: {}'.format(accuracy_score(va_y_cat, rf_va_pred)))
    print('Recall: {}'.format(recall_score(va_y_cat, rf_va_pred, average=average)))
    print('Precision: {}'.format(precision_score(va_y_cat, rf_va_pred, average=average)))
    cm_display = (confusion_matrix(va_y_cat, rf_va_pred))
    plot_cf(cm_display)
    print('Confusion matrix:\n {}'.format(cm_display))

    auc = round(roc_auc_score(va_y_cat, rf_va_pred), 4)
    label = "KNN, AUC="+str(auc)
    print(f'model 1 AUC score: {auc}')
    plot_roc_curve(va_y_cat, rf_va_pred,label)


    rf_tr_pred, rf_va_pred = train_svm(tr_X, tr_y_cat, va_X)
    print('\n\nSupport vector machine Result\n')
    print('\n Accuracy: {}'.format(accuracy_score(va_y_cat, rf_va_pred)))
    print('Recall: {}'.format(recall_score(va_y_cat, rf_va_pred, average=average)))
    print('Precision: {}'.format(precision_score(va_y_cat, rf_va_pred, average=average)))

    cm_display = (confusion_matrix(va_y_cat, rf_va_pred))
    plot_cf(cm_display)
    print('Confusion matrix:\n {}'.format(cm_display))

    auc = round(roc_auc_score(va_y_cat, rf_va_pred), 4)
    label = "SVM, AUC="+str(auc)
    print(f'model 1 AUC score: {auc}')
    plot_roc_curve(va_y_cat, rf_va_pred,label)


    rf_tr_pred, rf_va_pred = train_rf(tr_X, tr_y_cat, va_X)#, te_X)

    print('\n\nRandom Forest Result\n')
    print('\n\nAccuracy: {}'.format(accuracy_score(va_y_cat, rf_va_pred)))
    print('Recall: {}'.format(recall_score(va_y_cat, rf_va_pred, average=average)))
    print('Precision: {}'.format(precision_score(va_y_cat, rf_va_pred, average=average)))

    cm_display = (confusion_matrix(va_y_cat, rf_va_pred))
    plot_cf(cm_display)
    print('Confusion matrix:\n {}'.format(cm_display))

    auc = round(roc_auc_score(va_y_cat, rf_va_pred), 4)
    label = "RF, AUC="+str(auc)
    print(f'model 1 AUC score: {auc}')
    plot_roc_curve(va_y_cat, rf_va_pred,label)

    rf_tr_pred, rf_va_pred = train_bagg(tr_X, tr_y_cat, va_X)#, te_X)

    print('\n\AdaBoost Bagging Result\n')
    print('\n\nAccuracy: {}'.format(accuracy_score(va_y_cat, rf_va_pred)))
    print('Recall: {}'.format(recall_score(va_y_cat, rf_va_pred, average=average)))
    print('Precision: {}'.format(precision_score(va_y_cat, rf_va_pred, average=average)))
    cm_display = (confusion_matrix(va_y_cat, rf_va_pred))
    plot_cf(cm_display)
    print('Confusion matrix:\n {}'.format(cm_display))

    auc = round(roc_auc_score(va_y_cat, rf_va_pred), 4)
    label = "AdaBoost Bagging, AUC="+str(auc)
    print(f'model 1 AUC score: {auc}')
    plot_roc_curve(va_y_cat, rf_va_pred,label)

    rf_tr_pred, rf_va_pred = train_Grbagg(tr_X, tr_y_cat, va_X)#, te_X)

    print('\n\Gradient Bagging Result\n')
    print('\n\nAccuracy: {}'.format(accuracy_score(va_y_cat, rf_va_pred)))
    print('Recall: {}'.format(recall_score(va_y_cat, rf_va_pred, average=average)))
    print('Precision: {}'.format(precision_score(va_y_cat, rf_va_pred, average=average)))
    cm_display = (confusion_matrix(va_y_cat, rf_va_pred))
    plot_cf(cm_display)
    print('Confusion matrix:\n {}'.format(cm_display))
    auc = round(roc_auc_score(va_y_cat, rf_va_pred), 4)
    label = "Gradient Bagging, AUC="+str(auc)
    print(f'model 1 AUC score: {auc}')
    plot_roc_curve(va_y_cat, rf_va_pred,label)
