From 9438e38a01ea9887417da4a36d1a0bb51d3303ed Mon Sep 17 00:00:00 2001 From: Stephen Mayhew Date: Wed, 5 Oct 2016 14:39:22 -0500 Subject: [PATCH 1/4] Fixed typo in link. --- lbjava/doc/REGRESSION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbjava/doc/REGRESSION.md b/lbjava/doc/REGRESSION.md index 1dd00383..727616fa 100644 --- a/lbjava/doc/REGRESSION.md +++ b/lbjava/doc/REGRESSION.md @@ -4,7 +4,7 @@ title: REGRESSION # 6. A working example: Regression -As mentioned in [Section 2 Basics and definitions](DEFINITION.md#feature), there are two feature types in LBJava: `discrete` and `real`. In machine learning, classification refers to the problem of predicting the class of unlabeled data for which the output type is `discrete`. On the hther hand, regression refers to the problem that the desired output is continuous or `real`. [Section 3 A working example: classifying newsgroup documents into topics](20NEWSGROUP.md) gives an example of how to use LBJava for `discrete` type and this tutorial is dedicated to `real` type. +As mentioned in [Section 2 Basics and definitions](DEFINITIONS.md#feature), there are two feature types in LBJava: `discrete` and `real`. In machine learning, classification refers to the problem of predicting the class of unlabeled data for which the output type is `discrete`. On the hther hand, regression refers to the problem that the desired output is continuous or `real`. [Section 3 A working example: classifying newsgroup documents into topics](20NEWSGROUP.md) gives an example of how to use LBJava for `discrete` type and this tutorial is dedicated to `real` type. ## 6.1 Setting Up From c850e46e2bb659522b104c80a714ada9d79ee8ee Mon Sep 17 00:00:00 2001 From: Stephen Mayhew Date: Thu, 6 Oct 2016 16:13:36 -0500 Subject: [PATCH 2/4] clarified return types. --- lbjava/doc/LBJLANGUAGE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lbjava/doc/LBJLANGUAGE.md b/lbjava/doc/LBJLANGUAGE.md index 64aad185..e01ab5a2 100644 --- a/lbjava/doc/LBJLANGUAGE.md +++ b/lbjava/doc/LBJLANGUAGE.md @@ -115,10 +115,10 @@ list of feature return types follows: - `real%` - `mixed%` -Feature return types ending with square brackets indicate that an array of features is produced +Feature return types ending with square brackets (`[]`) indicate that an array of features is produced by this classifier. The user can expect the feature at a given index of the array to be the same feature with a differing value each time the classifier is called on a different input object. -Feature return types ending with a percent sign indicate that this classifier is a feature generator. +Feature return types ending with a percent sign (`%`) indicate that this classifier is a feature generator. A feature generator may return zero or more features in any order when it is called, and there is no guarantee that the same features will be produced when called on different input objects. Finally, the `mixed%` feature return type indicates that the classifier is a generator of both discrete From 068ef6e6e2a10a7bf458dd058afa967b809c6e19 Mon Sep 17 00:00:00 2001 From: Stephen Mayhew Date: Sun, 9 Oct 2016 21:45:01 -0500 Subject: [PATCH 3/4] Added yaml headers to top-level readmes --- lbjava-examples/README.md | 5 +++++ lbjava-mvn-plugin/README.md | 4 ++++ lbjava/README.md | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/lbjava-examples/README.md b/lbjava-examples/README.md index 5d1aaaa6..014d3dcd 100644 --- a/lbjava-examples/README.md +++ b/lbjava-examples/README.md @@ -1,3 +1,8 @@ +--- +title: LBJava examples +--- + + # LBJava examples Here are a couple of sample classification projects which are using LBJava. diff --git a/lbjava-mvn-plugin/README.md b/lbjava-mvn-plugin/README.md index 1be00051..6fa5afb9 100644 --- a/lbjava-mvn-plugin/README.md +++ b/lbjava-mvn-plugin/README.md @@ -1,3 +1,7 @@ +--- +title: LBJava Maven Plugin +--- + # lbjava-maven-plugin ## Contents: diff --git a/lbjava/README.md b/lbjava/README.md index 1b83e646..e71543e1 100644 --- a/lbjava/README.md +++ b/lbjava/README.md @@ -1,3 +1,7 @@ +--- +title: LBJava +--- + # Learning Based Java (LBJava) Learning Based Java is a modeling language for the rapid development of software systems with From 9f4cb51f862f2743759d954d1ec177f2c36e7b6b Mon Sep 17 00:00:00 2001 From: Stephen Mayhew Date: Wed, 20 Sep 2017 16:11:34 -0400 Subject: [PATCH 4/4] Added new file. --- .../WeightedSparseAveragedPerceptron.java | 733 ++++++++++++++++++ 1 file changed, 733 insertions(+) create mode 100644 lbjava/src/main/java/edu/illinois/cs/cogcomp/lbjava/learn/WeightedSparseAveragedPerceptron.java diff --git a/lbjava/src/main/java/edu/illinois/cs/cogcomp/lbjava/learn/WeightedSparseAveragedPerceptron.java b/lbjava/src/main/java/edu/illinois/cs/cogcomp/lbjava/learn/WeightedSparseAveragedPerceptron.java new file mode 100644 index 00000000..991edfc4 --- /dev/null +++ b/lbjava/src/main/java/edu/illinois/cs/cogcomp/lbjava/learn/WeightedSparseAveragedPerceptron.java @@ -0,0 +1,733 @@ +/** + * This software is released under the University of Illinois/Research and Academic Use License. See + * the LICENSE file in the root folder for details. Copyright (c) 2016 + * + * Developed by: The Cognitive Computations Group, University of Illinois at Urbana-Champaign + * http://cogcomp.cs.illinois.edu/ + */ +package edu.illinois.cs.cogcomp.lbjava.learn; + +import edu.illinois.cs.cogcomp.core.datastructures.vectors.DVector; +import edu.illinois.cs.cogcomp.core.datastructures.vectors.ExceptionlessInputStream; +import edu.illinois.cs.cogcomp.core.datastructures.vectors.ExceptionlessOutputStream; +import edu.illinois.cs.cogcomp.lbjava.classify.Classifier; +import edu.illinois.cs.cogcomp.lbjava.classify.Feature; + +import java.io.PrintStream; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Map; + +/** + * An approximation to voted Perceptron, in which a weighted average of the weight vectors arrived + * at during training becomes the weight vector used to make predictions after training. + * + *

