Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exposes views on the HDBSCAN cluster exemplars #229

Merged
merged 4 commits into from
Apr 15, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.oracle.labs.mlrg.olcut.util.Pair;
import org.tribuo.Example;
import org.tribuo.Excuse;
import org.tribuo.Feature;
import org.tribuo.ImmutableFeatureMap;
import org.tribuo.ImmutableOutputInfo;
import org.tribuo.Model;
Expand All @@ -29,6 +30,7 @@
import org.tribuo.math.la.DenseVector;
import org.tribuo.math.la.SGDVector;
import org.tribuo.math.la.SparseVector;
import org.tribuo.math.la.VectorTuple;
import org.tribuo.provenance.ModelProvenance;

import java.io.IOException;
Expand Down Expand Up @@ -107,6 +109,43 @@ public List<Double> getOutlierScores() {
return outlierScores;
}

/**
* Returns a deep copy of the cluster exemplars.
* @return The cluster exemplars.
*/
public List<HdbscanTrainer.ClusterExemplar> getClusterExemplars() {
List<HdbscanTrainer.ClusterExemplar> list = new ArrayList<>(clusterExemplars.size());
for (HdbscanTrainer.ClusterExemplar e : clusterExemplars) {
list.add(e.copy());
}
return list;
}

/**
* Returns the features in each cluster exemplar.
* <p>
* In many cases this should be used in preference to {@link #getClusterExemplars()}
* as it performs the mapping from Tribuo's internal feature ids to
* the externally visible feature names.
* @return The cluster exemplars.
*/
public List<Pair<Integer,List<Feature>>> getClusters() {
List<Pair<Integer,List<Feature>>> list = new ArrayList<>(clusterExemplars.size());

for (HdbscanTrainer.ClusterExemplar e : clusterExemplars) {
List<Feature> features = new ArrayList<>(e.getFeatures().numActiveElements());

for (VectorTuple v : e.getFeatures()) {
Feature f = new Feature(featureIDMap.get(v.index).getName(),v.value);
features.add(f);
}

list.add(new Pair<>(e.getLabel(),features));
}

return list;
}

@Override
public Prediction<ClusterID> predict(Example<ClusterID> example) {
SGDVector vector;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.PriorityQueue;
import java.util.TreeMap;
import java.util.TreeSet;
Expand Down Expand Up @@ -805,7 +806,7 @@ public TrainerProvenance getProvenance() {
/**
* A cluster exemplar, with attributes for the point's label, outlier score and its features.
*/
final static class ClusterExemplar implements Serializable {
public final static class ClusterExemplar implements Serializable {
private static final long serialVersionUID = 1L;

private final Integer label;
Expand All @@ -820,26 +821,72 @@ final static class ClusterExemplar implements Serializable {
this.maxDistToEdge = maxDistToEdge;
}

Integer getLabel() {
/**
* Get the label in this exemplar.
* @return The label.
*/
public Integer getLabel() {
return label;
}

Double getOutlierScore() {
/**
* Get the outlier score in this exemplar.
* @return The outlier score.
*/
public Double getOutlierScore() {
return outlierScore;
}

SGDVector getFeatures() {
/**
* Get the feature vector in this exemplar.
* @return The feature vector.
*/
public SGDVector getFeatures() {
return features;
}

Double getMaxDistToEdge() {
/**
* Get the maximum distance from this exemplar to the edge of the cluster.
* <p>
* For models trained in 4.2 this will return {@link Double#NEGATIVE_INFINITY} as that information is
* not produced by 4.2 models.
* @return The distance to the edge of the cluster.
*/
public Double getMaxDistToEdge() {
if (maxDistToEdge != null) {
return maxDistToEdge;
}
else {
return Double.NEGATIVE_INFINITY;
}
}

/**
* Copies this cluster exemplar.
* @return A deep copy of this cluster exemplar.
*/
public ClusterExemplar copy() {
return new ClusterExemplar(label,outlierScore,features.copy(),maxDistToEdge);
}

@Override
public String toString() {
double dist = maxDistToEdge == null ? Double.NEGATIVE_INFINITY : maxDistToEdge;
return "ClusterExemplar(label="+label+",outlierScore="+outlierScore+",vector="+features+",maxDistToEdge="+dist+")";
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ClusterExemplar that = (ClusterExemplar) o;
return label.equals(that.label) && outlierScore.equals(that.outlierScore) && features.equals(that.features) && Objects.equals(maxDistToEdge, that.maxDistToEdge);
}

@Override
public int hashCode() {
return Objects.hash(label, outlierScore, features, maxDistToEdge);
}
}

}