Rev 6380 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
## This routine sets up the callback code for user-written split## routines in rpart##rpartcallback <- function(mlist, nobs, init){if (length(mlist) < 3L)stop("User written methods must have 3 functions")if (!is.function(mlist$init))stop("User written method does not contain an 'init' function")if (!is.function(mlist$split))stop("User written method does not contain a 'split' function")if (!is.function(mlist$eval))stop("User written method does not contain an 'eval' function")user.eval <- mlist$evaluser.split <- mlist$splitnumresp <- init$numrespnumy <- init$numyparms <- init$parms#### expr2 is an expression that will call the user "evaluation"## function, and check that what comes back is valid## expr1 does the same for the user "split" function#### For speed in the C interface, yback, xback, and wback are## fixed S vectors of a fixed size, and nback tells us how## much of the vector is actually being used on this particular## callback.##if (numy == 1L) {expr2 <- quote({temp <- user.eval(yback[1:nback], wback[1:nback], parms)if (length(temp$label) != numresp)stop("User 'eval' function returned invalid label")if (length(temp$deviance) != 1L)stop("User 'eval' function returned invalid deviance")as.numeric(as.vector(c(temp$deviance, temp$label)))})expr1 <- quote({if (nback < 0L) { #categorical variablen2 <- -nbacktemp <- user.split(yback[1L:n2], wback[1L:n2],xback[1L:n2], parms, FALSE)ncat <- length(unique(xback[1L:n2]))if (length(temp$goodness) != ncat - 1L ||length(temp$direction) != ncat)stop("Invalid return from categorical 'split' function")} else {temp <- user.split(yback[1L:nback], wback[1L:nback],xback[1L:nback], parms, TRUE)if (length(temp$goodness) != (nback - 1L))stop("User 'split' function returned invalid goodness")if (length(temp$direction) != (nback - 1L))stop("User 'split' function returned invalid direction")}as.numeric(as.vector(c(temp$goodness, temp$direction)))})} else {expr2 <- quote({tempy <- matrix(yback[1L:(nback * numy)], ncol = numy)temp <- user.eval(tempy, wback[1L:nback], parms)if (length(temp$label) != numresp)stop("User 'eval' function returned invalid label")if (length(temp$deviance) != 1L)stop("User 'eval' function returned invalid deviance")as.numeric(as.vector(c(temp$deviance, temp$label)))})expr1 <- quote({if (nback < 0L) { #categorical variablen2 <- -nbacktempy <- matrix(yback[1L:(n2 * numy)], ncol = numy)temp <- user.split(tempy, wback[1L:n2], xback[1L:n2],parms, FALSE)ncat <- length(unique(xback[1L:n2]))if (length(temp$goodness) != ncat - 1L ||length(temp$direction) != ncat)stop("Invalid return from categorical 'split' function")} else {tempy <- matrix(yback[1L:(nback * numy)], ncol = numy)temp <- user.split(tempy, wback[1:nback], xback[1L:nback],parms, TRUE)if (length(temp$goodness) != (nback - 1L))stop("User 'split' function returned invalid goodness")if (length(temp$direction) != (nback - 1L))stop("User 'split' function returned invalid direction")}as.numeric(as.vector(c(temp$goodness, temp$direction)))})}#### The vectors nback, wback, xback and yback will have their## contents constantly re-inserted by C code. It's one way to make## things very fast. It is dangerous to do this, so they## are tossed into a separate frame to isolate them. Evaluations of## the above expressions occur in that frame.##rho <- new.env()assign("nback", integer(1L), envir = rho)assign("wback", double(nobs), envir = rho)assign("xback", double(nobs), envir = rho)assign("yback", double(nobs * numy), envir = rho)assign("user.eval", user.eval, envir = rho)assign("user.split", user.split, envir = rho)assign("numy", numy, envir = rho)assign("numresp", numresp, envir = rho)assign("parms", parms, envir = rho).Call(C_init_rpcallback, rho, as.integer(numy), as.integer(numresp),expr1, expr2)list(expr1 = expr1, expr2 = expr2, rho = rho)}