@@ -28,19 +28,28 @@ def print_coefficients(self):
28
28
"""Prints the model coefficients"""
29
29
print ("Model coefficients:" )
30
30
coeffs = az .extract (self .prediction_model .idata .posterior , var_names = "beta" )
31
- # Note: f"{name: <30}" pads the name with spaces so that we have alignment of the stats despite variable names of different lengths
31
+ # Note: f"{name: <30}" pads the name with spaces so that we have alignment of
32
+ # the stats despite variable names of different lengths
32
33
for name in self .labels :
33
34
coeff_samples = coeffs .sel (coeffs = name )
34
35
print (
35
- f" { name : <30} { coeff_samples .mean ().data :.2f} , 94% HDI [{ coeff_samples .quantile (0.03 ).data :.2f} , { coeff_samples .quantile (1 - 0.03 ).data :.2f} ]"
36
+ f"""
37
+ { name : <30} { coeff_samples .mean ().data :.2f} ,
38
+ 94% HDI [{ coeff_samples .quantile (0.03 ).data :.2f} ,
39
+ { coeff_samples .quantile (1 - 0.03 ).data :.2f} ]
40
+ """
36
41
)
37
42
# add coeff for measurement std
38
43
coeff_samples = az .extract (
39
44
self .prediction_model .idata .posterior , var_names = "sigma"
40
45
)
41
46
name = "sigma"
42
47
print (
43
- f" { name : <30} { coeff_samples .mean ().data :.2f} , 94% HDI [{ coeff_samples .quantile (0.03 ).data :.2f} , { coeff_samples .quantile (1 - 0.03 ).data :.2f} ]"
48
+ f"""
49
+ { name : <30} { coeff_samples .mean ().data :.2f} ,
50
+ 94% HDI [{ coeff_samples .quantile (0.03 ).data :.2f} ,
51
+ { coeff_samples .quantile (1 - 0.03 ).data :.2f} ]
52
+ """
44
53
)
45
54
46
55
@@ -121,8 +130,12 @@ def plot(self):
121
130
include_label = False ,
122
131
)
123
132
ax [0 ].plot (self .datapost .index , self .post_y , "k." )
133
+
124
134
ax [0 ].set (
125
- title = f"Pre-intervention Bayesian $R^2$: { self .score .r2 :.3f} (std = { self .score .r2_std :.3f} )"
135
+ title = f"""
136
+ Pre-intervention Bayesian $R^2$: { self .score .r2 :.3f}
137
+ (std = { self .score .r2_std :.3f} )
138
+ """
126
139
)
127
140
128
141
plot_xY (self .datapre .index , self .pre_impact , ax = ax [1 ])
@@ -198,7 +211,8 @@ class DifferenceInDifferences(ExperimentalDesign):
198
211
199
212
.. note::
200
213
201
- There is no pre/post intervention data distinction for DiD, we fit all the data available.
214
+ There is no pre/post intervention data distinction for DiD, we fit all the
215
+ data available.
202
216
203
217
"""
204
218
@@ -239,16 +253,26 @@ def __init__(
239
253
assert (
240
254
"treated" in self .data .columns
241
255
), "Require a boolean column labelling observations which are `treated`"
242
- # Check for `unit` in the incoming dataframe. *This is only used for plotting purposes*
256
+ # Check for `unit` in the incoming dataframe.
257
+ # *This is only used for plotting purposes*
243
258
assert (
244
259
"unit" in self .data .columns
245
- ), "Require a `unit` column to label unique units. This is used for plotting purposes"
246
- # Check that `group_variable_name` has TWO levels, representing the treated/untreated. But it does not matter what the actual names of the levels are.
260
+ ), """
261
+ Require a `unit` column to label unique units.
262
+ This is used for plotting purposes
263
+ """
264
+ # Check that `group_variable_name` has TWO levels, representing the
265
+ # treated/untreated. But it does not matter what the actual names of
266
+ # the levels are.
247
267
assert (
248
- len (pd .Categorical (self .data [self .group_variable_name ]).categories ) is 2
249
- ), f"There must be 2 levels of the grouping variable { self .group_variable_name } . I.e. the treated and untreated."
268
+ len (pd .Categorical (self .data [self .group_variable_name ]).categories ) == 2
269
+ ), f"""
270
+ There must be 2 levels of the grouping variable { self .group_variable_name }
271
+ .I.e. the treated and untreated.
272
+ """
250
273
251
- # TODO: `treated` is a deterministic function of group and time, so this could be a function rather than supplied data
274
+ # TODO: `treated` is a deterministic function of group and time, so this could
275
+ # be a function rather than supplied data
252
276
253
277
# DEVIATION FROM SKL EXPERIMENT CODE =============================
254
278
# fit the model to the observed (pre-intervention) data
@@ -348,11 +372,13 @@ def plot(self):
348
372
showmedians = False ,
349
373
widths = 0.2 ,
350
374
)
375
+
351
376
for pc in parts ["bodies" ]:
352
377
pc .set_facecolor ("C1" )
353
378
pc .set_edgecolor ("None" )
354
379
pc .set_alpha (0.5 )
355
- # Plot counterfactual - post-test for treatment group IF no treatment had occurred.
380
+ # Plot counterfactual - post-test for treatment group IF no treatment
381
+ # had occurred.
356
382
parts = ax .violinplot (
357
383
az .extract (
358
384
self .y_pred_counterfactual ,
@@ -380,7 +406,8 @@ def plot(self):
380
406
381
407
def _plot_causal_impact_arrow (self , ax ):
382
408
"""
383
- draw a vertical arrow between `y_pred_counterfactual` and `y_pred_counterfactual`
409
+ draw a vertical arrow between `y_pred_counterfactual` and
410
+ `y_pred_counterfactual`
384
411
"""
385
412
# Calculate y values to plot the arrow between
386
413
y_pred_treatment = (
@@ -438,13 +465,16 @@ class RegressionDiscontinuity(ExperimentalDesign):
438
465
439
466
:param data: A pandas dataframe
440
467
:param formula: A statistical model formula
441
- :param treatment_threshold: A scalar threshold value at which the treatment is applied
468
+ :param treatment_threshold: A scalar threshold value at which the treatment
469
+ is applied
442
470
:param prediction_model: A PyMC model
443
- :param running_variable_name: The name of the predictor variable that the treatment threshold is based upon
471
+ :param running_variable_name: The name of the predictor variable that the treatment
472
+ threshold is based upon
444
473
445
474
.. note::
446
475
447
- There is no pre/post intervention data distinction for the regression discontinuity design, we fit all the data available.
476
+ There is no pre/post intervention data distinction for the regression
477
+ discontinuity design, we fit all the data available.
448
478
"""
449
479
450
480
def __init__ (
@@ -469,7 +499,8 @@ def __init__(
469
499
self .y , self .X = np .asarray (y ), np .asarray (X )
470
500
self .outcome_variable_name = y .design_info .column_names [0 ]
471
501
472
- # TODO: `treated` is a deterministic function of x and treatment_threshold, so this could be a function rather than supplied data
502
+ # TODO: `treated` is a deterministic function of x and treatment_threshold, so
503
+ # this could be a function rather than supplied data
473
504
474
505
# DEVIATION FROM SKL EXPERIMENT CODE =============================
475
506
# fit the model to the observed (pre-intervention) data
@@ -492,8 +523,10 @@ def __init__(
492
523
(new_x ,) = build_design_matrices ([self ._x_design_info ], self .x_pred )
493
524
self .pred = self .prediction_model .predict (X = np .asarray (new_x ))
494
525
495
- # calculate discontinuity by evaluating the difference in model expectation on either side of the discontinuity
496
- # NOTE: `"treated": np.array([0, 1])`` assumes treatment is applied above (not below) the threshold
526
+ # calculate discontinuity by evaluating the difference in model expectation on
527
+ # either side of the discontinuity
528
+ # NOTE: `"treated": np.array([0, 1])`` assumes treatment is applied above
529
+ # (not below) the threshold
497
530
self .x_discon = pd .DataFrame (
498
531
{
499
532
self .running_variable_name : np .array (
@@ -514,7 +547,7 @@ def _is_treated(self, x):
514
547
515
548
.. warning::
516
549
517
- Assumes treatment is given to those ABOVE the treatment threshold.
550
+ Assumes treatment is given to those ABOVE the treatment threshold.
518
551
"""
519
552
return np .greater_equal (x , self .treatment_threshold )
520
553
@@ -536,10 +569,13 @@ def plot(self):
536
569
ax = ax ,
537
570
)
538
571
# create strings to compose title
539
- r2 = f"Bayesian $R^2$ on all data = { self .score .r2 :.3f} (std = { self .score .r2_std :.3f} )"
572
+ title_info = f"{ self .score .r2 :.3f} (std = { self .score .r2_std :.3f} )"
573
+ r2 = f"Bayesian $R^2$ on all data = { title_info } "
540
574
percentiles = self .discontinuity_at_threshold .quantile ([0.03 , 1 - 0.03 ]).values
541
575
ci = r"$CI_{94\%}$" + f"[{ percentiles [0 ]:.2f} , { percentiles [1 ]:.2f} ]"
542
- discon = f"Discontinuity at threshold = { self .discontinuity_at_threshold .mean ():.2f} , "
576
+ discon = f"""
577
+ Discontinuity at threshold = { self .discontinuity_at_threshold .mean ():.2f} ,
578
+ """
543
579
ax .set (title = r2 + "\n " + discon + ci )
544
580
# Intervention line
545
581
ax .axvline (
@@ -559,7 +595,7 @@ def summary(self):
559
595
print (f"Formula: { self .formula } " )
560
596
print (f"Running variable: { self .running_variable_name } " )
561
597
print (f"Threshold on running variable: { self .treatment_threshold } " )
562
- print (f "\n Results:" )
598
+ print ("\n Results:" )
563
599
print (
564
600
f"Discontinuity at threshold = { self .discontinuity_at_threshold .mean ():.2f} "
565
601
)
0 commit comments