aequitas
aequitas copied to clipboard
[Solved] meaning of get_crosstabs() param "score_thresholds", "score"
Hi everyone,
I am analyzing whether an API performs equally well for all groups. So I have a data set where I have continuous "score" values between 0 and 1. They are predictions made by the API for it's result being correct. Then there is the "label_value" which is either 0 (meaning that the API result was incorrect) or 1 (meaning that the API result was correct).
Now if I calculate the true positives for instance for women by hand I do:
f_tp = df[((df['sex'] == 'Female') & (df['label_value'] == 1) & (df['score'] >= t))]
where t is my treshold of 0.8. So I consider a score of 0.8 to be a prediction of being correct.
I do similar stuff to calculate tn, fp, fn:
f_tn = df[((df['sex'] == 'Female') & (df['label_value'] == 0) & (df['score'] < t))]
f_fp = df[((df['sex'] == 'Female') & (df['label_value'] == 0) & (df['score'] >= t))]
f_fn = df[((df['sex'] == 'Female') & (df['label_value'] == 1) & (df['score'] < t))]
And I obtain:
- tp = 1185
- tn = 43
- fp = 63
- fn = 104
Now I would like to make these calculations automatically using Aequitas.
g = Group()
xtab, _ = g.get_crosstabs(df, attr_cols=["sex"], score_thresholds= {'score': [0.8]})
In the result, I get values similar to those I got by hand but they are switched around :
- tp = 104
- tn = 63
- fp = 43
- fn = 1185
Here, tp is what I considered to be fn and fn is what I considered to be tp. What I considered to be tn is fp and what I considered to be fp is tn.
I can't quite wrap my mind around this. What am I missing? I think I might be confusing something? I'd be so happy if you could give me a hint.
Thanks!
I also looked here:
- https://dssg.github.io/aequitas/_modules/src/aequitas/group.html#Group.get_crosstabs to find out how to set the score threshold
And here:
- https://developers.google.com/machine-learning/crash-course/classification/true-false-positive-negative to make sure my definitions for tp, fp, tn, fn are correct
The numbers I calculated for predicted positive and predicted negative are also switched in Aequitas:
f_pp = df[((df['sex'] == 'Female') & (df['score'] >= t))] # 1248, is pn in Aequitas
f_pn = df[((df['sex'] == 'Female') & (df['score'] < t))] # 147, is pp in Aequitas
So when I say "all those with a score < t are positive", "all those with a score >= t are negative", I get the same results as Aequitas. Same for the other values. So Aequitas basically thinks that when the score is smaller than a threshold it counts as positive and when it is bigger than a threshold it counts as negative. I find this a bit counterintuitive, at least in my use case. Is there any setting or so to change this interpretation?
- I assume
label_value == 0
is the negative class ("API's classification was not correct"),label_value == 1
is the positive class ("API's classification was correct") - Therefore I thought that score means the probability predicted for the classification being correct (probability for positive class)
- However, the score in Aequitas is actually a score for the classification being incorrect (probability for negative class)
So the solution was to recalculate my score to 1 - score
and set the treshold to 1 - original_treshold
. Any score smaller than the treshold means "predicted positive", anything bigger than the treshold means "predicted negative".
Now I am getting the correct values for tp etc. from Aequitas.
And the part of the code that shows how the treshold is interpreted: https://github.com/dssg/aequitas/blob/bb17ce4f305e8a33af3ae18a2a9000555f2e684e/src/aequitas/bias.py#L729 https://github.com/dssg/aequitas/blob/bb17ce4f305e8a33af3ae18a2a9000555f2e684e/src/aequitas/bias.py#L730