Rev 6700 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** The routines for gini-classification*/#include <math.h>#include "rpart.h"#include "rpartproto.h"static int numclass;static double *left, /* left branch n (weighted) */*right, **ccnt;static double *prior, *aprior, /* altered priors */*freq, *loss; /* loss matrix */static int *tsplit, *countn;static double *awt, *rate;static double (*impurity) ();static doublegini_impure1(double p){return p * (1.0 - p);}static doublegini_impure2(double p){if (p == 0) return 0.0; else return -p * log(p);}intginiinit(int n, double **y, int maxcat, char **error,double *parm, int *size, int who, double *wt){int i, j, k;double temp;/* allocate memory and setup losses */if (who == 1) {numclass = 0; /* number of classes */for (i = 0; i < n; i++)if (*y[i] > numclass)numclass = (int) *y[i];if (parm[numclass + numclass * numclass] == 2)impurity = gini_impure2;elseimpurity = gini_impure1;left = (double *) ALLOC(numclass * 2, sizeof(double));right = left + numclass;tsplit = (int *) ALLOC(maxcat * 2, sizeof(int));countn = tsplit + maxcat;awt = (double *) ALLOC(maxcat * 2, sizeof(double));rate = awt + maxcat;if (maxcat > 0) {graycode_init0(maxcat);ccnt = (double **) ALLOC(numclass, sizeof(double *));ccnt[0] = (double *) ALLOC(numclass * maxcat, sizeof(double));for (i = 1; i < numclass; i++)ccnt[i] = ccnt[i - 1] + maxcat;}i = 3 * numclass + numclass * numclass;prior = (double *) ALLOC(i, sizeof(double));aprior = prior + numclass;freq = aprior + numclass;loss = freq + numclass;for (i = 0; i < numclass; i++)freq[i] = 0;temp = 0;for (i = 0; i < n; i++) {j = (int) *y[i] - 1;freq[j] += wt[i];temp += wt[i]; /* sum total of weights */}for (i = 0; i < numclass; i++)freq[i] /= temp; /* relative frequency */temp = 0;for (i = 0; i < numclass; i++) {prior[i] = parm[i];aprior[i] = 0;for (j = 0; j < numclass; j++) {k = numclass * j + i;loss[k] = parm[numclass + k];temp += loss[k] * prior[i];aprior[i] += loss[k] * prior[i];}}for (i = 0; i < numclass; i++) {if (freq[i] > 0) { /* watch out for a missing class */prior[i] /= freq[i];aprior[i] /= (temp * freq[i]); /* pi_i / n_i */}}}*size = 2 + numclass;return 0;}/** Compute the predicted response and the classification error* This is R(T) (this node's contribution) in the paper.*/voidginidev(int n, double **y, double *value, double *risk, double *wt){int i, j, max = 0;double temp, dev = 0;double prob;/** count up number in each class,* and P(T), the probability of reaching this branch of the tree*/for (i = 0; i < numclass; i++)freq[i] = 0;temp = 0;for (i = 0; i < n; i++) {j = (int) y[i][0] - 1;freq[j] += wt[i];temp += wt[i] * prior[j];}prob = temp; /* this is actually P(T)*n; R code will fix* it up *//** Now compute best class and its error*/for (i = 0; i < numclass; i++) { /* assume class i were the prediction */temp = 0;for (j = 0; j < numclass; j++)temp += freq[j] * loss[i * numclass + j] * prior[j];if (i == 0 || temp < dev) {max = i;dev = temp;}}value[0] = max + 1; /* remember: external groups start at 1 */for (i = 0; i < numclass; i++)value[i + 1] = freq[i];value[numclass + 1] = prob;*risk = dev;}/** return the error for a particular point*/doubleginipred(double *y, double *pred){int i, j;double temp;i = (int) y[0] - 1;j = (int) *pred - 1;temp = prior[i] * loss[i * numclass + j];return temp;}/** The gini splitting function. Find that split point in x such that* the rss within the two groups is decreased as much* as possible.*/voidgini(int n, double *y[], double *x, int numcat,int edge, double *improve, double *split, int *csplit, double my_risk,double *wt){int i, j, k;double lwt, rwt;int rtot, ltot;int direction = LEFT, where = 0;double total_ss, best, temp, p;double lmean, rmean; /* used to decide direction */for (i = 0; i < numclass; i++) {left[i] = 0;right[i] = 0;}lwt = 0;rwt = 0;rtot = 0;ltot = 0;for (i = 0; i < n; i++) {j = (int) *y[i] - 1;rwt += aprior[j] * wt[i]; /* altered weight = prior * case_weight */right[j] += wt[i];rtot++;}total_ss = 0;for (i = 0; i < numclass; i++) {temp = aprior[i] * right[i] / rwt; /* p(class=i, given node A) */total_ss += rwt * (*impurity) (temp); /* p(A) * I(A) */}best = total_ss; /* total weight of right * impurity of right + 0 *0 *//** at this point we split into 2 disjoint paths*/if (numcat > 0)goto categorical;for (i = 0; rtot > edge; i++) {j = (int) *y[i] - 1;rwt -= aprior[j] * wt[i];lwt += aprior[j] * wt[i];rtot--;ltot++;right[j] -= wt[i];left[j] += wt[i];if (ltot >= edge && x[i + 1] != x[i]) {temp = 0;lmean = 0;rmean = 0;for (j = 0; j < numclass; j++) {p = aprior[j] * left[j] / lwt; /* p(j | left) */temp += lwt * (*impurity) (p); /* p(left) * I(left) */lmean += p * j;p = aprior[j] * right[j] / rwt; /* p(j | right) */temp += rwt * (*impurity) (p); /* p(right) * I(right) */rmean += p * j;}if (temp < best) {best = temp;where = i;direction = lmean < rmean ? LEFT : RIGHT;}}}*improve = total_ss - best;if (*improve > 0) { /* found something */csplit[0] = direction;*split = (x[where] + x[where + 1]) / 2;}return;categorical:;/** First collapse the data into a numclass x numcat array* ccnt[i][j] = number of class i obs, category j of the predictor*/for (j = 0; j < numcat; j++) {awt[j] = 0;countn[j] = 0;for (i = 0; i < numclass; i++)ccnt[i][j] = 0;}for (i = 0; i < n; i++) {j = (int) *y[i] - 1;k = (int) x[i] - 1;awt[k] += aprior[j] * wt[i];countn[k]++;ccnt[j][k] += wt[i];}for (i = 0; i < numcat; i++) {if (awt[i] == 0)tsplit[i] = 0;else {rate[i] = ccnt[0][i] / awt[i]; /* a scratch array */tsplit[i] = RIGHT;}}if (numclass == 2)graycode_init2(numcat, countn, rate);elsegraycode_init1(numcat, countn);while ((i = graycode()) < numcat) {/* item i changes groups */if (tsplit[i] == LEFT) {tsplit[i] = RIGHT;rwt += awt[i];lwt -= awt[i];rtot += countn[i];ltot -= countn[i];for (j = 0; j < numclass; j++) {right[j] += ccnt[j][i];left[j] -= ccnt[j][i];}} else {tsplit[i] = LEFT;rwt -= awt[i];lwt += awt[i];rtot -= countn[i];ltot += countn[i];for (j = 0; j < numclass; j++) {right[j] -= ccnt[j][i];left[j] += ccnt[j][i];}}if (ltot >= edge && rtot >= edge) {temp = 0;lmean = 0;rmean = 0;for (j = 0; j < numclass; j++) {p = aprior[j] * left[j] / lwt;temp += lwt * (*impurity) (p);lmean += p * j;p = aprior[j] * right[j] / rwt; /* p(j | right) */temp += rwt * (*impurity) (p); /* p(right) * I(right) */rmean += p * j;}if (temp < best) {best = temp;if (lmean < rmean)for (j = 0; j < numcat; j++) csplit[j] = tsplit[j];elsefor (j = 0; j < numcat; j++) csplit[j] = -tsplit[j];}}}*improve = total_ss - best;}