- Je combineert twee groepsgrids en selecteert binnen een gekozen empirische grens op publieke foutkosten.
- Je houdt gekozen drempels vast op afzonderlijke gegevens en onderscheidt validatie-uitkomsten van een algemene fairnessgarantie.
Een gevonden modelscore is nog geen besluit. Bij welke score krijgt een melding extra aandacht? Een lagere drempel vindt vaak meer urgente meldingen, maar kan ook meer gewone meldingen onterecht selecteren.
Stel je kaartjes op volgorde van hun score voor. Een verschuifbare scheidslijn bepaalt welke kaartjes doorgaan. Je wilt zien welke fouten én groepsverschillen veranderen voordat je één beleid kiest.
Je onderzoekt twee volledig verzonnen groepen op een klein, vast drempelgrid. De voorbeelden maken een afweging zichtbaar; ze bepalen niet welke groepsspecifieke behandeling maatschappelijk of juridisch passend is. Kies op validatiegegevens en beoordeel de vastgehouden keuze daarna op andere rijen.
1. Maak eerst de mogelijke beslissingen zichtbaar
Groep a heeft labels 0, 0, 1, 1 en scores 0,1; 0,4; 0,35; 0,8. Een score gelijk aan de drempel telt als positief. Het grid bevat hier vier vooraf gekozen drempels: nul, 0,3, 0,5 en één.
Bij drempel 0,3 gaan de scores 0,4; 0,35 en 0,8 door. Dat levert twee TP en één FP op. Bij 0,5 blijft alleen de score 0,8 over, waardoor één urgente melding wordt gemist.
cuts = [0.,.3,.5,1.]
a = threshold_profile(
[0,0,1,1],[.1,.4,.35,.8],cuts)
print(a[1]['tp'],a[1]['fp'])
print(a[2]['fn'])
# 2 1
# 1
Een hogere drempel kan bij dezelfde labels en scores geen extra positieve voorspellingen creëren. De profielen bewaren daarom dezelfde groepsgrootte en dezelfde aantallen positieve en negatieve labels. Een lege groep houdt tellingen nul; haar conditionele maten kunnen onbekend blijven.
012. Combineer groepsdrempels en maak kosten expliciet
Groep b heeft één urgente en drie gewone meldingen. Je onderzoekt daar hetzelfde grid. Vier keuzes voor a en vier voor b geven samen zestien kandidaten; dit is een begrensd onderzoek, geen zoektocht door alle denkbare beslisregels.
Noem de publieke foutkosten c_FP en c_FN. De totale FP en FN tellen fouten over beide groepen, en C is hun gewogen som. Alle kandidaten gebruiken dezelfde validatierijen, zodat hun kosten op dezelfde gegevens worden vergeleken.
Kies een kost van één per FP en twee per FN. Bij drempel 0,3 voor beide groepen zijn er samen twee FP en geen FN: C is twee. Het TPR-verschil is nul; het FPR-verschil is een half min een derde, ongeveer 0,167.
b = threshold_profile(
[0,0,0,1],[.05,.2,.6,.7],cuts)
groups = [
{'id':'a','profiles':a},
{'id':'b','profiles':b}]
grid = combine_policies(groups,1.,2.)
hand = [c for c in grid
if c['id']=='1:1'][0]
print(len(grid))
print(hand['weighted_cost'])
print(round(hand[
'equalized_odds_gap'],3))
# 16
# 2.0
# 0.167
023. Kies één criterium en leg de grens vast
Verander in het beeld de foutkosten, de maximale toegestane gap en het vergeleken criterium. Selection vergelijkt selectieratio’s; opportunity vergelijkt TPR; equalized_odds vergelijkt het grootste TPR-/FPR-verschil. Het gekozen criterium bepaalt welke kandidaten door het filter komen.
Onderzoek een vast grid voor twee verzonnen groepen. Filter op een expliciet criterium, vergelijk publieke foutkosten en beoordeel pas daarna de gekozen drempels op andere rijen.
Groen: past binnen de grens · grote stip: gekozen. Punten kunnen samenvallen; de tabel toont iedere kandidaat.
- Kandidaten
- 16
- Binnen gekozen grens
- 4
- Gekozen ID
- 1:1
- Validatiekosten C
- 2
Gekozen 1:1: drempel a 0,3, b 0,3; validatiegap 0,167. Kies op deze validatiegegevens, voordat je de andere rijen bekijkt.
| ID | Drempels a / b | Kosten C | Gap |
|---|---|---|---|
| 0:0 | 0 / 0 | 5 | 0 |
| 0:1 | 0 / 0,3 | 3 | 0,667 |
| 0:2 | 0 / 0,5 | 3 | 0,667 |
| 0:3 | 0 / 1 | 4 | 1 |
| 1:0 | 0,3 / 0 | 4 | 0,5 |
| 1:1gekozen | 0,3 / 0,3 | 2 | 0,167 |
| 1:2 | 0,3 / 0,5 | 2 | 0,167 |
| 1:3 | 0,3 / 1 | 3 | 1 |
| 2:0 | 0,5 / 0 | 5 | 1 |
| 2:1 | 0,5 / 0,3 | 3 | 0,5 |
| 2:2 | 0,5 / 0,5 | 3 | 0,5 |
| 2:3 | 0,5 / 1 | 4 | 0,5 |
| 3:0 | 1 / 0 | 7 | 1 |
| 3:1 | 1 / 0,3 | 5 | 1 |
| 3:2 | 1 / 0,5 | 5 | 1 |
| 3:3 | 1 / 1 | 6 | 0 |
Pas de vaste keuze toe op andere rijen
Je bekijkt nu alleen validatie. De knop houdt de gekozen drempels vast en vergrendelt de keuzevelden.
Dit is een beperkt deterministisch grid op vaste oefendata. Een kleine gap bewijst geen algemene fairness of statistische zekerheid. Dezelfde oefenbeoordeling wordt bij terugkeer hergebruikt; na bekijken is zij geen nieuwe onafhankelijke eindtest.
Noem de gekozen gap Δ en de publieke tolerantie τ. Een kandidaat mag mee als zijn gap bekend is en niet groter is dan τ. Gelijkheid aan de grens is toegestaan; onbekend wordt niet als nul behandeld.
Daarna kies je binnen dit grid de laagste gewogen foutkosten. Bij gelijke kosten gaat de kleinere gekozen gap voor; bij opnieuw gelijkheid gebruik je lexicografisch de drempels in de vaste groepsvolgorde. Die laatste stap maakt een gelijke uitkomst reproduceerbaar, zonder haar inhoudelijk beter te verklaren.
Met equalized_odds en tolerantie 0,2 kiest ons voorbeeld kandidaat 1:1. De indices in dat id beginnen bij nul: index één verwijst naar de tweede drempel, dus 0,3. De groepsdrempels zijn hier toevallig gelijk; de zoekruimte laat ook ongelijke drempels toe.
choice = choose_policy(
grid,'equalized_odds',.2)
chosen_id = choice['chosen_id']
selected = [c for c in grid
if c['id']==chosen_id][0]
print(chosen_id)
print(list(selected[
'thresholds'].values()))
# 1:1
# [0.3, 0.3]
Een andere kostenkeuze kan andere fouten aantrekkelijk maken. Een strengere gapgrens kan alle kandidaten uitsluiten, of alleen kandidaten met hoge foutkosten overhouden. Geen passende kandidaat is een geldige uitkomst, geen aanleiding om onbekende maten weg te poetsen.
034. Houd de keuze vast op afzonderlijke gegevens
Een validatie-uitkomst voorspelt geen zekerheid over nieuwe gegevens. Houd beide gekozen drempels op 0,3 en beoordeel andere rijen. Kies in deze beoordeling niet opnieuw een gunstig beleid uit.
test = [
('a',[1,1,0,0],[.1,.2,.7,.8]),
('b',[1,0,0,0],[.9,.1,.2,.25])]
fixed = []
for name,y,s in test:
t = selected['thresholds'][name]
prof = threshold_profile(y,s,[t])
fixed.append({
'id':name,'profiles':prof})
check = combine_policies(
fixed,1.,2.)[0]
print(check['equalized_odds_gap'])
# 1.0
In a worden nu alle urgente meldingen gemist en alle gewone geselecteerd; in b gebeurt het omgekeerde. De gap groeit naar één. Dit voorbeeld maakt concreet waarom een gekozen empirische grens geen algemene fairnessgarantie, statistische zekerheid of bewijs over toekomstige populaties is.
Ook aangeleverde kandidaatkosten en labels verdienen controle: de keuzefunctie bewijst hun herkomst niet. De twee datasets in dit voorbeeld zijn vooraf apart gemaakt. Op echte gegevens vraagt een gewijzigd ontwerp opnieuw een onafhankelijke beoordeling.
Wat je nu kunt
- Je maakt een begrensd drempelgrid en benoemt publieke foutkosten.
- Je kiest expliciet een criterium, een inclusieve grens en een reproduceerbare rangorde.
- Je beoordeelt vastgehouden drempels op afzonderlijke rijen zonder opnieuw te selecteren.
Hierna onderzoek je modeluitleg: welke invoer hangt samen met een voorspelling, en wanneer zegt zo’n verband nog niets over een oorzaak?