knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
data(package="mlbench") data(Sonar, package="mlbench") data(DNA, package="mlbench") data(spam, package="kernlab") data.list <- list( spam=list( input.mat=as.matrix(spam[1:57]), output.vec=ifelse(spam$type=="spam", 1, -1)), Sonar=list( input.mat=as.matrix(Sonar[,1:60]), output.vec=ifelse(Sonar$Class=="R", 1, -1)), DNA=list( input.mat=ifelse(as.matrix(DNA[,1:180])==0, 0, 1), output.vec=ifelse(DNA$Class=="n", -1, 1)))
N <- 10 set.seed(1) rand.pred.vec <- rnorm(N) subtrain.output.vec <- rep(c(-1, 1), l=N) subtrain.diff.count.dt <- aum::aum_diffs_binary(subtrain.output.vec, denominator="count") subtrain.diff.rate.dt <- aum::aum_diffs_binary(subtrain.output.vec, denominator="rate") library(data.table) PairsDT <- function(output.vec){ is.positive <- output.vec == 1 data.table(expand.grid( positive=which(is.positive), negative=which(!is.positive))) } subtrain.pairs.dt <- PairsDT(subtrain.output.vec) margin <- 1 ## Note: for efficiency subtrain labels are assumed to be pre-computed ## in the enclosing environment, once before the optimization starts. equal.class.weights <- function(output.vec){ otab <- table(output.vec) as.numeric(1/otab[paste(output.vec)]) } subtrain.obs.weights <- equal.class.weights(subtrain.output.vec) Logistic <- function(pred.vec, output.vec, obs.weights){ list( gradient=-obs.weights*output.vec/(1+exp(output.vec*pred.vec)), loss=sum(obs.weights*log(1+exp(-output.vec*pred.vec)))) } AUM <- function(pred.vec, diff.dt){ L <- aum::aum(diff.dt, pred.vec) d <- L$derivative_mat non.diff <- abs(d[,1] - d[,2]) > 1e-6 if(any(non.diff)){ cat(sprintf("%d non-diff points\n", sum(non.diff))) print(d[non.diff, ]) } with(L, list(gradient=derivative_mat[,1], loss=aum)) } loss.list <- list( logistic=function(pred.vec, output.vec=subtrain.output.vec, ...){ Logistic(pred.vec, output.vec, 1/length(pred.vec)) }, logistic.weighted= function(pred.vec, output.vec=subtrain.output.vec, obs.weights=subtrain.obs.weights, ...){ Logistic(pred.vec, output.vec, obs.weights) }, aum.count=function(pred.vec, diff.count.dt=subtrain.diff.count.dt, ...){ AUM(pred.vec, diff.count.dt) }, aum.rate=function(pred.vec, diff.rate.dt=subtrain.diff.rate.dt, ...){ AUM(pred.vec, diff.rate.dt) }, squared.hinge.all.pairs=function(pred.vec, pairs.dt=subtrain.pairs.dt, ...){ pairs.dt[, diff := pred.vec[positive]-pred.vec[negative]-margin] pairs.dt[, diff.clipped := ifelse(diff<0, diff, 0)] pairs.tall <- data.table::melt( pairs.dt, measure.vars=c("positive", "negative"), value.name="pred.i", variable.name="label") ## d/dx (x - y - m)^2 = x - y - m ## d/dy (x - y - m)^2 = -(x - y - m) pairs.tall[, grad.sign := ifelse(label=="positive", 1, -1)] N.pairs <- nrow(pairs.dt) grad.dt <- pairs.tall[, .( gradient=sum(grad.sign*diff.clipped) ), keyby=pred.i] list( gradient=grad.dt$gradient/N.pairs, loss=sum(pairs.dt$diff.clipped^2)/N.pairs) } ) result.list <- list() for(loss.name in names(loss.list)){ fun <- loss.list[[loss.name]] result.list[[loss.name]] <- fun(rand.pred.vec) } str(result.list) sapply(result.list, "[[", "gradient")
out.loss.list <- list() data.name <- "Sonar" input.output.list <- data.list[[data.name]] input.mat <- input.output.list[["input.mat"]] full.input.mat <- scale(input.mat) full.output.vec <- input.output.list[["output.vec"]] stopifnot(full.output.vec %in% c(-1, 1)) set.seed(1) n.folds <- 2 unique.folds <- 1:n.folds fold.vec <- sample(rep(unique.folds, l=length(full.output.vec))) validation.fold <- 1 is.set.list <- list( validation=fold.vec == validation.fold, subtrain=fold.vec != validation.fold) set.data.list <- list() for(set.name in names(is.set.list)){ is.set <- is.set.list[[set.name]] output.vec <- full.output.vec[is.set] set.data.list[[set.name]] <- list( output.vec=output.vec, obs.weights=equal.class.weights(output.vec), input.mat=full.input.mat[is.set,], diff.rate.dt=aum::aum_diffs_binary(output.vec, denominator="rate"), diff.count.dt=aum::aum_diffs_binary(output.vec, denominator="count"), pairs.dt=PairsDT(output.vec)) } X.mat <- set.data.list$subtrain$input.mat for(loss.name in names(loss.list)){ loss.grad.fun <- loss.list[[loss.name]] step.size <- 0.1 cat(sprintf("loss=%s\n", loss.name)) set.seed(1) weight.vec <- last.w <- rnorm(ncol(X.mat)) done <- FALSE iteration <- 0 prev.set.loss.vec <- rep(1e10, 2) while(!done){ iteration <- iteration+1 loss.for.weight <- function(w, set.data=set.data.list$subtrain){ pred <- set.data$input.mat %*% w set.data$pred.vec <- pred out <- do.call(loss.grad.fun, set.data) out$pred <- pred out } loss.before.step <- loss.for.weight(weight.vec) direction <- -t(X.mat) %*% loss.before.step[["gradient"]] loss.for.step <- function(step.size){ new.weight <- weight.vec + step.size * direction out <- loss.for.weight(new.weight) out$new.weight <- new.weight out$step.size <- step.size out } loss.after.step <- loss.for.step(step.size) weight.vec <- loss.after.step[["new.weight"]] diff.w <- sum(abs(weight.vec-last.w)) last.w <- weight.vec set.loss.vec <- numeric() for(set.name in names(set.data.list)){ set.data <- set.data.list[[set.name]] set.loss <- loss.for.weight(weight.vec, set.data) set.loss.vec[[set.name]] <- set.loss[["loss"]] roc.df <- WeightedROC::WeightedROC( set.loss[["pred"]], set.data[["output.vec"]]) auc <- WeightedROC::WeightedAUC(roc.df) out.dt <- data.table( loss.name, iteration, set.name, auc, loss.value=set.loss$loss) for(aum.type in c("count", "rate")){ diff.name <- paste0("diff.", aum.type, ".dt") aum.list <- aum::aum(set.data[[diff.name]], set.loss[["pred"]]) out.col <- paste0("aum.", aum.type) out.dt[[out.col]] <- aum.list[["aum"]] } out.loss.list[[paste( loss.name, iteration, set.name )]] <- out.dt if(2000 < iteration || diff.w < 1e-6){ done <- TRUE } }#for(set.name }#while(!done }#for(loss.name out.loss <- do.call(rbind, out.loss.list) (max.valid.auc <- out.loss[ set.name=="validation", .SD[which.max(auc), .(iteration, auc, set.name)], by=.(loss.name)]) library(ggplot2) ggplot(,aes( iteration, auc, color=set.name))+ geom_line( data=out.loss)+ geom_point( data=max.valid.auc)+ facet_grid( . ~ loss.name, labeller="label_both", scales='free', space='fixed')
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.