Inequity Fini
There’s always a reasonable and intelligent way to approach any problem.
Then there’s the way I usually choose.
Yep. Trust me to do it the unreasonable and stoopid way.
The question I was asking in my previous blog post on this topic was pretty simple: Will even a small amount of systemic unfairness have a measurable and significant impact on who wins and who loses in our little, random game?
Here’s me, being stoopid: I decided to calculate the average ID Number of the winning cohort, to see how that was affected by injecting some unfairness into the game (i.e. 1% of the population refusing to give a pebble to a chunk of folks representing 10% of the overall population).
My method worked, but it finally dawned on me that I was taking a really round about way to look for my answer. I had the data - why not just look at the raw number of individuals in the affected population that actually made it into the winning cohort.
Doh.
Here’s the code to do just that. If it’s gibberish to you, feel free to ignore it… I’ll ‘splain below:
#!/usr/bin/env python3
import random
from datetime import datetime
# choose a random seed
random.seed(datetime.now().timestamp())
people = {}
averages = []
winners = []
# we begin with 1000 people, each with 100 pebbles
for i in range(1000):
people[i] = 100
# let's play the game 100 times...
for k in range(100):
# every second, each individual picks a random person and gives them one pebble
for i in range(3600 * 8):
for p in range(len(people)):
r = p
while(r == p):
if p >= len(people) - (len(people) * 0.001):
r = random.randint(100,len(people) - 1)
else:
r = random.randint(0,len(people) - 1)
if people[p] > 0:
people[p] -= 1
people[r] += 1
# let's pull out the values so we can easily sort them...
values = []
for p in range(len(people)):
values.append(people[p])
# sort the results, lowest to highest
values.sort()
count = 0
total = 0
for p in range(100):
if people[p] >= 100:
count += 1
for p in range(len(people)):
if people[p] >= 100:
total += 1
print('Run #%3.3i count: %i winners: %i' % ((k + 1), count, total))
averages.append(count)
winners.append(total)
# now, let's do a little statistical math...
avg = sum(averages) / len(averages)
var = sum((x-avg)**2 for x in averages) / len(averages)
std = var**0.5
print('Overall (affected group): average:%f variance: %f std_deviation: %f' % (avg, var, std))
avg = sum(winners) / len(winners)
var = sum((x-avg)**2 for x in winners) / len(winners)
std = var**0.5
print('Overall (winners): average:%f variance: %f std_deviation: %f' % (avg, var, std))
So, once again, I’m playing the game 100 times. At the end of each game, I’m counting the number of folks in the affected group (the 10% of players with an ID Number in the range 0-99) that are winners (defined as having 100 or more pebbles at the end of the game). I’m also counting the overall number of winners.
In the original, completely fair version of the game, one would expect that our affected group - which makes up 10% of the overall population - would, on average, make up 10% of the winners. And yep, that’s what we find:
Overall (affected group): average:36.770000 variance: 24.357100 std_deviation: 4.935291
Overall (winners): average:367.810000 variance: 83.853900 std_deviation: 9.157178
But what happens with our 1% systemic unfairness paradigm?
Overall (affected group): average:4.470000 variance: 4.169100 std_deviation: 2.041837
Overall (winners): average:358.460000 variance: 97.348400 std_deviation: 9.866529
The affected group goes from making up 10.00% of the winners to only making up 1.25%, because only 1% of the overall population refuses to allow them a fair chance in the game.
By now, you really should know what comes next…
Let’s go a little further. What if only 0.1% of the players (only one person in our population of 1000 players) decides that they won’t give a pebble to a specific group comprising 10% of the population? Surely, systemic unfairness on such a small scale can’t have a measurable impact…
Overall (affected group): average:30.290000 variance: 23.885900 std_deviation: 4.887320
Overall (winners): average:369.440000 variance: 89.066400 std_deviation: 9.437500
With only 0.1% of the population behaving unfairly, the marginalized group now makes up, on average, only 8.20% of the winning population (when, in a completely fair game, they made up 10.00%).
Apparently, even the smallest amount of built-in unfairness can have a profound impact.
-TL
Tom Liston
Owner, Principal Consultant
Bad Wolf Security, LLC
Mastodon: @tliston@infosec.exchange
Twitter (yes, I know… X): @tliston
April 28, 2021