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

Remove bug in ARE in evaluate.py #89

Merged
merged 31 commits into from May 20, 2017

Conversation

JohnnyTeutonic
Copy link
Contributor

As per discussion at cremi/cremi_python#3 (comment) about errors with the normalisation of the Adapted Rand Errror, I have incorporated the changes to the ARE, adapted from the fixed code found in the above discussion, which is seen in the link: https://gist.github.com/thouis/63888c375cbeb2f702e94e2e82eebee8.
The main change to the code is the removal of the division by 'n' , which previously had included division by both zero and non-zero pixels, which occurred when calculating the sum of the pixels in segments A and B. So now this code reflects only division by non-zero pixels, which is what should have been reflected in the reference implementation.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.05%) to 50.079% when pulling 81c0f60 on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.03%) to 50.105% when pulling de738fc on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.03%) to 50.105% when pulling de738fc on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.03%) to 50.105% when pulling 685ac89 on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.08%) to 50.052% when pulling f760002 on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.08%) to 50.052% when pulling fe8468a on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.08%) to 50.052% when pulling 7ca16be on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.08%) to 50.052% when pulling 86e6dd8 on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.05%) to 50.079% when pulling 6c3b5a3 on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.01%) to 50.118% when pulling 8391091 on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.5%) to 50.618% when pulling c7abd48 on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

Copy link
Collaborator

@jni jni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JohnnyTeutonic pretty good but still some work to do here! =)

gala/evaluate.py Outdated
@@ -927,10 +927,11 @@ def rand_by_threshold(ucm, gt, npoints=None):
return np.concatenate((ts[np.newaxis, :], result), axis=0)

def adapted_rand_error(seg, gt, all_stats=False):
from gala import evaluate as ev
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Erm...

gala/evaluate.py Outdated
@@ -942,6 +943,7 @@ def adapted_rand_error(seg, gt, all_stats=False):
all_stats : boolean, optional
whether to also return precision and recall as a 3-tuple with rand_error


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this extra newline

gala/evaluate.py Outdated
@@ -952,40 +954,43 @@ def adapted_rand_error(seg, gt, all_stats=False):
rec : float, optional
The adapted Rand recall. (Only returned when `all_stats` is ``True``.)


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one too

gala/evaluate.py Outdated
# This is the contingency table obtained from segA and segB, we obtain
# the marginal probabilities from the table.
p_ij = ev.contingency_table(segA, segB, norm=False)
contingency_table = p_ij.A
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WHOA. Do not do this. This instantiates a potentially enormous array. The contingency table should be usable in sparse format. .A is used to make numpy arrays out of e.g. the marginals, which are much smaller (n + m instead of n * m)

gala/evaluate.py Outdated

p_ij = sparse.csr_matrix((ones_data, (segA[:], segB[:])), shape=(n_labels_A, n_labels_B))
# Sum of the joint distribution squared
sum_p_ij = np.sum(contingency_table**2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sum_p_ij = np.sum(p_ij.data ** 2)

See Elegant SciPy, Nunez-Iglesias et al, Chapter 5. =P

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, check the comment about sum_a: sum_p_ij = p_ij.data @ p_ij.data.

gala/evaluate.py Outdated
precision = sumAB / sumB
recall = sumAB / sumA
precision = (sum_p_ij - n )/ (sum_a - n)
recall = (sum_p_ij -n )/ (sum_b - n)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP8 here also

gala/evaluate.py Outdated

fScore = 2.0 * precision * recall / (precision + recall)
are = 1.0 - fScore

are = abs(1.0 - fScore)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just write 1 - f_score here — the 1.0 is a legacy construct from Python 2.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, you shouldn't need abs here...?

gala/evaluate.py Outdated
precision = sumAB / sumB
recall = sumAB / sumA
precision = (sum_p_ij - n )/ (sum_a - n)
recall = (sum_p_ij -n )/ (sum_b - n)

fScore = 2.0 * precision * recall / (precision + recall)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not your responsibility, but you might as well fix fScore -> f_score while you're here. =)

def test_are():
seg = np.array([[0,1], [1,0]])
gt = np.array([[1,2],[0,1]])
assert_almost_equal(abs(ev.adapted_rand_error(seg,gt)),0.3333333)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there an abs here?

seg = np.array([[0,1], [1,0]])
gt = np.array([[1,2],[0,1]])
assert_almost_equal(abs(ev.adapted_rand_error(seg,gt)),0.3333333)
assert seg.shape == gt.shape
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is always true by construction, so you can remove it.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.5%) to 50.618% when pulling 1c612af on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.5%) to 50.592% when pulling 9018d0c on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@JohnnyTeutonic
Copy link
Contributor Author

Okay, I included all your changes and also removed the unnecessary ravel functional calls (segA = np.ravel(gt), segB = np.ravel(seg)) at the beginning of the function, as I realised that the contingency table already flattens the input arrays anyway. So that removes some more redundant code.

Copy link
Collaborator

@jni jni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JohnnyTeutonic I've requested one more change. It's minor, I promise! =)


def test_are():
seg = np.array([[0, 1], [1, 0]])
gt = np.array([[1, 2],[0, 1]])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JohnnyTeutonic part of the reason this whole issue arose was the way 0 was being treated as background. We've decided to not do this, but, in case we eventually do, it would be best if this test didn't use the 0 label. So can you please relabel 0s to 3 in both volumes?

@coveralls
Copy link

Coverage Status

Coverage increased (+0.5%) to 50.618% when pulling 90988b6 on JohnnyTeutonic:adapted_rand_index into 6613db2 on janelia-flyem:master.

@jni jni merged commit f84a682 into janelia-flyem:master May 20, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants