Rev 6394 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** These routines interface via the rpart_callback routine to* provide for user-written split functions*/#include "rpart.h"#include "rpartproto.h"static int n_return; /* number of return values from the eval fcn */static double *uscratch; /* variously used scratch vector */intusersplit_init(int n, double *y[], int maxcat, char **error,double *parm, int *size, int who, double *wt){if (who == 1) {/* If who==0 we are being called internally via xval, and don't* need to rerun the initialization.* Call-back to the C code to get the number of columns for y and* the length of the return vector* the scratch vector needed is of length max(2n, nreturn+1)*/rpart_callback0(&n_return);uscratch = (double *) ALLOC(n_return + 1 > 2 * n ? n_return + 1 : 2 *n,sizeof(double));}*size = n_return;return 0;}/** The user evaluation function*/voidusersplit_eval(int n, double *y[], double *value, double *risk, double *wt){int i;rpart_callback1(n, y, wt, uscratch);*risk = uscratch[0];for (i = 0; i < n_return; i++)value[i] = uscratch[i + 1];}/** Call the user-supplied splitting function.*/voidusersplit(int n, double *y[], double *x, int nclass, int edge,double *improve, double *split, int *csplit, double myrisk,double *wt){int i, j, k;int m;int left_n, right_n;int where = 0;double best;double *dscratch;double ftemp;/** If it's categorical, and all are tied, don't bother to callback.* (Completely tied continuous is caught earlier than this).* (This isn't common, but callbacks are expensive).*/if (nclass > 0) {ftemp = x[0];for (i = 1; i < n; i++)if (x[i] != ftemp)break;if (i == n) {*improve = 0.0;return;}}/** get the vector of "goodness of split"* on return uscratch contains the goodness for each split* followed by the 'direction'*/rpart_callback2(n, nclass, y, wt, x, uscratch);if (nclass == 0) {/** Find the split point that has the best goodness, subject* to the edge criteria, and tied x's *Remember, uscratch[0]* contains the goodnes for x[0] left, and all others right,* so has n-1 real elements. *The 'direction' vector is* returned pasted onto the end of uscratch.*/dscratch = uscratch + n - 1;best = 0;for (i = edge - 1; i < n - edge; i++) {if ((x[i] < x[i + 1]) && (uscratch[i] > best)) {best = uscratch[i];where = i;}}if (best > 0) { /* found something */csplit[0] = (int) dscratch[where];*split = (x[where] + x[where + 1]) / 2;}} else {/** Categorical -- somewhat more work to be done here to* guarantee the edge criteria.* The return vector uscratch has first the number of categories* that were found (call it m), then m-1 goodnesses, then m labels* in order, and the assurance that the best split is one of* those that use categories in that order.*/for (i = 0; i < nclass; i++)csplit[i] = 0;best = 0;m = (int) uscratch[0];dscratch = uscratch + m;where = -1;left_n = 0;for (i = 1; i < m; i++) {k = (int) dscratch[i - 1]; /* the next group of interest */for (j = 0; j < n; j++)if (x[j] == k)left_n++;right_n = n - left_n;if (right_n < edge)break;if (where < 0 || uscratch[i] > best) {best = uscratch[i];where = i;}}/** Now mark the groups as to left/right* If there was no way to split it with at least 'edge' in each* group, best will still = 0.*/if (best > 0) {for (i = 0; i < m; i++) {k = (int) dscratch[i]; /* the next group of interest */if (i < where)csplit[k - 1] = LEFT;elsecsplit[k - 1] = RIGHT;}}}*improve = best;}/** We don't do in-C cross validation for user splits, so there* is no prediction routine.* (Because of the structure of the calls, it's faster to make* use of xpred.rpart for user-written split routines).*/doubleusersplit_pred(double *y, double *yhat){return 0.0;}