public final double lgrad(double u, double a, Loss loss) { assert loss.isForNumeric() : "Loss function " + loss + " not applicable to numerics"; switch (loss) { case Quadratic: return 2 * (u - a); case Absolute: return Math.signum(u - a); case Huber: return Math.abs(u - a) <= 1 ? u - a : Math.signum(u - a); case Poisson: assert a >= 0 : "Poisson loss L(u,a) requires variable a >= 0"; return Math.exp(u) - a; case Hinge: // return a*u <= 1 ? -a : 0; return a == 0 ? (-u <= 1 ? 1 : 0) : (u <= 1 ? -1 : 0); // Booleans are coded as {0,1} instead of {-1,1} case Logistic: // return -a/(1+Math.exp(a*u)); return a == 0 ? 1 / (1 + Math.exp(-u)) : -1 / (1 + Math.exp(u)); // Booleans are coded as {0,1} instead of {-1,1} case Periodic: return ((2 * Math.PI) / _period) * Math.sin((a - u) * (2 * Math.PI) / _period); default: throw new RuntimeException("Unknown loss function " + loss); } }
public final double loss(double u, double a, Loss loss) { assert loss.isForNumeric() : "Loss function " + loss + " not applicable to numerics"; switch (loss) { case Quadratic: return (u - a) * (u - a); case Absolute: return Math.abs(u - a); case Huber: return Math.abs(u - a) <= 1 ? 0.5 * (u - a) * (u - a) : Math.abs(u - a) - 0.5; case Poisson: assert a >= 0 : "Poisson loss L(u,a) requires variable a >= 0"; return Math.exp(u) + (a == 0 ? 0 : -a * u + a * Math.log(a) - a); // Since \lim_{a->0} a*log(a) = 0 case Hinge: // return Math.max(1-a*u,0); return Math.max(1 - (a == 0 ? -u : u), 0); // Booleans are coded {0,1} instead of {-1,1} case Logistic: // return Math.log(1 + Math.exp(-a * u)); return Math.log( 1 + Math.exp(a == 0 ? u : -u)); // Booleans are coded {0,1} instead of {-1,1} case Periodic: return 1 - Math.cos((a - u) * (2 * Math.PI) / _period); default: throw new RuntimeException("Unknown loss function " + loss); } }
// Read the 'tree' columns, do model-specific math and put the results in the // fs[] array, and return the sum. Dividing any fs[] element by the sum // turns the results into a probability distribution. @Override protected float score1(Chunk chks[], float fs[ /*nclass*/], int row) { if (_nclass == 1) // Classification? return (float) chk_tree(chks, 0).at0(row); // Regression. if (_nclass == 2) { // The Boolean Optimization // This optimization assumes the 2nd tree of a 2-class system is the // inverse of the first. Fill in the missing tree fs[1] = (float) Math.exp(chk_tree(chks, 0).at0(row)); fs[2] = 1.0f / fs[1]; // exp(-d) === 1/d return fs[1] + fs[2]; } float sum = 0; for (int k = 0; k < _nclass; k++) // Sum across of likelyhoods sum += (fs[k + 1] = (float) Math.exp(chk_tree(chks, k).at0(row))); return sum; }
protected void calcModelStats( CoxPHModel model, final double[] newCoef, final double newLoglik) { CoxPHModel.CoxPHParameters p = model._parms; CoxPHModel.CoxPHOutput o = model._output; final int n_coef = o.coef.length; final Matrix inv_hessian = new Matrix(o.hessian).inverse(); for (int j = 0; j < n_coef; ++j) { for (int k = 0; k <= j; ++k) { final double elem = -inv_hessian.get(j, k); o.var_coef[j][k] = elem; o.var_coef[k][j] = elem; } } for (int j = 0; j < n_coef; ++j) { o.coef[j] = newCoef[j]; o.exp_coef[j] = Math.exp(o.coef[j]); o.exp_neg_coef[j] = Math.exp(-o.coef[j]); o.se_coef[j] = Math.sqrt(o.var_coef[j][j]); o.z_coef[j] = o.coef[j] / o.se_coef[j]; } if (o.iter == 0) { o.null_loglik = newLoglik; o.maxrsq = 1 - Math.exp(2 * o.null_loglik / o.n); o.score_test = 0; for (int j = 0; j < n_coef; ++j) { double sum = 0; for (int k = 0; k < n_coef; ++k) sum += o.var_coef[j][k] * o.gradient[k]; o.score_test += o.gradient[j] * sum; } } o.loglik = newLoglik; o.loglik_test = -2 * (o.null_loglik - o.loglik); o.rsq = 1 - Math.exp(-o.loglik_test / o.n); o.wald_test = 0; for (int j = 0; j < n_coef; ++j) { double sum = 0; for (int k = 0; k < n_coef; ++k) sum -= o.hessian[j][k] * (o.coef[k] - p.init); o.wald_test += (o.coef[j] - p.init) * sum; } }
public static double impute(double u, Loss loss) { assert loss.isForNumeric() : "Loss function " + loss + " not applicable to numerics"; switch (loss) { case Quadratic: case Absolute: case Huber: case Periodic: return u; case Poisson: return Math.exp(u) - 1; case Hinge: case Logistic: return u > 0 ? 1 : 0; // Booleans are coded as {0,1} instead of {-1,1} default: throw new RuntimeException("Unknown loss function " + loss); } }
@Override protected float[] score0(double[] data, float[] preds) { float[] p = super.score0(data, preds); if (nclasses() > 1) { // classification // Because we call Math.exp, we have to be numerically stable or else // we get Infinities, and then shortly NaN's. Rescale the data so the // largest value is +/-1 and the other values are smaller. // See notes here: http://www.hongliangjie.com/2011/01/07/logsum/ float maxval = Float.NEGATIVE_INFINITY; float dsum = 0; if (nclasses() == 2) p[2] = -p[1]; // Find a max for (int k = 1; k < p.length; k++) maxval = Math.max(maxval, p[k]); assert !Float.isInfinite(maxval) : "Something is wrong with GBM trees since returned prediction is " + Arrays.toString(p); for (int k = 1; k < p.length; k++) dsum += (p[k] = (float) Math.exp(p[k] - maxval)); div(p, dsum); p[0] = getPrediction(p, data); } else { // regression // do nothing for regression } return p; }
@Override protected void processRow(long gid, Row row) { n++; double[] response = row.response; int ncats = row.nBins; int[] cats = row.numIds; double[] nums = row.numVals; final double weight = _has_weights_column ? response[0] : 1.0; if (weight <= 0) throw new IllegalArgumentException("weights must be positive values"); final long event = (long) response[response.length - 1]; final int t1 = _has_start_column ? (int) (((long) response[response.length - 3] + 1) - _min_time) : -1; final int t2 = (int) (((long) response[response.length - 2]) - _min_time); if (t1 > t2) throw new IllegalArgumentException("start times must be strictly less than stop times"); final int numStart = _dinfo.numStart(); sumWeights += weight; for (int j = 0; j < ncats; ++j) sumWeightedCatX[cats[j]] += weight; for (int j = 0; j < nums.length; ++j) sumWeightedNumX[j] += weight * nums[j]; double logRisk = 0; for (int j = 0; j < ncats; ++j) logRisk += _beta[cats[j]]; for (int j = 0; j < nums.length - _n_offsets; ++j) logRisk += nums[j] * _beta[numStart + j]; for (int j = nums.length - _n_offsets; j < nums.length; ++j) logRisk += nums[j]; final double risk = weight * Math.exp(logRisk); logRisk *= weight; if (event > 0) { countEvents[t2]++; sizeEvents[t2] += weight; sumLogRiskEvents[t2] += logRisk; sumRiskEvents[t2] += risk; } else sizeCensored[t2] += weight; if (_has_start_column) { for (int t = t1; t <= t2; ++t) sizeRiskSet[t] += weight; for (int t = t1; t <= t2; ++t) rcumsumRisk[t] += risk; } else { sizeRiskSet[t2] += weight; rcumsumRisk[t2] += risk; } final int ntotal = ncats + (nums.length - _n_offsets); final int numStartIter = numStart - ncats; for (int jit = 0; jit < ntotal; ++jit) { final boolean jIsCat = jit < ncats; final int j = jIsCat ? cats[jit] : numStartIter + jit; final double x1 = jIsCat ? 1.0 : nums[jit - ncats]; final double xRisk = x1 * risk; if (event > 0) { sumXEvents[t2][j] += weight * x1; sumXRiskEvents[t2][j] += xRisk; } if (_has_start_column) { for (int t = t1; t <= t2; ++t) rcumsumXRisk[t][j] += xRisk; } else { rcumsumXRisk[t2][j] += xRisk; } for (int kit = 0; kit < ntotal; ++kit) { final boolean kIsCat = kit < ncats; final int k = kIsCat ? cats[kit] : numStartIter + kit; final double x2 = kIsCat ? 1.0 : nums[kit - ncats]; final double xxRisk = x2 * xRisk; if (event > 0) sumXXRiskEvents[t2][j][k] += xxRisk; if (_has_start_column) { for (int t = t1; t <= t2; ++t) rcumsumXXRisk[t][j][k] += xxRisk; } else { rcumsumXXRisk[t2][j][k] += xxRisk; } } } }