in causalml/optimize/unit_selection.py [0:0]
def _obj_func_midp(self, data, treatment, outcome):
"""
Calculates bounds for the objective function. Returns the midpoint
between bounds.
Parameters
----------
pr_y1_w1 : float
The probability of conversion given treatment assignment.
pr_y1_w0 : float
The probability of conversion given control assignment.
pr_y0_w1 : float
The probability of no conversion given treatment assignment
(1 - pr_y1_w1).
pr_y0_w0 : float
The probability of no conversion given control assignment
(1 - pr_1y_w0)
pr_y1w1_x : float
Probability of complier or always-taker given X.
pr_y0w0_x : float
Probability of complier or never-taker given X.
pr_y1w0_x : float
Probability of defier or always-taker given X.
pr_y0w1_x : float
Probability of never-taker or defier given X.
pr_y_x : float
Organic probability of conversion.
"""
X = data.drop([treatment, outcome], axis=1)
beta = self.complier_payoff
gamma = self.alwaystaker_payoff
theta = self.nevertaker_payoff
delta = self.defier_payoff
pr_y0_w1, pr_y1_w1 = np.split(
self.trt_model.predict_proba(X), indices_or_sections=2, axis=1
)
pr_y0_w0, pr_y1_w0 = np.split(
self.ctr_model.predict_proba(X), indices_or_sections=2, axis=1
)
segment_prob = self.segment_model.predict_proba(X)
segment_name = self.segment_model.classes_
pr_y1w1_x = segment_prob[:, segment_name == "AC"]
pr_y0w0_x = segment_prob[:, segment_name == "NC"]
pr_y1w0_x = segment_prob[:, segment_name == "AD"]
pr_y0w1_x = segment_prob[:, segment_name == "ND"]
if self.organic_conversion is not None:
pr_y_x = self.organic_conversion
else:
pr_y_x = pr_y1_w0
warnings.warn(
"Probability of organic conversion estimated from control observations."
)
p1 = (beta - theta) * pr_y1_w1 + delta * pr_y1_w0 + theta * pr_y0_w0
p2 = gamma * pr_y1_w1 + delta * pr_y0_w1 + (beta - gamma) * pr_y0_w0
p3 = (
(gamma - delta) * pr_y1_w1
+ delta * pr_y1_w0
+ theta * pr_y0_w0
+ (beta - gamma - theta + delta) * (pr_y1w1_x + pr_y0w0_x)
)
p4 = (
(beta - theta) * pr_y1_w1
- (beta - gamma - theta) * pr_y1_w0
+ theta * pr_y0_w0
+ (beta - gamma - theta + delta) * (pr_y1w0_x + pr_y0w1_x)
)
p5 = (gamma - delta) * pr_y1_w1 + delta * pr_y1_w0 + theta * pr_y0_w0
p6 = (
(beta - theta) * pr_y1_w1
- (beta - gamma - theta) * pr_y1_w0
+ theta * pr_y0_w0
)
p7 = (
(gamma - delta) * pr_y1_w1
- (beta - gamma - theta) * pr_y1_w0
+ theta * pr_y0_w0
+ (beta - gamma - theta + delta) * pr_y_x
)
p8 = (
(beta - theta) * pr_y1_w1
+ delta * pr_y1_w0
+ theta * pr_y0_w0
- (beta - gamma - theta + delta) * pr_y_x
)
params_1 = np.concatenate((p1, p2, p3, p4), axis=1)
params_2 = np.concatenate((p5, p6, p7, p8), axis=1)
sigma = beta - gamma - theta + delta
if sigma < 0:
lower_bound = np.max(params_1, axis=1)
upper_bound = np.min(params_2, axis=1)
elif sigma > 0:
lower_bound = np.max(params_2, axis=1)
upper_bound = np.min(params_1, axis=1)
return (lower_bound + upper_bound) / 2