Skip to content

Commit 2bd9a0f

Browse files
authored
Merge pull request #138 from washingtonpost/hotfix-partial-reporting
hotfix for partial reporting bug
2 parents 71b70be + 2c0df30 commit 2bd9a0f

File tree

2 files changed

+27
-39
lines changed

2 files changed

+27
-39
lines changed

src/elexmodel/models/BootstrapElectionModel.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,10 @@ def _generate_nonreporting_bounds(
357357

358358
# if percent reporting is 0 or 1, don't try to compute anything and revert to naive bounds
359359
lower_bound[
360-
np.isclose(nonreporting_expected_vote_frac, 0) | np.isclose(nonreporting_expected_vote_frac, 1)
360+
(nonreporting_expected_vote_frac < 0.5) | np.isclose(nonreporting_expected_vote_frac, 1)
361361
] = unobserved_lower_bound
362362
upper_bound[
363-
np.isclose(nonreporting_expected_vote_frac, 0) | np.isclose(nonreporting_expected_vote_frac, 1)
363+
(nonreporting_expected_vote_frac < 0.5) | np.isclose(nonreporting_expected_vote_frac, 1)
364364
] = unobserved_upper_bound
365365

366366
return lower_bound.values.reshape(-1, 1), upper_bound.values.reshape(-1, 1)

tests/models/test_bootstrap_election_model.py

+25-37
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def test_estimate_strata_dist(bootstrap_election_model, rng):
149149

150150
def test_generate_nonreporting_bounds(bootstrap_election_model, rng):
151151
nonreporting_units = pd.DataFrame(
152-
[[0.1, 1.2, 75], [0.8, 0.8, 24], [0.1, 0.01, 0], [-0.2, 0.8, 99], [-0.3, 0.9, 100]],
152+
[[0.1, 1.2, 75], [0.1, 0.01, 0], [-0.2, 0.8, 99], [-0.3, 0.9, 100]],
153153
columns=["results_normalized_margin", "turnout_factor", "percent_expected_vote"],
154154
)
155155

@@ -162,35 +162,29 @@ def test_generate_nonreporting_bounds(bootstrap_election_model, rng):
162162
assert lower[0] == pytest.approx(-0.175)
163163
assert upper[0] == pytest.approx(0.325)
164164

165-
assert lower[1] == pytest.approx(-0.568)
166-
assert upper[1] == pytest.approx(0.952)
167-
168165
# if expected vote is close to 0 or 1 we set the bounds to be the extreme case
169-
assert lower[2] == bootstrap_election_model.y_unobserved_lower_bound
170-
assert upper[2] == bootstrap_election_model.y_unobserved_upper_bound
166+
assert lower[1] == bootstrap_election_model.y_unobserved_lower_bound
167+
assert upper[1] == bootstrap_election_model.y_unobserved_upper_bound
171168

172-
assert lower[3] == pytest.approx(-0.208)
173-
assert upper[3] == pytest.approx(-0.188)
169+
assert lower[2] == pytest.approx(-0.208)
170+
assert upper[2] == pytest.approx(-0.188)
174171

175-
assert lower[4] == bootstrap_election_model.y_unobserved_lower_bound
176-
assert upper[4] == bootstrap_election_model.y_unobserved_upper_bound
172+
assert lower[3] == bootstrap_election_model.y_unobserved_lower_bound
173+
assert upper[3] == bootstrap_election_model.y_unobserved_upper_bound
177174

178175
lower, upper = bootstrap_election_model._generate_nonreporting_bounds(nonreporting_units, "turnout_factor")
179176

180177
assert lower[0] == pytest.approx(0.96)
181178
assert upper[0] == pytest.approx(4.8)
182179

183-
assert lower[1] == pytest.approx(1.081081081)
184-
assert upper[1] == pytest.approx(80) # this is 80 since we divide 0.8 / 0.01 (it's clipped)
185-
186-
assert lower[2] == bootstrap_election_model.z_unobserved_lower_bound
187-
assert upper[2] == bootstrap_election_model.z_unobserved_upper_bound
180+
assert lower[1] == bootstrap_election_model.z_unobserved_lower_bound
181+
assert upper[1] == bootstrap_election_model.z_unobserved_upper_bound
188182

189-
assert lower[3] == pytest.approx(0.536912752)
190-
assert upper[3] == pytest.approx(1.632653061)
183+
assert lower[2] == pytest.approx(0.536912752)
184+
assert upper[2] == pytest.approx(1.632653061)
191185

192-
assert lower[4] == bootstrap_election_model.z_unobserved_lower_bound
193-
assert upper[4] == bootstrap_election_model.z_unobserved_upper_bound
186+
assert lower[3] == bootstrap_election_model.z_unobserved_lower_bound
187+
assert upper[3] == bootstrap_election_model.z_unobserved_upper_bound
194188

195189
# changing parameters
196190
bootstrap_election_model.y_unobserved_lower_bound = -0.8
@@ -202,17 +196,14 @@ def test_generate_nonreporting_bounds(bootstrap_election_model, rng):
202196
assert lower[0] == pytest.approx(-0.125)
203197
assert upper[0] == pytest.approx(0.275)
204198

205-
assert lower[1] == pytest.approx(-0.416)
206-
assert upper[1] == pytest.approx(0.8)
199+
assert lower[1] == bootstrap_election_model.y_unobserved_lower_bound
200+
assert upper[1] == bootstrap_election_model.y_unobserved_upper_bound
207201

208-
assert lower[2] == bootstrap_election_model.y_unobserved_lower_bound
209-
assert upper[2] == bootstrap_election_model.y_unobserved_upper_bound
202+
assert lower[2] == pytest.approx(-0.206)
203+
assert upper[2] == pytest.approx(-0.19)
210204

211-
assert lower[3] == pytest.approx(-0.206)
212-
assert upper[3] == pytest.approx(-0.19)
213-
214-
assert lower[4] == bootstrap_election_model.y_unobserved_lower_bound
215-
assert upper[4] == bootstrap_election_model.y_unobserved_upper_bound
205+
assert lower[3] == bootstrap_election_model.y_unobserved_lower_bound
206+
assert upper[3] == bootstrap_election_model.y_unobserved_upper_bound
216207

217208
bootstrap_election_model.y_unobserved_lower_bound = 0.8
218209
bootstrap_election_model.y_unobserved_upper_bound = 1.2
@@ -222,17 +213,14 @@ def test_generate_nonreporting_bounds(bootstrap_election_model, rng):
222213
assert lower[0] == pytest.approx(1.411764706)
223214
assert upper[0] == pytest.approx(1.846153846)
224215

225-
assert lower[1] == pytest.approx(2.352941176)
226-
assert upper[1] == pytest.approx(5.714285714)
227-
228-
assert lower[2] == bootstrap_election_model.z_unobserved_lower_bound
229-
assert upper[2] == bootstrap_election_model.z_unobserved_upper_bound
216+
assert lower[1] == bootstrap_election_model.z_unobserved_lower_bound
217+
assert upper[1] == bootstrap_election_model.z_unobserved_upper_bound
230218

231-
assert lower[3] == pytest.approx(0.733944954)
232-
assert upper[3] == pytest.approx(0.898876404)
219+
assert lower[2] == pytest.approx(0.733944954)
220+
assert upper[2] == pytest.approx(0.898876404)
233221

234-
assert lower[4] == bootstrap_election_model.z_unobserved_lower_bound
235-
assert upper[4] == bootstrap_election_model.z_unobserved_upper_bound
222+
assert lower[3] == bootstrap_election_model.z_unobserved_lower_bound
223+
assert upper[3] == bootstrap_election_model.z_unobserved_upper_bound
236224

237225

238226
def test_strata_pit(bootstrap_election_model, rng):

0 commit comments

Comments
 (0)