rm(list = ls())

##############################################################
#### Below is the code to create a balanced data set.    #####
#### The rest of the code in this section                #####
#### has been commented out.                             #####
##############################################################

## import libraries 
### Loading DMwr to balance the unbalanced class
#library(DMwR)


## set seed
#set.seed(21)

## import data original data 
#df <-  read.csv('train.csv')
## drop the ID_code column on both the test and train data
#df <-  df[,-1] 

## convert Target to factor
#df$target <- as.factor(df$target)

## split train and test data
#n <- nrow(df) * 0.8
#ind <- sample(nrow(df), size = n, replace = FALSE)
#df.train <- df[ind, ]
#df.test <- df[-ind,]

#as.data.frame(table(df.train$target))
#prop.table(table(df.train$target))
## SMOTE
#balanced.data <- SMOTE(target ~., df.train, perc.over = 750, k = 5, perc.under = 110)

#print(as.data.frame(table(balanced.data$target)))


#print(prop.table(table(balanced.data$target)))

#write.csv(balanced.data, "df_train_balanced.csv", row.names = FALSE)
#write.csv(df.test, "df_test.csv", row.names = FALSE)
##############################################################

##############################################################
####  This section begins the modeling section            ####
##############################################################
# Import libraries 
library(MLmetrics) # library to calculate error metrics
library(glmnet)
library(e1071)

library(randomForest)
library(gbm)

# import data
set.seed(21)
df.train <- read.csv("df_train_balanced.csv") # balanced training set
shuffle <- sample(nrow(df.train), nrow(df.train)) # we need to shuffle the data frame
df.train <- df.train[shuffle,]
df.train$target <- as.factor(df.train$target)
df.test <- read.csv("df_test.csv") # sampled training data from code above
shuffle <- sample(nrow(df.test), nrow(df.test)) # we need to shuffle the data frame
df.test <- df.test[shuffle,]
df.test$target <- as.factor(df.test$target)
df.train.scale <- data.frame(scale(df.train[,-1]))
df.train.scale <- cbind(df.train.scale, target = df.train$target)
df.test.scale <- data.frame(scale(df.test[,-1]))
df.test.scale <- cbind(df.test.scale, target = df.test$target)
performance_colnames <- c("model", "accuracy", "f1", "precision", "recall", "rocAUC")




# logistic regresion
## Standard 
model.name <-  "Logistic"
logistic.fit <- glm(target~., data= df.train, family=binomial)
logistic.pred.probs <- predict(logistic.fit, df.test, type="response")  
model.pred <-  ifelse(logistic.pred.probs > 0.5, 1, 0)
accuracy <- Accuracy(model.pred, df.test$target)
f1 <- F1_Score(model.pred, df.test$target)
prec <- Precision(model.pred, df.test$target)
rec <- Recall(model.pred, df.test$target)
rocauc <- AUC(model.pred, df.test$target)
prauc <- PRAUC(model.pred, df.test$target)
performance <- data.frame( model.name, accuracy, f1, prec, rec, rocauc, stringsAsFactors = F)
colnames(performance) <- performance_colnames

## Ridge
set.seed(21)
model.name <- "Ridge"
x.data.train <- model.matrix(target~., df.train.scale)[,-1] # convert Xs into a usable form for glmnet
x.data.test <- model.matrix(target~., df.test.scale)[,-1]  # convert Xs into a usable form for glmnet


## run cv to determine the best lambda  
#lambdagrid <- 10^seq(10,-3, length=100)
#cv.out.class <-  cv.glmnet(x.data.train, df.train$target, alpha =0 , lambda = lambdagrid,  family = 'binomial')
#(bestlam <-  cv.out.class$lambda.min) # best lambda is 0.001

bestlam <- 0.001

#run again with besty lambda
mod.ridge <-  glmnet(x.data.train, df.train$target, alpha = 0, lambda=bestlam, family = 'binomial')
model.pred<-  rep(0, length(df.test$target))
prob  <-  predict(mod.ridge,s = bestlam, newx = x.data.test, type = 'response')
model.pred[prob>.5] <- 1

