/** * Builds L2-regularized classifiers for a sequence of regularization parameter lambdas. * * @param trainSet the training set. * @param isSparse <code>true</code> if the training set is treated as sparse. * @param maxNumIters the maximum number of iterations. * @param lambdas the lambdas array. * @return L2-regularized binary classifiers. */ public GLM[] buildClassifiers( Instances trainSet, boolean isSparse, int maxNumIters, double[] lambdas) { Attribute classAttribute = trainSet.getTargetAttribute(); if (classAttribute.getType() != Attribute.Type.NOMINAL) { throw new IllegalArgumentException("Class attribute must be nominal."); } NominalAttribute clazz = (NominalAttribute) classAttribute; int numClasses = clazz.getStates().length; if (isSparse) { SparseDataset sd = getSparseDataset(trainSet, true); int[] attrs = sd.attrs; int[][] indices = sd.indices; double[][] values = sd.values; double[] y = new double[sd.y.length]; double[] cList = sd.cList; if (numClasses == 2) { for (int i = 0; i < y.length; i++) { int label = (int) sd.y[i]; y[i] = label == 0 ? 1 : 0; } GLM[] glms = buildBinaryClassifiers(attrs, indices, values, y, maxNumIters, lambdas); for (GLM glm : glms) { double[] w = glm.w[0]; for (int j = 0; j < cList.length; j++) { int attIndex = attrs[j]; w[attIndex] *= cList[j]; } } return glms; } else { int p = attrs.length == 0 ? 0 : (StatUtils.max(attrs) + 1); GLM[] glms = new GLM[lambdas.length]; for (int i = 0; i < glms.length; i++) { glms[i] = new GLM(numClasses, p); } for (int k = 0; k < numClasses; k++) { // One-vs-the-rest for (int i = 0; i < y.length; i++) { int label = (int) sd.y[i]; y[i] = label == k ? 1 : 0; } GLM[] binaryClassifiers = buildBinaryClassifiers(attrs, indices, values, y, maxNumIters, lambdas); for (int l = 0; l < glms.length; l++) { GLM binaryClassifier = binaryClassifiers[l]; GLM glm = glms[l]; double[] w = binaryClassifier.w[0]; for (int j = 0; j < cList.length; j++) { int attIndex = attrs[j]; glm.w[k][attIndex] = w[attIndex] * cList[j]; } glm.intercept[k] = binaryClassifier.intercept[0]; } } return glms; } } else { DenseDataset dd = getDenseDataset(trainSet, true); int[] attrs = dd.attrs; double[][] x = dd.x; double[] y = new double[dd.y.length]; double[] cList = dd.cList; if (numClasses == 2) { for (int i = 0; i < y.length; i++) { int label = (int) dd.y[i]; y[i] = label == 0 ? 1 : 0; } GLM[] glms = buildBinaryClassifiers(attrs, x, y, maxNumIters, lambdas); for (GLM glm : glms) { double[] w = glm.w[0]; for (int j = 0; j < cList.length; j++) { int attIndex = attrs[j]; w[attIndex] *= cList[j]; } } return glms; } else { int p = attrs.length == 0 ? 0 : attrs[attrs.length - 1] + 1; GLM[] glms = new GLM[lambdas.length]; for (int i = 0; i < glms.length; i++) { glms[i] = new GLM(numClasses, p); } for (int k = 0; k < numClasses; k++) { // One-vs-the-rest for (int i = 0; i < y.length; i++) { int label = (int) dd.y[i]; y[i] = label == k ? 1 : 0; } GLM[] binaryClassifiers = buildBinaryClassifiers(attrs, x, y, maxNumIters, lambdas); for (int l = 0; l < glms.length; l++) { GLM binaryClassifier = binaryClassifiers[l]; GLM glm = glms[l]; double[] w = binaryClassifier.w[0]; for (int j = 0; j < cList.length; j++) { int attIndex = attrs[j]; glm.w[k][attIndex] = w[attIndex] * cList[j]; } glm.intercept[k] = binaryClassifier.intercept[0]; } } return glms; } } }