/** * <p><b>Note: The streams are NOT closed</b></p> */ public static void doPredict(StreamReader reader, StreamWriter writer, Model model) { int correct = 0; int total = 0; double error = 0; double sump = 0, sumt = 0, sumpp = 0, sumtt = 0, sumpt = 0; int nr_class = model.getNrClass(); double[] prob_estimates = null; int n; int nr_feature = model.getNrFeature(); if (model.bias >= 0) n = nr_feature + 1; else n = nr_feature; if (flag_predict_probability && !model.isProbabilityModel()) { throw new ArgumentException("probability output is only supported for logistic regression"); } if (flag_predict_probability) { int[] labels = model.getLabels(); prob_estimates = new double[nr_class]; writer.Write("labels"); for (int j = 0; j < nr_class; j++) writer.Write(" {0}", labels[j]); writer.WriteLine(); } String line = null; while ((line = reader.ReadLine()) != null) { List<Feature> x = new List<Feature>(); string[] parts = line.Split(new[]{' ', '\t'}, StringSplitOptions.RemoveEmptyEntries); double target_label; if (parts.Length == 0) { throw new InvalidOperationException("Wrong input format at line " + (total + 1)); } String label = parts[0]; target_label = Linear.atof(label); foreach (var token in parts.Skip(1)) { string[] split = token.Split(':'); if (split.Length < 2) { throw new InvalidOperationException("Wrong input format at line " + (total + 1)); } try { int idx = Linear.atoi(split[0]); double val = Linear.atof(split[1]); // feature indices larger than those in training are not used if (idx <= nr_feature) { Feature node = new Feature(idx, val); x.Add(node); } } catch (FormatException e) { throw new InvalidOperationException("Wrong input format at line " + (total + 1), e); } } if (model.bias >= 0) { Feature node = new Feature(n, model.bias); x.Add(node); } Feature[] nodes = x.ToArray(); double predict_label; if (flag_predict_probability) { Debug.Assert(prob_estimates != null); predict_label = Linear.predictProbability(model, nodes, prob_estimates); Console.Write(predict_label); for (int j = 0; j < model.nr_class; j++) Console.Write(" {0}", prob_estimates[j]); Console.WriteLine(); } else { predict_label = Linear.predict(model, nodes); Console.WriteLine("{0}", predict_label); } if (predict_label == target_label) { ++correct; } error += (predict_label - target_label) * (predict_label - target_label); sump += predict_label; sumt += target_label; sumpp += predict_label * predict_label; sumtt += target_label * target_label; sumpt += predict_label * target_label; ++total; } if (model.solverType.isSupportVectorRegression()) // { Linear.info("Mean squared error = {0} (regression)", error / total); Linear.info("Squared correlation coefficient = {0} (regression)", // ((total * sumpt - sump * sumt) * (total * sumpt - sump * sumt)) / ((total * sumpp - sump * sump) * (total * sumtt - sumt * sumt))); } else { Linear.info("Accuracy = {0} ({1}/{2})", (double)correct / total * 100, correct, total); } }
public bool Equals(Feature other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return other.Index == Index && other.Value.Equals(Value); }
/** * reads a problem from LibSVM format * @param file the SVM file * @throws IOException obviously in case of any I/O exception ;) * @throws InvalidInputDataException if the input file is not correctly formatted */ public static Problem readProblem(FileInfo file, double bias) { using (StreamReader fp = new StreamReader(File.OpenRead(file.FullName))) { List<Double> vy = new List<Double>(); List<Feature[]> vx = new List<Feature[]>(); int max_index = 0; int lineNr = 0; while (true) { String line = fp.ReadLine(); if (line == null) break; lineNr++; var tokens = line.Split(new[]{' ', '\t', '\f', ':'}, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length == 0) { throw new InvalidInputDataException("empty line", file, lineNr); } try { vy.Add(Linear.atof(tokens[0])); } catch (FormatException e) { throw new InvalidInputDataException("invalid label: " + tokens[0], file, lineNr, e); } tokens = tokens.Skip(1).ToArray(); int m = tokens.Length / 2; Feature[] x; if (bias >= 0) { x = new Feature[m + 1]; } else { x = new Feature[m]; } int indexBefore = 0; for (int j = 0; j < m; j++) { var token = tokens[j * 2]; int index; try { index = Linear.atoi(token); } catch (FormatException e) { throw new InvalidInputDataException("invalid index: " + token, file, lineNr, e); } // assert that indices are valid and sorted if (index < 0) throw new InvalidInputDataException("invalid index: " + index, file, lineNr); if (index <= indexBefore) throw new InvalidInputDataException("indices must be sorted in ascending order", file, lineNr); indexBefore = index; token = tokens[j * 2 + 1]; try { double value = Linear.atof(token); x[j] = new Feature(index, value); } catch (FormatException) { throw new InvalidInputDataException("invalid value: " + token, file, lineNr); } } if (m > 0) { max_index = Math.Max(max_index, x[m - 1].Index); } vx.Add(x); } return constructProblem(vy, vx, max_index, bias); } }
public static double predictValues(Model model, Feature[] x, double[] dec_values) { int n; if (model.bias >= 0) n = model.nr_feature + 1; else n = model.nr_feature; double[] w = model.w; int nr_w; if (model.nr_class == 2 && model.solverType.getId() != SolverType.MCSVM_CS) nr_w = 1; else nr_w = model.nr_class; for (int i = 0; i < nr_w; i++) dec_values[i] = 0; foreach (Feature lx in x) { int idx = lx.Index; // the dimension of testing data may exceed that of training if (idx <= n) { for (int i = 0; i < nr_w; i++) { dec_values[i] += w[(idx - 1) * nr_w + i] * lx.Value; } } } if (model.nr_class == 2) { if (model.solverType.isSupportVectorRegression()) return dec_values[0]; else return (dec_values[0] > 0) ? model.label[0] : model.label[1]; } else { int dec_max_idx = 0; for (int i = 1; i < model.nr_class; i++) { if (dec_values[i] > dec_values[dec_max_idx]) dec_max_idx = i; } return model.label[dec_max_idx]; } }
/** * @throws IllegalArgumentException if model is not probabilistic (see {@link Model#isProbabilityModel()}) */ public static double predictProbability(Model model, Feature[] x, double[] prob_estimates) { if (!model.isProbabilityModel()) { StringBuilder sb = new StringBuilder("probability output is only supported for logistic regression"); sb.Append(". This is currently only supported by the following solvers: "); int i = 0; foreach (SolverType solverType in SolverType.values()) { if (solverType.isLogisticRegressionSolver()) { if (i++ > 0) { sb.Append(", "); } sb.Append(solverType.Name); } } throw new ArgumentException(sb.ToString()); } int nr_class = model.nr_class; int nr_w; if (nr_class == 2) nr_w = 1; else nr_w = nr_class; double label = predictValues(model, x, prob_estimates); for (int i = 0; i < nr_w; i++) prob_estimates[i] = 1 / (1 + Math.Exp(-prob_estimates[i])); if (nr_class == 2) // for binary classification prob_estimates[1] = 1.0 - prob_estimates[0]; else { double sum = 0; for (int i = 0; i < nr_class; i++) sum += prob_estimates[i]; for (int i = 0; i < nr_class; i++) prob_estimates[i] = prob_estimates[i] / sum; } return label; }
public static double predict(Model model, Feature[] x) { double[] dec_values = new double[model.nr_class]; return predictValues(model, x, dec_values); }
/** * @throws IllegalArgumentException if the feature nodes of prob are not sorted in ascending order */ public static Model train(Problem prob, Parameter param) { if (prob == null) throw new ArgumentNullException("problem must not be null"); if (param == null) throw new ArgumentNullException("parameter must not be null"); if (prob.n == 0) throw new ArgumentNullException("problem has zero features"); if (prob.l == 0) throw new ArgumentNullException("problem has zero instances"); foreach (Feature[] nodes in prob.x) { int indexBefore = 0; foreach (Feature n_ in nodes) { if (n_.Index <= indexBefore) { throw new ArgumentException("feature nodes must be sorted by index in ascending order"); } indexBefore = n_.Index; } } int l = prob.l; int n = prob.n; int w_size = prob.n; Model model = new Model(); if (prob.bias >= 0) model.nr_feature = n - 1; else model.nr_feature = n; model.solverType = param.solverType; model.bias = prob.bias; if (param.solverType.getId() == SolverType.L2R_L2LOSS_SVR || // param.solverType.getId() == SolverType.L2R_L1LOSS_SVR_DUAL || // param.solverType.getId() == SolverType.L2R_L2LOSS_SVR_DUAL) { model.w = new double[w_size]; model.nr_class = 2; model.label = null; checkProblemSize(n, model.nr_class); train_one(prob, param, model.w, 0, 0); } else { int[] perm = new int[l]; // group training data of the same class GroupClassesReturn rv = groupClasses(prob, perm); int nr_class = rv.nr_class; int[] label = rv.label; int[] start = rv.start; int[] count = rv.count; checkProblemSize(n, nr_class); model.nr_class = nr_class; model.label = new int[nr_class]; for (int i = 0; i < nr_class; i++) model.label[i] = label[i]; // calculate weighted C double[] weighted_C = new double[nr_class]; for (int i = 0; i < nr_class; i++) weighted_C[i] = param.C; for (int i = 0; i < param.getNumWeights(); i++) { int j; for (j = 0; j < nr_class; j++) if (param.weightLabel[i] == label[j]) break; if (j == nr_class) throw new ArgumentException("class label " + param.weightLabel[i] + " specified in weight is not found"); weighted_C[j] *= param.weight[i]; } // constructing the subproblem Feature[][] x = new Feature[l][]; for (int i = 0; i < l; i++) x[i] = prob.x[perm[i]]; Problem sub_prob = new Problem(); sub_prob.l = l; sub_prob.n = n; sub_prob.x = new Feature[sub_prob.l][]; sub_prob.y = new double[sub_prob.l]; for (int k = 0; k < sub_prob.l; k++) sub_prob.x[k] = x[k]; // multi-class svm by Crammer and Singer if (param.solverType.getId() == SolverType.MCSVM_CS) { model.w = new double[n * nr_class]; for (int i = 0; i < nr_class; i++) { for (int j = start[i]; j < start[i] + count[i]; j++) { sub_prob.y[j] = i; } } SolverMCSVM_CS solver = new SolverMCSVM_CS(sub_prob, nr_class, weighted_C, param.eps); solver.solve(model.w); } else { if (nr_class == 2) { model.w = new double[w_size]; int e0 = start[0] + count[0]; int k = 0; for (; k < e0; k++) sub_prob.y[k] = +1; for (; k < sub_prob.l; k++) sub_prob.y[k] = -1; train_one(sub_prob, param, model.w, weighted_C[0], weighted_C[1]); } else { model.w = new double[w_size * nr_class]; double[] w = new double[w_size]; for (int i = 0; i < nr_class; i++) { int si = start[i]; int ei = si + count[i]; int k = 0; for (; k < si; k++) sub_prob.y[k] = -1; for (; k < ei; k++) sub_prob.y[k] = +1; for (; k < sub_prob.l; k++) sub_prob.y[k] = -1; train_one(sub_prob, param, w, weighted_C[i], param.C); for (int j = 0; j < n; j++) model.w[j * nr_class + i] = w[j]; } } } } return model; }