docs: public OutlierResult run(Database database, Relation<N> nrel, Relation<? extends NumberVector> relation) {
      final NeighborSetPredicate npred = getNeighborSetPredicateFactory().instantiate(database, nrel);
      WritableDoubleDataStore means = DataStoreUtil.makeDoubleStorage(relation.getDBIDs(), DataStoreFactory.HINT_TEMP);
  
      // Calculate average of neighborhood for each object and perform a linear
      // regression using the covariance matrix
      CovarianceMatrix covm = new CovarianceMatrix(2);
      for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
        final double local = relation.get(iditer).doubleValue(0);
        // Compute mean of neighbors
        Mean mean = new Mean();
        DBIDs neighbors = npred.getNeighborDBIDs(iditer);
        for(DBIDIter iter = neighbors.iter(); iter.valid(); iter.advance()) {
          if(DBIDUtil.equal(iditer, iter)) {
            continue;
          }
          mean.put(relation.get(iter).doubleValue(0));
        }
        final double m;
        if(mean.getCount() > 0) {
          m = mean.getMean();
        }
        else {
          // if object id has no neighbors ==> avg = non-spatial attribute of id
          m = local;
        }
        // Store the mean for the score calculation
        means.putDouble(iditer, m);
        covm.put(new double[] { local, m });
      }
      // Finalize covariance matrix, compute linear regression
      final double slope, inter;
      {
        double[] meanv = covm.getMeanVector();
        double[][] fmat = covm.destroyToSampleMatrix();
        final double covxx = fmat[0][0], covxy = fmat[0][1];
        slope = covxy / covxx;
        inter = meanv[1] - slope * meanv[0];
      }
  
      // calculate mean and variance for error
      WritableDoubleDataStore scores = DataStoreUtil.makeDoubleStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC);
      MeanVariance mv = new MeanVariance();
      for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
        // Compute the error from the linear regression
        double y_i = relation.get(iditer).doubleValue(0);
        double e = means.doubleValue(iditer) - (slope * y_i + inter);
        scores.putDouble(iditer, e);
        mv.put(e);
      }
  
      // Normalize scores
      DoubleMinMax minmax = new DoubleMinMax();
      {
        final double mean = mv.getMean();
        final double variance = mv.getNaiveStddev();
        for(DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
          double score = Math.abs((scores.doubleValue(iditer) - mean) / variance);
          minmax.put(score);
          scores.putDouble(iditer, score);
        }
      }
      // build representation
      DoubleRelation scoreResult = new MaterializedDoubleRelation("SPO", "Scatterplot-Outlier", scores, relation.getDBIDs());
      OutlierScoreMeta scoreMeta = new BasicOutlierScoreMeta(minmax.getMin(), minmax.getMax(), 0.0, Double.POSITIVE_INFINITY, 0);
      OutlierResult or = new OutlierResult(scoreMeta, scoreResult);
      or.addChildResult(npred);
      return or;
    }