@@ -543,6 +543,59 @@ def _get_confidence_intervals(self, model):
543
543
return [ci_low .values [0 ], ci_high .values [0 ]]
544
544
545
545
546
+ class InstrumentalVariableEstimator (Estimator ):
547
+ """
548
+ Carry out estimation using instrumental variable adjustment rather than conventional adjustment. This means we do
549
+ not need to observe all confounders in order to adjust for them. A key assumption here is linearity.
550
+ """
551
+
552
+ def __init__ (
553
+ self ,
554
+ treatment : tuple ,
555
+ treatment_value : float ,
556
+ control_value : float ,
557
+ adjustment_set : set ,
558
+ outcome : tuple ,
559
+ instrument : str ,
560
+ df : pd .DataFrame = None ,
561
+ intercept : int = 1 ,
562
+ ):
563
+ super ().__init__ (treatment , treatment_value , control_value , adjustment_set , outcome , df , None )
564
+ self .intercept = intercept
565
+ self .model = None
566
+ self .instrument = instrument
567
+
568
+ def add_modelling_assumptions (self ):
569
+ """
570
+ Add modelling assumptions to the estimator. This is a list of strings which list the modelling assumptions that
571
+ must hold if the resulting causal inference is to be considered valid.
572
+ """
573
+ self .modelling_assumptions += """The instrument and the treatment, and the treatment and the outcome must be
574
+ related linearly in the form Y = aX + b."""
575
+ self .modelling_assumptions += """The three IV conditions must hold
576
+ (i) Instrument is associated with treatment
577
+ (ii) Instrument does not affect outcome except through its potential effect on treatment
578
+ (iii) Instrument and outcome do not share causes
579
+ """
580
+
581
+ def estimate_coefficient (self ):
582
+ """
583
+ Estimate the linear regression coefficient of the treatment on the outcome.
584
+ """
585
+
586
+ # Estimate the total effect of instrument I on outcome Y = abI + c1
587
+ ab = sm .OLS (self .df [self .outcome ], self .df [[self .instrument ]]).fit ().params [self .instrument ]
588
+
589
+ # Estimate the direct effect of instrument I on treatment X = aI + c1
590
+ a = sm .OLS (self .df [self .treatment ], self .df [[self .instrument ]]).fit ().params [self .instrument ]
591
+
592
+ # Estimate the coefficient of I on X by cancelling
593
+ return ab / a
594
+
595
+ def estimate_ate (self ):
596
+ return (self .treatment_value - self .control_value ) * self .estimate_coefficient (), (None , None )
597
+
598
+
546
599
class CausalForestEstimator (Estimator ):
547
600
"""A causal random forest estimator is a non-parametric estimator which recursively partitions the covariate space
548
601
to learn a low-dimensional representation of treatment effect heterogeneity. This form of estimator is best suited
0 commit comments