The R Project SVN R-packages

Rev

Rev 6464 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/*
 * nodesplit -- Split the node in two, and keep a count as we do of how
 *  many splits are determined by each surrogate variable.
 *
 * me     : pointer to the node of the tree
 * nodenum: the node number of the current node, used to update "which"
 * n1, n2 : starting and ending indices for the observation numbers
 * nnleft, nnright: at the end, how many obs were sent to the left and
 *            to the right.  Beware-  for certain settings of the
 *            usesurrogate option, some obs go neither left nor right
 */
#include "rpart.h"
#include "node.h"
#include "rpartproto.h"
#include <stdio.h>

void
nodesplit(pNode me, int nodenum, int n1, int n2, int *nnleft, int *nnright)
{
    int i, j, k;
    pSplit tsplit;
    int var, extra, lastisleft, someleft;
    int i1, i2, i3;
    int leftson, rightson;
    int pvar;
    double psplit;
    int *index;
    int *which;
    int **sorts;
    int *sindex;                /* sindex[i] is a shorthand for sorts[var][i] */
    double **xdata;
    int nleft, nright;
    //int           dummy;      /* debugging */

    which = rp.which;
    sorts = rp.sorts;
    xdata = rp.xdata;
    leftson = 2 * nodenum;      /* the label that will go with the left son */
    rightson = leftson + 1;

    /*
     * Walk through the variables (primary, then surrogate 1, then surr 2...)
     *   and reassign "which"
     */
    tsplit = me->primary;
    pvar = tsplit->var_num;     /* primary variable */
    someleft = 0;
    nleft = 0;
    nright = 0;

    if (rp.numcat[pvar] > 0) {  /* categorical primary variable */
    index = tsplit->csplit;
    for (i = n1; i < n2; i++) {
        j = sorts[pvar][i];
        if (j < 0)
        someleft++;     /* missing value */
        else
        switch (index[(int) xdata[pvar][j] - 1]) {
        case LEFT:
            which[j] = leftson;
            nleft++;
            break;
        case RIGHT:
            which[j] = leftson + 1;
            nright++;
            break;
        }
    }
    } else {
    psplit = tsplit->spoint;        /* value of split point */
    extra = tsplit->csplit[0];
    for (i = n1; i < n2; i++) {
        j = sorts[pvar][i];
        if (j < 0)
        someleft++;
        else {
        if (xdata[pvar][j] < psplit)
            k = extra;
        else
            k = -extra;
        if (k == LEFT) {
            which[j] = leftson;
            nleft++;
        } else {
            which[j] = leftson + 1;
            nright++;
        }
        }
    }
    }

    /*
     * Now the surrogates
     *   Usually, there aren't a lot of observations that need to
     *   be split.  So it is more efficient to make one 1:n pass,
     *   with multiple runs through the surrogate list.
     */
    if (someleft > 0 && rp.usesurrogate > 0) {
    for (i = n1; i < n2; i++) {
        j = rp.sorts[pvar][i];
        if (j >= 0)
        continue;       /* already split */

        j = -(j + 1);       /* obs number - search for surrogates */
        for (tsplit = me->surrogate; tsplit; tsplit = tsplit->nextsplit) {
        var = tsplit->var_num;
        if (!R_FINITE(xdata[var][j]))
            continue;
        /* surrogate not missing - process it */

        if (rp.numcat[var] > 0) {       /* categorical surrogate */
            index = tsplit->csplit;
            k = (int) xdata[var][j];    /* the value of the surrogate  */
            /*
             * The need for the if stmt below may not be obvious.
             * The surrogate's value must not be missing, AND there
             * must have been at least 1 person with both this
             * level of the surrogate and a primary split value
             * somewhere in the node.  If everyone in this node
             * with level k of the surrogate also had a missing
             * value of the primary variable, then index[k-1] will
             * be zero.
             */
            if (index[k - 1]) {
            tsplit->count++;
            if (index[k - 1] == LEFT) {
                which[j] = leftson;
                nleft++;
            } else {
                which[j] = leftson + 1;
                nright++;
            }
            someleft--;
            break;
            }
        } else {
            psplit = tsplit->spoint;    /* continuous surrogate */
            extra = tsplit->csplit[0];
            tsplit->count++;
            if (xdata[var][j] < psplit)
            k = extra;
            else
            k = -extra;
            if (k == LEFT) {
            which[j] = leftson;
            nleft++;
            } else {
            which[j] = rightson;
            nright++;
            }
            someleft--;
            break;
        }
        }
    }
    }
    if (someleft > 0 && rp.usesurrogate == 2) {
    /* all surrogates missing, use the default */
    i = me->lastsurrogate;
    if (i) {           /* 50-50 splits are possible - there is no
                * "default" */
        if (i < 0) {
        lastisleft = leftson;
        nleft += someleft;
        } else {
        lastisleft = rightson;
        nright += someleft;
        }

        for (i = n1; i < n2; i++) {
        j = sorts[pvar][i];
        /*
         * only those who weren't split by the primary (j < 0) and
         * weren't split by a surrogate (which == nodenum) need to be
         * assigned
         */
        if (j < 0) {
            j = -(j + 1);
            if (which[j] == nodenum)
            which[j] = lastisleft;
        }
        }
    }
    }
    /*
     * Last part of the work is to update the sorts matrix
     *
     * Say that n1=5, n2=12, 4 go left, 3 go right, and one obs
     *   stays home, and the data looks like this:
     *
     *   sorts[var][5] = 17    which[17]= 17 = 2*nodenum +1 = rightson
     *       "            4    which[4] = 16 = 2*nodenum    = leftson
     *                   21          21   16
     *                    6           6   17
     *      "         7           7   16
     *                   30          30   17
     *                    8           8   16
     *  sorts[var][12]= -11    which[11] = 8 = nodenum  (X = missing)
     *
     *  Now, every one of the rows of the sorts contains these same
     *    elements -- 4,6,7,8,11,17,21,30 -- in some order, which
     *    represents both how they are sorted and any missings via
     *    negative numbers.
     *  We need to reorder this as {{goes left}, {goes right}, {stays
     *    here}}, preserving order within the first two groups.  The
     *    order within the "stay here" group doesn't matter since they
     *    won't be looked at again for splitting.
     *  So the result in this case should be
     *       4, 21, 7, 8,   17, 6, 30,  -11
     *  The algorithm is the opposite of a merge sort.
     *
     *  Footnote: if no surrogate variables were used, then one could
     *   skip this process for the primary split variable, as that
     *   portion of "sorts" would remain unchanged.  It's not worth
     *   the bother of checking, however.
     */
    for (k = 0; k < rp.nvar; k++) {
    sindex = rp.sorts[k];   /* point to variable k */
    i1 = n1;
    i2 = i1 + nleft;
    i3 = i2 + nright;
    for (i = n1; i < n2; i++) {
        j = sindex[i];
        if (j < 0)
        j = -(j + 1);
        if (which[j] == leftson)
        sindex[i1++] = sindex[i];
        else {
        if (which[j] == rightson)
            rp.tempvec[i2++] = sindex[i];
        else
            rp.tempvec[i3++] = sindex[i];       /* went nowhere */
        }
    }
    for (i = n1 + nleft; i < n2; i++)
        sindex[i] = rp.tempvec[i];
    }

    *nnleft = nleft;
    *nnright = nright;
}