6
$\begingroup$

According to IsolationForest papers (refs are given in documentation) the score produced by Isolation Forest should be between 0 and 1.

The implementation in scikit-learn negates the scores (so high score is more on inlier) and also seems to shift it by some amount. I've tried to figure out how to reverse it but was not successful so far. The code has some methods and attributes like score_samples() and self.offset_ that are not accessible from a fitted object. The documentation and comments in code on usage of self.contamination seem contradictory...

I have version 19.1 of scikit-learn (can't tell if there were significant changes in IsolationForest implementation since then)

Any ideas/suggestions would be appreciated!

$\endgroup$
10
+50
$\begingroup$

So the code that corresponds to IsolationForest in 0.19.1 can be found here. This makes your problem a lot more manageable and a lot less confusing since what currently lives on sklearn's master branch is quite different from the 0.19.1 release.

In this version, we can recover the underlying scores directly, since decision_function gives them to us like this:

/// do the work for calculating the path lengths across the ensemble ///
scores = 2 ** (-depths.mean(axis=1) / _average_path_length(self.max_samples_))
return 0.5 - scores

scores is calculated exactly as you'd expect from the original paper. To recover what we want, we simply have to do the following:

model = sklearn.ensemble.IsolationForest()
model.fit(data)
sklearn_score_anomalies = model.decision_function(data_to_predict)
original_paper_score = [-1*s + 0.5 for s in sklearn_score_anomalies]

Very important note going forward: this will not be default behavior for decision_function in future releases of scikit-learn, so assess the docs for later releases to see what you have to do to recover the original score from your model!!

Hope this helped!

$\endgroup$
  • $\begingroup$ Thank you! This is certainly a simpler situation. I guess I didn't realize that master is not the latest stable version (which is 0.19.1) $\endgroup$ – DAF Jun 12 '18 at 20:22
1
$\begingroup$

A shortcut for tm1212 answer could be:

model = sklearn.ensemble.IsolationForest()
model.fit(data)
sklearn_score_anomalies = abs(model.score_samples(data_to_predict))
$\endgroup$
  • 1
    $\begingroup$ Nice find! I think this will work for anyone using version 0.22 or later $\endgroup$ – tm1212 Dec 6 '19 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.