#calculate performance measures 

accuracy <- Accuracy(model.pred, df.test$target)
f1 <- F1_Score(model.pred, df.test$target)
prec <- Precision(model.pred, df.test$target)
rec <- Recall(model.pred, df.test$target)
rocauc <- AUC(model.pred, df.test$target)
performance <- rbind(performance, c( model.name, accuracy, f1, prec, rec, rocauc))
colnames(performance) <- performance_colnames

## Lasso
set.seed(21)
model.name <- "Lasso"

# run cv to determine the best lambda  
#cv.out.class <-  cv.glmnet(x.data.train, df.train.scale$target, alpha =1 , lambda = lambdagrid,  family = 'binomial')
#(bestlam <-  cv.out.class$lambda.min) # best lambda is 0.001

bestlam <- 0.001
#run again with besty lambda
mod.lasso <-  glmnet(x.data.train, df.train$target, alpha = 1, lambda=bestlam, family = 'binomial')
model.pred<-  rep(0, length(df.test$target))
prob  <-  predict(mod.lasso,s = bestlam, newx = x.data.test, type = 'response')
model.pred[prob>.5] <- 1

#calculate performance measures 
accuracy <- Accuracy(model.pred, df.test$target)
f1 <- F1_Score(model.pred, df.test$target)
prec <- Precision(model.pred, df.test$target)
rec <- Recall(model.pred, df.test$target)
rocauc <- AUC(model.pred, df.test$target)

performance <- rbind(performance, c( model.name, accuracy, f1, prec, rec, rocauc ))
colnames(performance) <- performance_colnames



# Naive bayes 
set.seed(21)
model.name <-  "Naive_Bayes"
naive_bay <- naiveBayes(target~., df.train)
model.pred <- predict(naive_bay, df.test)

model.pred <- as.integer(model.pred)
accuracy <- Accuracy(model.pred, df.test$target)
f1 <- F1_Score(model.pred, df.test$target)
prec <- Precision(model.pred, df.test$target)
rec <- Recall(model.pred, df.test$target)
rocauc <- AUC(model.pred, df.test$target)
performance <- rbind(performance, c( model.name, accuracy, f1, prec, rec, rocauc))
colnames(performance) <- performance_colnames



# Tree Methods
## Random Forest

set.seed(21)
model.name <- "Random Forrest"

mtry <- sqrt(ncol(df.train)-1)
n_trees <- c(100, 150, 200, 250, 300 )
nodes <- c(10, 20, 30, 40, 50 , 60)
n = length(n_trees) * length(nodes)
nod_record <-rep(0, n)
record <- rep(0, n)
tree_recod <- rep(0, n)
c <- 1

##############################################################
#  Section commented out below is for hyper parameter tuning #
##############################################################

#for(i in 1:length(n_trees)){
#for(j in 1:length(nodes)){
#rf <- randomForest(target ~., data = df.train, maxnodes = nodes[j], ntree = n_trees[i])
#model.pred <- predict(rf, df.train)
#record[c] <- AUC(model.pred, df.test$target)
#nod_record[c] <- j
#tree_recod[c] <- i
#c <- c + 1}}
#(best <- which.max(record))
#(best.nodes <- nod_record[best]) 3rd from nodes
#(best_tree <- tree_recod[best]) 2nd from n_trees

rf <- randomForest(target ~., data = df.train, maxnodes = nodes[3], ntree = n_trees[2])
model.pred <- predict(rf, df.test)

accuracy <- Accuracy(model.pred, df.test$target)
f1 <- F1_Score(model.pred, df.test$target)
prec <- Precision(model.pred, df.test$target)
rec <- Recall(model.pred, df.test$target)
rocauc <- AUC(model.pred, df.test$target)
performance <- rbind(performance, c( model.name, accuracy, f1, prec, rec, rocauc))
colnames(performance) <- performance_colnames




