#' @name aiR
#'
#' @title aiR
#'
#' @param data Data frame that contains all named columns needed
#' @param input.col character vector of column names for aiRnet
#' @param var.classify index or column name of vector that contains classifying values
#' @param aiRnet aiRnet object generated by aiRnet function
#' @param cycles Number of cycles done to correct.
#' @param sample.method Method to save internal subset of data as the training data. "Sample" to take
#' a random sample of all rows in data as training set. "Factor" to indicate if you are training
#' on rows containing a particular factor level.
#' @param sample.size Number between (0-1) that modifies how much of desired sample.method data is used.
#' Default set to 0.5. Excluded rows will be used as test examples and not affect aiRnet.
#' @param batch.size Number indicating how many rows to make batches from training sample. Default set to "all"
#' for no batches to be made.
#' @param sample.Factor Necessary when sample.method set to "Factor". Assign as vector of length 2 in the following form
#' c("column.index/name","factor.level"). Can assign only column name or index but first level is chosen in this case.
#' @param na.rm remove NAs, default set to TRUE. Function likely to fail with NAs
#' @param test.rate "none" or "fast" or "slow" or integer specifying how often the test model is checked. Test model is
#' used only when sample.size < 0.8 is set, otherwise the full model is used instead. "fast" indicates model is tested
#' at begining and end. "slow" indicates full model is tested each cycle. An integer indicates how many cycles pass
#' before testing the model. e.i. 1 is equivelent to "slow", 2 is every other cycle, 3 is every third cycle, ... etc.
#' "none" indicates that the model will not be verified on any model.
#'
#' @return data frame of loss and the aiRnet of the training values. data set used is optional
#'
#' @export
aiR <- function(data,
input.col,
var.classify,
aiRnet,
cycles = 100,
sample.method="Sample",
sample.size=.5,
batch.size="all",
sample.Factor = NULL,
na.rm=TRUE,
test.rate = "fast") {
if(!is.aiRnet(aiRnet)){
stop("aiRnet must be of class \"aiRnet\"")
}
if(!all(input.col%in%colnames(data))){
mesg <- paste0(paste0("\"",input.col[!input.col%in%colnames(data)],"\""), collapse = ", ")
stop(paste("Error: the following character(s) are not found in data header:", mesg,""))
}
if(!all(unlist(lapply(data[,input.col], is.numeric)))){
stop(paste("At least 1 column in input.col is not a numeric vector"))
}
n <- length(aiRnet) #how many layers
classify.vec <- data[[var.classify]]
if(isTRUE(na.rm)) {
data <- na.exclude(data)
} else {
warning("na.rm set to FALSE, NA values not sutable for matrix multiplication. Set NA to place holder value.")
}
# if(!is.element(test, c(TRUE,FALSE))) {
# stop("test must be either TRUE or FALSE")
# }
# if(!is.element(data.return, c(TRUE,FALSE))) {
# stop("data.return must be either TRUE or FALSE")
# }
if(!is.factor(classify.vec)) {
stop("var.classify must be assigned a factor vector as a classification variable.")
} else {
class.levels <- levels(classify.vec) #variable.. recording levels of classification vector.
}
#How much of data is training, what method to train against
sample.rows <- aiRsubset(x = data,
sample.method = sample.method,
sample.size = sample.size,
sample.Factor = sample.Factor)
if(batch.size=="all"){
batch.size <- sum(sample.rows)
}
if(is.element(test.rate, set = c("none","fast","slow"))){
if(test.rate=="none"){
modularTest <- cycles+1
} else if(test.rate=="fast"){
modularTest <- cycles
} else if(test.rate=="slow"){
modularTest <- 1
}
} else if(is.numeric(test.rate)&&test.rate%%1==0){
modularTest <- test.rate
} else {
stop("test.rate must be a non-zero integer or \"none\", or \"fast\", \"slow\".")
}
data <- data[,c(input.col)]
data_train <- data[sample.rows,]
classify_train.vec <- classify.vec[sample.rows]
if(sample.size<0.8){
data_test <- data[!sample.rows,]
classify_test.vec <- classify.vec[!sample.rows]
} else {
data_test <- data
classify_test.vec <- classify.vec
}
#Decide what to do with test variable and test.rate variable
aiRobj <- aiRrun(data_train = data_train,
data_test = data_test,
classify_train.vec = classify_train.vec,
classify_test.vec = classify_test.vec,
class.levels = class.levels,
aiRnet = aiRnet,
cycles = cycles,
batch.size = batch.size,
modularTest = modularTest)
return(aiRobj)
}
#' @name aiRrun
#'
#' @title aiRrun
#'
#' @description handles the activation and back propigation of the network.
#'
#' @param data_train training dataset
#' @param data_test testing dataset
#' @param aiRnet aiRnet object to be trained
#' @param classify_train.vec vector of training classifiers
#' @param classify_test.vec vector of test calssifiers
#' @param class.levels the levels of the classifier vector
#' @param cycles number of iterations done
#' @param batch.size number of samples taken at a time in a batch
#' @param modularTest How many cycles pass before the aiRnet is used on data_test
#'
#' @return list of aiRnet and dataframe
aiRrun <- function(data_train,
data_test,
aiRnet,
classify_train.vec,
classify_test.vec,
class.levels,
cycles,
batch.size,
modularTest){
#subdivide into batches
batches <- aiRbatch(data = data_train, batch.size = batch.size)
nb <- length(batches)
tot.cost <- numeric(cycles)
mean.cost <- numeric(cycles)
test.cost <- rep(NA,cycles)
n <- length(aiRnet)+1
#test model
aiRbest <- aiRnet
min.cost <- batch.size*ncol(data_train)
for(i in 1:cycles){
if(i==1||i%%modularTest==0){
testActiv <- aiRactivation(data = data_test, aiRnet = aiRnet)
testCost <- aiRcost(data = testActiv[[n]], class.levels = class.levels, classify = classify_test.vec)
test.cost[i] <- testCost$mean.cost
}
if(i%%nb==0){
b <- batches[[nb]]
batches <- aiRbatch(data = data_train, batch.size = batch.size)
} else {
b <- batches[[i%%nb]]
}
#find activation
aiRactiv <- aiRactivation(data = data_train[b,], aiRnet = aiRnet)
# find cost
aiRcost <- aiRcost(data = aiRactiv[[n]], class.levels = class.levels, classify = classify_train.vec[b])
tot.cost[i] <- aiRcost$total.cost
mean.cost[i] <- aiRcost$mean.cost
if(tot.cost[i]==min(tot.cost[i],min.cost)){
aiRbest <- aiRnet
}
newaiR <- backprop(aiRnet = aiRnet, aiRcost = aiRcost, aiRactivation = aiRactiv)
aiRnet <- aiRfresh(aiRnet = newaiR)
svMisc::progress(i, max.value = cycles, progress.bar = T)
}
d <- data.frame(cycles = 1:cycles, tot.cost = tot.cost, mean.cost = mean.cost, test.cost = test.cost)
#ggplot(data = NULL, aes(x = 1:cycles, y = tot.cost)) + geom_point()
ret <- list(aiRnet,aiRbest, d)
names(ret) <- c("aiRnet","aiRbest","Cost")
class(ret) <- "aiR"
return(ret)
}
#' @name aiRactivation
#'
#' @title aiRactivation
#'
#' @description calculates and saves the activation of the network.
#'
#' @param data datasets to pass through model
#' @param aiRnet aiRnet object to be trained
#'
#' @return returns a list of length(aiRnet)+1 where the first index is data. Subsequent indexes show
#' the activation levels of neurons per data observation. May be helpful in data visualization.
#'
#' @export
aiRactivation <- function(aiRnet, data) {
#
if(!is.aiRnet(aiRnet)){
stop("aiRnet must be of class \"aiRnet\"")
}
n <- length(aiRnet)
l <- list(n+1)
l[[1]] <- data
for(i in 2:(n+1)) { #Transform data through aiRnet
data <- as.matrix(data)%*%aiRnet[[i-1]]$weights
data <- mat.opperation(x = data, y = aiRnet[[i-1]]$bias, opperation = "+")
data <- sigmoid(data)
l[[i]] <- data
}
l[[n+1]] <- apply(l[[n+1]],2,zero)
names(l) <- c("data",paste0("layer",1:n))
class(l) <- "aiRactivation"
return(l)
}
#' @name aiRcost
#'
#' @title aiRcost
#'
#' @description Calculates the resulting cost of the network for a given dataset activation.
#'
#' @param data takes in final activation level of a network.
#' @param classify Factor vector of correct classifications corresponding to data observations.
#' @param class.levels the levels of the classifier vector
#'
#' @return returns aiRcost object containing the following labels cost, dcost, obser.cost, total.cost, mean.cost
#' cost: cost per value,
#' dcost: differential cost per value,
#' obser.cost: cost per observation,
#' total.cost: batch total cost,
#' mean.cost: batch mean cost
#'
#' @export
aiRcost <- function(data, classify, class.levels) {
class.mat <- diag(nrow = length(class.levels),ncol = length(class.levels))
correct <- class.mat[classify,]
cost <- (data-correct)^2
dcost <- 2*(data-correct)
dsig <- dsigmoid(data)
if(is.null(dim(cost))){
obs.cost <- sum(cost)
} else {
obs.cost <- apply(cost,1,sum)
}
total.cost <- sum(obs.cost)
mean.cost <- mean(obs.cost)
ret <- list(cost, dcost, obs.cost, total.cost, mean.cost)
names(ret) <- c("cost","dcost","obser.cost","total.cost", "mean.cost")
class(ret) <- "aiRcost"
return(ret)
}
#' @name backprop
#'
#' @title backprop
#'
#' @param aiRnet aiRnet object
#' @param aiRcost aiRcost object
#' @param aiRactivation aiRactivation object
#'
#' @return returns aiRnet with change.w and change.b values filled
backprop <- function(aiRnet, aiRcost, aiRactivation) {
#
n <- length(aiRactivation)
n.obs <- nrow(aiRactivation[[n]])
gencost <- aiRcost$dcost*dsigmoid(aiRactivation[[n]])
# cost.vec <- cost.vec*scales::rescale(abs(cost.vec), c(1,2))
deltaW <- t(aiRactivation[[n-1]])%*%gencost/n.obs
deltaA <- gencost%*%t(aiRnet[[n-1]]$weights)
deltaB <- unname(apply(gencost,2, mean))
# start.adjust <- aiRactivation[[n-1]]*cost.vec
aiRnet[[n-1]]$change.w <- deltaW
aiRnet[[n-1]]$change.b <- deltaB
if(n>2){
for(i in (n-1):2){
gencost <- deltaA*dsigmoid(aiRactivation[[i]])
# start.adjust <- aiRactivation[[i-1]]*cost.vec
deltaW <- t(aiRactivation[[i-1]])%*%gencost/n.obs
deltaA <- gencost%*%t(aiRnet[[i-1]]$weights)
deltaB <- apply(gencost,2, mean)
aiRnet[[i-1]]$change.w <- deltaW #ideally we wouldnt do the apply
aiRnet[[i-1]]$change.b <- deltaB
}
}
return(aiRnet)
}
#' @name aiRfresh
#'
#' @title aiRfresh
#'
#' @description applies the changes of change.w and change.b to the layer's respective
#' weights and biasis
#'
#' @param aiRnet aiRnet object
#'
#' @return aiRnet object adjusted via change.w and change.b
aiRfresh <- function(aiRnet){
n <- length(aiRnet)
for(i in 1:n){
aiRnet[[i]]$weights <- aiRnet[[i]]$weights - aiRnet[[i]]$change.w
aiRnet[[i]]$bias <- aiRnet[[i]]$bias - aiRnet[[i]]$change.b
aiRnet[[i]]$change.w <- aiRnet[[i]]$change.w*0
aiRnet[[i]]$change.b <- aiRnet[[i]]$change.b*0
}
return(aiRnet)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.