/
improved.py
97 lines (84 loc) · 3.56 KB
/
improved.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
from collections import Counter
from random import choices, seed
def _create_trial_school(
population: int, prob_sped: float, prob_low_ses: float
) -> Counter:
"""Creates a counter of students with one of four possible labels: ('sped low',
'sped high', 'gen_ed low' 'gen_ed high').
:population: int The number of students in the school.
:prob_sped: float The probability that a student is labeled as sped.
:prob_low_ses: float The probability that a student labeled as low ses.
:returns: Counter The number of students with each label.
"""
prob_gen_ed = 1 - prob_sped
prob_high_ses = 1 - prob_low_ses
labels = ("sped low", "sped high", "gen_ed low", "gen_ed high")
probabilities = (
round(prob_sped * prob_low_ses, 3),
round(prob_sped * prob_high_ses, 3),
round(prob_gen_ed * prob_low_ses, 3),
round(prob_gen_ed * prob_high_ses, 3),
)
return Counter(choices(population=labels, weights=probabilities, k=population))
def _update_pr_counts(
pr_counter: Counter,
percent_low_ses_overall: float,
percent_low_ses_in_sped: float,
) -> None:
"""Updates the number of schools that have proportional representation.
:pr_counter: Counter The proportional representation counter to be updated.
:percent_low_ses_overall: float The percentage of students at the school who are
labeled low income.
:percent_low_ses_in_sped: float The percentage of students who are labeled both as
low income and sped.
:returns: Counter The proportional representation counter updated if the school has
proportional representation.
"""
pr_delta = percent_low_ses_overall - percent_low_ses_in_sped
if pr_delta == 0:
pr_counter.update(["exact"])
if 0 <= pr_delta <= 0.02:
pr_counter.update(["within range"])
return pr_counter
def run_trials(
trials: int,
population: int,
prob_sped: float,
prob_low_ses: float,
print_results: bool = True,
) -> dict[str, float]:
"""Run trials simulating a school with a given probabilities of students being
labeled sped and low ses.
:trials: int The number of trials to run.
:population: int The number of students at the school.
:prob_sped: float The probability that a student is labeled as sped.
:prob_low_ses: float The probability that a student is labeled as low ses.
:returns: dict Contains the percentages of schools that have proportional
representation across all trials.
"""
proportional_representation = Counter()
for _ in range(trials):
school = _create_trial_school(population, prob_sped, prob_low_ses)
count_sped = school["sped low"] + school["sped high"]
count_low_ses = school["sped low"] + school["gen_ed low"]
proportional_representation = _update_pr_counts(
proportional_representation,
percent_low_ses_overall=round(count_low_ses / population, 3),
percent_low_ses_in_sped=round(school["sped low"] / count_sped, 3),
)
results = {
pr: round(count / trials * 100, 2)
for pr, count in proportional_representation.items()
}
if print_results:
print(
f"The probability of having exact proportional representation in {trials:,} trials is: {results.get('exact', 0.0)}%"
)
print(
f"The probability of being within 2% in {trials:,} trials is: {results.get('within range', 0.0)}%"
)
return results
if __name__ == "__main__":
seed(1)
trials = 10000
results = run_trials(trials, 600, 0.166, 0.35)