final int mindim = dbdim / 2;
final int maxdim = dbdim - 1;
ArrayList<OutlierResult> results = new ArrayList<OutlierResult>(num);
{
FiniteProgress prog = logger.isVerbose() ? new FiniteProgress("LOF iterations", num, logger) : null;
for(int i = 0; i < num; i++) {
BitSet dimset = randomSubspace(dbdim, mindim, maxdim);
DimensionsSelectingEuclideanDistanceFunction df = new DimensionsSelectingEuclideanDistanceFunction(dimset);
LOF<NumberVector<?, ?>, DoubleDistance> lof = new LOF<NumberVector<?, ?>, DoubleDistance>(k, df, df);
// run LOF and collect the result
OutlierResult result = lof.run(relation);
results.add(result);
if(prog != null) {
prog.incrementProcessed(logger);
}
}
if(prog != null) {
prog.ensureCompleted(logger);
}
}
WritableDataStore<Double> scores = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC, Double.class);
DoubleMinMax minmax = new DoubleMinMax();
if(breadth) {
FiniteProgress cprog = logger.isVerbose() ? new FiniteProgress("Combining results", relation.size(), logger) : null;
HashMap<IterableIterator<DBID>, Relation<Double>> IDVectorOntoScoreVector = new HashMap<IterableIterator<DBID>, Relation<Double>>();
// Mapping score-sorted DBID-Iterators onto their corresponding scores.
// We need to initialize them now be able to iterate them "in parallel".
for(OutlierResult r : results) {
IDVectorOntoScoreVector.put(r.getOrdering().iter(relation.getDBIDs()), r.getScores());
}
// Iterating over the *lines* of the AS_t(i)-matrix.
for(int i = 0; i < relation.size(); i++) {
// Iterating over the elements of a line (breadth-first).
for(IterableIterator<DBID> iter : IDVectorOntoScoreVector.keySet()) {
if(iter.hasNext()) { // Always true if every algorithm returns a
// complete result (one score for every DBID).
DBID tmpID = iter.next();
double score = IDVectorOntoScoreVector.get(iter).get(tmpID);
if(scores.get(tmpID) == null) {
scores.put(tmpID, score);
minmax.put(score);
}
}
else {
logger.warning("Incomplete result: Iterator does not contain |DB| DBIDs");
}
}
// Progress does not take the initial mapping into account.
if(cprog != null) {
cprog.incrementProcessed(logger);
}
}
if(cprog != null) {
cprog.ensureCompleted(logger);
}
}
else {
FiniteProgress cprog = logger.isVerbose() ? new FiniteProgress("Combining results", relation.size(), logger) : null;
for(DBID id : relation.iterDBIDs()) {
double sum = 0.0;
for(OutlierResult r : results) {
sum += r.getScores().get(id);
}
scores.put(id, sum);
minmax.put(sum);
if(cprog != null) {
cprog.incrementProcessed(logger);
}
}
if(cprog != null) {
cprog.ensureCompleted(logger);
}
}
OutlierScoreMeta meta = new BasicOutlierScoreMeta(minmax.getMin(), minmax.getMax());
Relation<Double> scoreres = new MaterializedRelation<Double>("Feature bagging", "fb-outlier", TypeUtil.DOUBLE, scores, relation.getDBIDs());
return new OutlierResult(meta, scoreres);