3. X-learner#
Next, let’s introduce the X-learner. As a combination of S-learner and T-learner, the X-learner can use information from the control(treatment) group to derive better estimators for the treatment(control) group, which is provably more efficient than the above two.
The algorithm of X learner can be summarized as the following steps:
Step 1: Estimate \(\mu_0(s)\) and \(\mu_1(s)\) separately with any regression algorithms or supervised machine learning methods (same as T-learner);
Step 2: Obtain the imputed treatment effects for individuals
Step 3: Fit the imputed treatment effects to obtain \(\hat\tau_1(s):=\mathbb{E}[\tilde{\Delta}_i^1|S=s]\) and \(\hat\tau_0(s):=\mathbb{E}[\tilde{\Delta}_i^0|S=s]\);
Step 4: The final HTE estimator is given by
where \(g(s)\) is a weight function between \([0,1]\). A possible way is to use the propensity score model as an estimate of \(g(s)\).
# import related packages
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt;
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.linear_model import LinearRegression
from causaldm.learners.CEL.Single_Stage import _env_getdata_CEL
MovieLens Data#
# Get the MovieLens data
MovieLens_CEL = _env_getdata_CEL.get_movielens_CEL()
MovieLens_CEL.pop(MovieLens_CEL.columns[0])
MovieLens_CEL = MovieLens_CEL[MovieLens_CEL.columns.drop(['Comedy','Action', 'Thriller'])]
MovieLens_CEL
user_id | movie_id | rating | age | Drama | Sci-Fi | gender_M | occupation_academic/educator | occupation_college/grad student | occupation_executive/managerial | occupation_other | occupation_technician/engineer | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 48.0 | 1193.0 | 4.0 | 25.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
1 | 48.0 | 919.0 | 4.0 | 25.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
2 | 48.0 | 527.0 | 5.0 | 25.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
3 | 48.0 | 1721.0 | 4.0 | 25.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
4 | 48.0 | 150.0 | 4.0 | 25.0 | 1.0 | 0.0 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
65637 | 5878.0 | 3300.0 | 2.0 | 25.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
65638 | 5878.0 | 1391.0 | 1.0 | 25.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
65639 | 5878.0 | 185.0 | 4.0 | 25.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
65640 | 5878.0 | 2232.0 | 1.0 | 25.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
65641 | 5878.0 | 426.0 | 3.0 | 25.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
65642 rows × 12 columns
n = len(MovieLens_CEL)
userinfo_index = np.array([3,6,7,8,9,10,11])
SandA = MovieLens_CEL.iloc[:, np.array([3,4,6,7,8,9,10,11])]
# Step 1: Fit two models under treatment and control separately, same as T-learner
import numpy as np
mu0 = GradientBoostingRegressor(max_depth=3)
mu1 = GradientBoostingRegressor(max_depth=3)
S_T0 = MovieLens_CEL.iloc[np.where(MovieLens_CEL['Drama']==0)[0],userinfo_index]
S_T1 = MovieLens_CEL.iloc[np.where(MovieLens_CEL['Drama']==1)[0],userinfo_index]
R_T0 = MovieLens_CEL.iloc[np.where(MovieLens_CEL['Drama']==0)[0],2]
R_T1 = MovieLens_CEL.iloc[np.where(MovieLens_CEL['Drama']==1)[0],2]
mu0.fit(S_T0, R_T0)
mu1.fit(S_T1, R_T1)
GradientBoostingRegressor()
# Step 2: impute the potential outcomes that are unobserved in original data
n_T0 = len(R_T0)
n_T1 = len(R_T1)
Delta0 = mu1.predict(S_T0) - R_T0
Delta1 = R_T1 - mu0.predict(S_T1)
# Step 3: Fit tau_1(s) and tau_0(s)
tau0 = GradientBoostingRegressor(max_depth=2)
tau1 = GradientBoostingRegressor(max_depth=2)
tau0.fit(S_T0, Delta0)
tau1.fit(S_T1, Delta1)
GradientBoostingRegressor(max_depth=2)
# Step 4: fit the propensity score model $\hat{g}(s)$ and obtain the final HTE estimator by taking weighted average of tau0 and tau1
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import GradientBoostingRegressor
g = LogisticRegression()
g.fit(MovieLens_CEL.iloc[:,userinfo_index],MovieLens_CEL['Drama'])
HTE_X_learner = g.predict_proba(MovieLens_CEL.iloc[:,userinfo_index])[:,0]*tau0.predict(MovieLens_CEL.iloc[:,userinfo_index]) + g.predict_proba(MovieLens_CEL.iloc[:,userinfo_index])[:,1]*tau1.predict(MovieLens_CEL.iloc[:,userinfo_index])
Let’s focus on the estimated HTEs for three randomly chosen users:
print("X-learner: ",HTE_X_learner[np.array([0,1000,5000])])
X-learner: [0.33630057 0.31723622 0.37261498]
ATE_X_learner = np.sum(HTE_X_learner)/n
print("Choosing Drama instead of Sci-Fi is expected to improve the rating of all users by",round(ATE_X_learner,4), "out of 5 points.")
Choosing Drama instead of Sci-Fi is expected to improve the rating of all users by 0.3566 out of 5 points.
Conclusion: Same as the estimation result provided by S-learner and T-learner, people are more inclined to give higher ratings to drama than science fictions.
Note: For more details about the meta learners, please refer to [1] as a detailed introduction of related methods.
References#
Kunzel, S. R., Sekhon, J. S., Bickel, P. J., and Yu, B. (2019). Metalearners for estimating heterogeneous treatment effects using machine learning. Proceedings of the national academy of sciences 116, 4156–4165.