+ * During training, after each example ei is processed, the weight vector + * wi becomes the active weight vector used to make predictions on future training + * examples. If a mistake was made on ei, wi will be different + * than wi - 1. Otherwise, it will remain unchanged. + * + *

+ * After training, each distinct weight vector arrived at during training is associated with an + * integer weight equal to the number of examples whose training made that weight vector active. A + * new weight vector w* is computed by taking the average of all these weight + * vectors weighted as described. w* is used to make all predictions returned to + * the user through methods such as {@link Classifier#classify(Object)} or + * {@link Classifier#discreteValue(Object)}. + * + *

+ * The above description is a useful way to think about the operation of this {@link Learner}. + * However, the user should note that this implementation never explicitly stores + * w*. Instead, it is computed efficiently on demand. Thus, interspersed online + * training and evaluation is efficient and operates as expected. + * + *

+ * It is assumed that {@link Learner#labeler} is a single discrete classifier that produces the same + * feature for every example object and that the values that feature may take are available through + * the {@link Classifier#allowableValues()} method. The second value returned from + * {@link Classifier#allowableValues()} is treated as "positive", and it is assumed there are + * exactly 2 allowable values. Assertions will produce error messages if these assumptions do not + * hold. + * + * @author Nick Rizzolo + **/ +public class WeightedSparseAveragedPerceptron extends SparsePerceptron { + /** Default for {@link LinearThresholdUnit#weightVector}. */ + public static final AveragedWeightVector defaultWeightVector = new AveragedWeightVector(); + + /** + * Holds the same reference as {@link LinearThresholdUnit#weightVector} casted to + * {@link WeightedSparseAveragedPerceptron.AveragedWeightVector}. + **/ + protected AveragedWeightVector awv; + /** Keeps the extra information necessary to compute the averaged bias. */ + protected double averagedBias; + + + /** + * The learning rate and threshold take default values, while the name of the classifier gets + * the empty string. + **/ + public WeightedSparseAveragedPerceptron() { + this(""); + } + + /** + * Sets the learning rate to the specified value, and the threshold takes the default, while the + * name of the classifier gets the empty string. + * + * @param r The desired learning rate value. + **/ + public WeightedSparseAveragedPerceptron(double r) { + this("", r); + } + + /** + * Sets the learning rate and threshold to the specified values, while the name of the + * classifier gets the empty string. + * + * @param r The desired learning rate value. + * @param t The desired threshold value. + **/ + public WeightedSparseAveragedPerceptron(double r, double t) { + this("", r, t); + } + + /** + * Use this constructor to fit a thick separator, where both the positive and negative sides of + * the hyperplane will be given the specified thickness, while the name of the classifier gets + * the empty string. + * + * @param r The desired learning rate value. + * @param t The desired threshold value. + * @param pt The desired thickness. + **/ + public WeightedSparseAveragedPerceptron(double r, double t, double pt) { + this("", r, t, pt); + } + + /** + * Use this constructor to fit a thick separator, where the positive and negative sides of the + * hyperplane will be given the specified separate thicknesses, while the name of the classifier + * gets the empty string. + * + * @param r The desired learning rate value. + * @param t The desired threshold value. + * @param pt The desired positive thickness. + * @param nt The desired negative thickness. + **/ + public WeightedSparseAveragedPerceptron(double r, double t, double pt, double nt) { + this("", r, t, pt, nt); + } + + /** + * Initializing constructor. Sets all member variables to their associated settings in the + * {@link WeightedSparseAveragedPerceptron.Parameters} object. + * + * @param p The settings of all parameters. + **/ + public WeightedSparseAveragedPerceptron(WeightedSparseAveragedPerceptron.Parameters p) { + this("", p); + } + + + /** + * The learning rate and threshold take default values. + * + * @param n The name of the classifier. + **/ + public WeightedSparseAveragedPerceptron(String n) { + this(n, defaultLearningRate); + } + + /** + * Sets the learning rate to the specified value, and the threshold takes the default. + * + * @param n The name of the classifier. + * @param r The desired learning rate value. + **/ + public WeightedSparseAveragedPerceptron(String n, double r) { + this(n, r, defaultThreshold); + } + + /** + * Sets the learning rate and threshold to the specified values. + * + * @param n The name of the classifier. + * @param r The desired learning rate value. + * @param t The desired threshold value. + **/ + public WeightedSparseAveragedPerceptron(String n, double r, double t) { + this(n, r, t, defaultThickness); + } + + /** + * Use this constructor to fit a thick separator, where both the positive and negative sides of + * the hyperplane will be given the specified thickness. + * + * @param n The name of the classifier. + * @param r The desired learning rate value. + * @param t The desired threshold value. + * @param pt The desired thickness. + **/ + public WeightedSparseAveragedPerceptron(String n, double r, double t, double pt) { + this(n, r, t, pt, pt); + } + + /** + * Use this constructor to fit a thick separator, where the positive and negative sides of the + * hyperplane will be given the specified separate thicknesses. + * + * @param n The name of the classifier. + * @param r The desired learning rate value. + * @param t The desired threshold value. + * @param pt The desired positive thickness. + * @param nt The desired negative thickness. + **/ + public WeightedSparseAveragedPerceptron(String n, double r, double t, double pt, double nt) { + super(n); + Parameters p = new Parameters(); + p.learningRate = r; + p.threshold = t; + p.positiveThickness = pt; + p.negativeThickness = nt; + setParameters(p); + } + + /** + * Initializing constructor. Sets all member variables to their associated settings in the + * {@link WeightedSparseAveragedPerceptron.Parameters} object. + * + * @param n The name of the classifier. + * @param p The settings of all parameters. + **/ + public WeightedSparseAveragedPerceptron(String n, WeightedSparseAveragedPerceptron.Parameters p) { + super(n); + setParameters(p); + } + + + /** + * Retrieves the parameters that are set in this learner. + * + * @return An object containing all the values of the parameters that control the behavior of + * this learning algorithm. + **/ + public Learner.Parameters getParameters() { + Parameters p = new Parameters((SparsePerceptron.Parameters) super.getParameters()); + return p; + } + + + /** + * Sets the values of parameters that control the behavior of this learning algorithm. + * + * @param p The parameters. + **/ + public void setParameters(Parameters p) { + super.setParameters(p); + awv = (AveragedWeightVector) weightVector; + } + + + /** + * The score of the specified object is equal to w * x + bias where * + * is dot product, w is the weight vector, and x is the feature vector + * produced by the extractor. + * + * @param exampleFeatures The example's array of feature indices. + * @param exampleValues The example's array of feature values. + * @return The result of the dot product plus the bias. + **/ + public double score(int[] exampleFeatures, double[] exampleValues) { + double result = awv.dot(exampleFeatures, exampleValues, initialWeight); + int examples = awv.getExamples(); + + if (examples > 0) + result += (examples * bias - averagedBias) / (double) examples; + return result; + } + + + /** + * Scales the feature vector produced by the extractor by the learning rate and adds it to the + * weight vector. + * + * @param exampleFeatures The example's array of feature indices. + * @param exampleValues The example's array of feature values. + **/ + public void promote(int[] exampleFeatures, double[] exampleValues, double rate) { + bias += rate; + + int examples = awv.getExamples(); + averagedBias += examples * rate; + awv.scaledAdd(exampleFeatures, exampleValues, rate, initialWeight); + } + + + /** + * Scales the feature vector produced by the extractor by the learning rate and subtracts it + * from the weight vector. + * + * @param exampleFeatures The example's array of feature indices. + * @param exampleValues The example's array of feature values. + **/ + public void demote(int[] exampleFeatures, double[] exampleValues, double rate) { + bias -= rate; + + int examples = awv.getExamples(); + averagedBias -= examples * rate; + awv.scaledAdd(exampleFeatures, exampleValues, -rate, initialWeight); + } + + + /** + * This method works just like {@link LinearThresholdUnit#learn(int[],double[],int[],double[])}, + * except it notifies its weight vector when it got an example correct in addition to updating + * it when it makes a mistake. + * + * @param exampleFeatures The example's array of feature indices + * @param exampleValues The example's array of feature values + * @param exampleLabels The example's label(s) + * @param labelValues The labels' values + **/ + public void learn(int[] exampleFeatures, double[] exampleValues, int[] exampleLabels, + double[] labelValues) { + assert exampleLabels.length == 1 : "Example must have a single label."; + assert exampleLabels[0] == 0 || exampleLabels[0] == 1 : "Example has unallowed label value."; + + boolean label = (exampleLabels[0] == 1); + + double s = awv.simpleDot(exampleFeatures, exampleValues, initialWeight) + bias; + if (label && s < threshold + positiveThickness) + promote(exampleFeatures, exampleValues, getLearningRate()); + else if (!label && s >= threshold - negativeThickness) + demote(exampleFeatures, exampleValues, getLearningRate()); + else + awv.correctExample(); + } + + + /** + * Initializes the weight vector array to the size of the supplied number of features, with each + * cell taking the default value of {@link #initialWeight}. + * + * @param numExamples The number of examples + * @param numFeatures The number of features + **/ + public void initialize(int numExamples, int numFeatures) { + double[] weights = new double[numFeatures]; + Arrays.fill(weights, initialWeight); + weightVector = awv = new AveragedWeightVector(weights); + } + + + /** Resets the weight vector to all zeros. */ + public void forget() { + super.forget(); + awv = (AveragedWeightVector) weightVector; + averagedBias = 0; + } + + + /** + * Writes the algorithm's internal representation as text. In the first line of output, the name + * of the classifier is printed, followed by {@link SparsePerceptron#learningRate}, + * {@link LinearThresholdUnit#initialWeight}, {@link LinearThresholdUnit#threshold}, + * {@link LinearThresholdUnit#positiveThickness}, {@link LinearThresholdUnit#negativeThickness}, + * {@link LinearThresholdUnit#bias}, and finally {@link #averagedBias}. + * + * @param out The output stream. + **/ + public void write(PrintStream out) { + out.println(name + ": " + learningRate + ", " + initialWeight + ", " + threshold + ", " + + positiveThickness + ", " + negativeThickness + ", " + bias + ", " + averagedBias); + if (lexicon == null || lexicon.size() == 0) + awv.write(out); + else + awv.write(out, lexicon); + } + + + /** + * Writes the learned function's internal representation in binary form. + * + * @param out The output stream. + **/ + public void write(ExceptionlessOutputStream out) { + super.write(out); + out.writeDouble(averagedBias); + } + + + /** + * Reads the binary representation of a learner with this object's run-time type, overwriting + * any and all learned or manually specified parameters as well as the label lexicon but without + * modifying the feature lexicon. + * + * @param in The input stream. + **/ + public void read(ExceptionlessInputStream in) { + super.read(in); + awv = (AveragedWeightVector) weightVector; + averagedBias = in.readDouble(); + } + + + /** + * Simply a container for all of {@link WeightedSparseAveragedPerceptron}'s configurable parameters. + * Using instances of this class should make code more readable and constructors less + * complicated. Note that if the object referenced by + * {@link LinearThresholdUnit.Parameters#weightVector} is replaced via an instance of this + * class, it must be replaced with an {@link WeightedSparseAveragedPerceptron.AveragedWeightVector}. + * + * @author Nick Rizzolo + **/ + public static class Parameters extends SparsePerceptron.Parameters { + /** Sets all the default values. */ + public Parameters() { + weightVector = (AveragedWeightVector) defaultWeightVector.clone(); + } + + + /** + * Sets the parameters from the parent's parameters object, giving defaults to all + * parameters declared in this object. + **/ + public Parameters(SparsePerceptron.Parameters p) { + super(p); + } + + + /** Copy constructor. */ + public Parameters(Parameters p) { + super(p); + } + + + /** + * Calls the appropriate Learner.setParameters(Parameters) method for this + * Parameters object. + * + * @param l The learner whose parameters will be set. + **/ + public void setParameters(Learner l) { + ((WeightedSparseAveragedPerceptron) l).setParameters(this); + } + } + + + /** + * This implementation of a sparse weight vector associates two doubles with each + * {@link Feature}. The first plays the role of the usual weight vector, and the second + * accumulates multiples of examples on which mistakes were made to help implement the weighted + * average. + * + * @author Nick Rizzolo + **/ + public static class AveragedWeightVector extends SparseWeightVector { + /** + * Together with {@link SparseWeightVector#weights}, this vector provides enough information + * to reconstruct the average of all weight vectors arrived at during the course of + * learning. + **/ + public DVector averagedWeights; + /** Counts the total number of training examples this vector has seen. */ + protected int examples; + + + /** Simply instantiates the weight vectors. */ + public AveragedWeightVector() { + this(new DVector(defaultCapacity)); + } + + /** + * Simply initializes the weight vectors. + * + * @param w An array of weights. + **/ + public AveragedWeightVector(double[] w) { + this(new DVector(w)); + } + + /** + * Simply initializes the weight vectors. + * + * @param w A vector of weights. + **/ + public AveragedWeightVector(DVector w) { + super((DVector) w.clone()); + averagedWeights = w; + } + + + /** Increments the {@link #examples} variable. */ + public void correctExample() { + ++examples; + } + + /** Returns the {@link #examples} variable. */ + public int getExamples() { + return examples; + } + + + /** + * Returns the averaged weight of the given feature. + * + * @param featureIndex The feature index. + * @param defaultW The default weight. + * @return The weight of the feature. + **/ + public double getAveragedWeight(int featureIndex, double defaultW) { + if (examples == 0) + return 0; + double aw = averagedWeights.get(featureIndex, defaultW); + double w = getWeight(featureIndex, defaultW); + return (examples * w - aw) / (double) examples; + } + + + /** + * Takes the dot product of this AveragedWeightVector with the argument vector, + * using the hard coded default weight. + * + * @param exampleFeatures The example's array of feature indices. + * @param exampleValues The example's array of feature values. + * @return The computed dot product. + **/ + public double dot(int[] exampleFeatures, double[] exampleValues) { + return dot(exampleFeatures, exampleValues, defaultWeight); + } + + + /** + * Takes the dot product of this AveragedWeightVector with the argument vector, + * using the specified default weight when one is not yet present in this vector. + * + * @param exampleFeatures The example's array of feature indices. + * @param exampleValues The example's array of feature values. + * @param defaultW The default weight. + * @return The computed dot product. + **/ + public double dot(int[] exampleFeatures, double[] exampleValues, double defaultW) { + double sum = 0; + + for (int i = 0; i < exampleFeatures.length; i++) { + double w = getAveragedWeight(exampleFeatures[i], defaultW); + sum += w * exampleValues[i]; + } + + return sum; + } + + + /** + * Takes the dot product of the regular, non-averaged, Perceptron weight vector with the + * given vector, using the hard coded default weight. + * + * @param exampleFeatures The example's array of feature indices. + * @param exampleValues The example's array of feature values. + * @return The computed dot product. + **/ + public double simpleDot(int[] exampleFeatures, double[] exampleValues) { + return super.dot(exampleFeatures, exampleValues, defaultWeight); + } + + + /** + * Takes the dot product of the regular, non-averaged, Perceptron weight vector with the + * given vector, using the specified default weight when a feature is not yet present in + * this vector. + * + * @param exampleFeatures The example's array of feature indices. + * @param exampleValues The example's array of feature values. + * @param defaultW An initial weight for new features. + * @return The computed dot product. + **/ + public double simpleDot(int[] exampleFeatures, double[] exampleValues, double defaultW) { + return super.dot(exampleFeatures, exampleValues, defaultW); + } + + + /** + * Performs pairwise addition of the feature values in the given vector scaled by the given + * factor, modifying this weight vector, using the specified default weight when a feature + * from the given vector is not yet present in this vector. The default weight is used to + * initialize new feature weights. + * + * @param exampleFeatures The example's array of feature indices. + * @param exampleValues The example's array of feature values. + * @param factor The scaling factor. + **/ + public void scaledAdd(int[] exampleFeatures, double[] exampleValues, double factor) { + scaledAdd(exampleFeatures, exampleValues, factor, defaultWeight); + } + + + /** + * Performs pairwise addition of the feature values in the given vector scaled by the given + * factor, modifying this weight vector, using the specified default weight when a feature + * from the given vector is not yet present in this vector. + * + * @param exampleFeatures The example's array of feature indices. + * @param exampleValues The example's array of feature values. + * @param factor The scaling factor. + * @param defaultW An initial weight for new features. + **/ + public void scaledAdd(int[] exampleFeatures, double[] exampleValues, double factor, + double defaultW) { + for (int i = 0; i < exampleFeatures.length; i++) { + int featureIndex = exampleFeatures[i]; + double currentWeight = getWeight(featureIndex, defaultW); + double w = currentWeight + factor * exampleValues[i]; + + double difference = w - currentWeight; + updateAveragedWeight(featureIndex, examples * difference); + + setWeight(featureIndex, w); + } + + ++examples; + } + + + /** + * Adds a new value to the current averaged weight indexed by the supplied feature index. + * + * @param featureIndex The feature index. + * @param w The value to add to the current weight. + **/ + protected void updateAveragedWeight(int featureIndex, double w) { + double newWeight = averagedWeights.get(featureIndex, defaultWeight) + w; + averagedWeights.set(featureIndex, newWeight, defaultWeight); + } + + + /** + * Outputs the contents of this SparseWeightVector into the specified + * PrintStream. The string representation starts with a "Begin" + * annotation, ends with an "End" annotation, and without a + * Lexicon passed as a parameter, the weights are simply printed in the order + * of their integer indices. + * + * @param out The stream to write to. + **/ + public void write(PrintStream out) { + out.println("Begin AveragedWeightVector"); + for (int i = 0; i < averagedWeights.size(); ++i) + out.println(getAveragedWeight(i, 0)); + out.println("End AveragedWeightVector"); + } + + + /** + * Outputs the contents of this SparseWeightVector into the specified + * PrintStream. The string representation starts with a "Begin" + * annotation, ends with an "End" annotation, and lists each feature with its + * corresponding weight on the same, separate line in between. + * + * @param out The stream to write to. + * @param lex The feature lexicon. + **/ + public void write(PrintStream out, Lexicon lex) { + out.println("Begin AveragedWeightVector"); + + Map map = lex.getMap(); + Map.Entry[] entries = (Map.Entry[]) map.entrySet().toArray(new Map.Entry[map.size()]); + Arrays.sort(entries, new Comparator() { + public int compare(Object o1, Object o2) { + Map.Entry e1 = (Map.Entry) o1; + Map.Entry e2 = (Map.Entry) o2; + int i1 = ((Integer) e1.getValue()).intValue(); + int i2 = ((Integer) e2.getValue()).intValue(); + if ((i1 < weights.size()) != (i2 < weights.size())) + return i1 - i2; + return ((Feature) e1.getKey()).compareTo(e2.getKey()); + } + }); + + int i, biggest = 0; + for (i = 0; i < entries.length; ++i) { + String key = + entries[i].getKey().toString() + + (((Integer) entries[i].getValue()).intValue() < weights.size() ? "" + : " (pruned)"); + biggest = Math.max(biggest, key.length()); + } + + if (biggest % 2 == 0) + biggest += 2; + else + ++biggest; + + for (i = 0; i < entries.length; ++i) { + String key = + entries[i].getKey().toString() + + (((Integer) entries[i].getValue()).intValue() < weights.size() ? "" + : " (pruned)"); + out.print(key); + for (int j = 0; key.length() + j < biggest; ++j) + out.print(" "); + + int index = ((Integer) entries[i].getValue()).intValue(); + double weight = getAveragedWeight(index, 0); + out.println(weight); + } + + out.println("End AveragedWeightVector"); + } + + + /** + * Writes the weight vector's internal representation in binary form. + * + * @param out The output stream. + **/ + public void write(ExceptionlessOutputStream out) { + super.write(out); + out.writeInt(examples); + averagedWeights.write(out); + } + + + /** + * Reads the representation of a weight vector with this object's run-time type from the + * given stream, overwriting the data in this object. + * + *

+ * This method is appropriate for reading weight vectors as written by + * {@link #write(ExceptionlessOutputStream)}. + * + * @param in The input stream. + **/ + public void read(ExceptionlessInputStream in) { + super.read(in); + examples = in.readInt(); + averagedWeights.read(in); + } + + + /** + * Returns a copy of this AveragedWeightVector. + * + * @return A copy of this AveragedWeightVector. + **/ + public Object clone() { + AveragedWeightVector clone = (AveragedWeightVector) super.clone(); + clone.averagedWeights = (DVector) averagedWeights.clone(); + return clone; + } + + + /** + * Returns a new, empty weight vector with the same parameter settings as this one. + * + * @return An empty weight vector. + **/ + public SparseWeightVector emptyClone() { + return new AveragedWeightVector(); + } + } +}