import%20marimo%0A%0A__generated_with%20%3D%20%220.24.0%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20dice_ml%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20import%20plotly.graph_objects%20as%20go%0A%20%20%20%20from%20plotly.subplots%20import%20make_subplots%0A%20%20%20%20from%20sklearn.datasets%20import%20load_wine%0A%20%20%20%20from%20sklearn.linear_model%20import%20LogisticRegression%0A%20%20%20%20from%20sklearn.metrics%20import%20accuracy_score%0A%20%20%20%20from%20sklearn.model_selection%20import%20train_test_split%0A%20%20%20%20from%20sklearn.preprocessing%20import%20StandardScaler%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20LogisticRegression%2C%0A%20%20%20%20%20%20%20%20StandardScaler%2C%0A%20%20%20%20%20%20%20%20dice_ml%2C%0A%20%20%20%20%20%20%20%20go%2C%0A%20%20%20%20%20%20%20%20load_wine%2C%0A%20%20%20%20%20%20%20%20make_subplots%2C%0A%20%20%20%20%20%20%20%20mo%2C%0A%20%20%20%20%20%20%20%20np%2C%0A%20%20%20%20%20%20%20%20pd%2C%0A%20%20%20%20%20%20%20%20train_test_split%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%5B%E2%86%90%2045%20Shapley%20Values%5D(45_shapley.py)%20%7C%20%5BIndex%5D(..%2Findex.html)%20%7C%20%5B47%20GELU%20Activation%20%E2%86%92%5D(47_gelu.py)%0A%0A%20%20%20%20%23%20Model%20Counterfactuals%3A%20Actionable%20Algorithmic%20Recourse%20and%20Diverse%20Counterfactual%20Explanations%20(DiCE)%0A%0A%20%20%20%20%23%23%20%5Ba%5D%20Why%20do%20you%20need%20to%20know%20these%20concepts%3F%0A%0A%20%20%20%20Feature%20attribution%20frameworks%20(such%20as%20SHAP%20and%20Permutation%20Importance)%20explain%20model%20behavior%20by%20answering%20a%20backward-looking%20diagnostic%20question%3A%20*%22Which%20features%20contributed%20most%20heavily%20to%20the%20model's%20decision%3F%22*%0A%0A%20%20%20%20However%2C%20in%20high-stakes%20automated%20decisions%20(such%20as%20credit%20lending%2C%20job%20candidate%20screening%2C%20college%20admissions%2C%20and%20criminal%20justice%20risk%20scoring)%2C%20an%20applicant%20whose%20loan%20is%20rejected%20is%20not%20helped%20by%20knowing%20that%20their%20credit%20score%20was%20the%20dominant%20negative%20factor.%20The%20applicant%20requires%20an%20actionable%2C%20forward-looking%20answer%20to%20a%20different%20question%3A%0A%0A%20%20%20%20%3E%20**%22What%20minimal%2C%20feasible%20changes%20can%20I%20make%20to%20my%20application%20to%20turn%20this%20rejection%20into%20an%20approval%3F%22**%0A%0A%20%20%20%20%23%23%23%23%20Algorithmic%20Recourse%0A%20%20%20%20**Counterfactual%20Explanations**%20(formalized%20by%20Wachter%2C%20Mittelstadt%2C%20and%20Russell%20in%202017)%20identify%20the%20closest%20possible%20hypothetical%20input%20vector%20%24x%5E*%20%3D%20x%20%2B%20%5CDelta%20x%24%20that%20flips%20the%20model's%20prediction%20across%20the%20decision%20boundary%20to%20the%20desired%20target%20class%20%24y%5E*%24.%0A%0A%20%20%20%20%23%23%23%23%20Model%20Counterfactuals%20vs%20Causal%20Counterfactuals%0A%20%20%20%20-%20**Model%20Counterfactuals**%3A%20Search%20the%20empirical%20decision%20manifold%20of%20a%20frozen%20predictive%20classifier%20%24%5Chat%7Bf%7D(x)%24%20to%20find%20boundary%20crossings.%20They%20operate%20within%20the%20model's%20internal%20feature%20space%20without%20requiring%20an%20underlying%20causal%20Directed%20Acyclic%20Graph%20(DAG).%0A%20%20%20%20-%20**Causal%20Counterfactuals**%3A%20Formulated%20under%20Judea%20Pearl's%20Structural%20Causal%20Models%20(SCMs)%20and%20the%20Potential%20Outcomes%20framework%20(%24do%24-calculus).%20They%20model%20the%20true%20physical%20consequences%20of%20real-world%20interventions%2C%20accounting%20for%20downstream%20ripple%20effects.%0A%0A%20%20%20%20%23%23%23%23%20Diverse%20Counterfactual%20Explanations%20(DiCE)%0A%20%20%20%20Providing%20a%20single%20counterfactual%20is%20often%20inadequate%20in%20practice.%20A%20proposed%20change%20might%20demand%20an%20action%20that%20is%20impossible%20or%20prohibitively%20expensive%20for%20a%20specific%20user%20(e.g.%20moving%20to%20a%20new%20zip%20code%20or%20increasing%20annual%20income%20by%20%24100%2C000%20in%20one%20month).%0A%0A%20%20%20%20**DiCE%20(Mothilal%20et%20al.%2C%202020)**%20addresses%20this%20limitation%20by%20formulating%20a%20multi-objective%20optimization%20problem.%20It%20finds%20a%20diverse%20set%20of%20%24K%24%20distinct%20counterfactuals%2C%20optimizing%20for%3A%0A%20%20%20%201.%20**Proximity**%3A%20Minimizing%20the%20overall%20perturbation%20distance%20between%20the%20factual%20point%20and%20counterfactuals.%0A%20%20%20%202.%20**Sparsity**%3A%20Changing%20as%20few%20features%20as%20possible.%0A%20%20%20%203.%20**Diversity**%3A%20Ensuring%20the%20counterfactuals%20offer%20qualitatively%20different%20pathways%20to%20approval%20via%20Determinantal%20Point%20Processes%20(DPP).%0A%20%20%20%204.%20**Feasibility**%3A%20Enforcing%20immutable%20features%20(e.g.%20age%20cannot%20decrease%2C%20race%20and%20gender%20cannot%20be%20altered)%20and%20realistic%20numerical%20bounds.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20%5Bb%5D%20Mathematical%20Foundations%20and%20Optimization%20Mechanics%0A%0A%20%20%20%20%23%23%23%201.%20The%20Wachter%20Minimal%20Perturbation%20Formulation%0A%0A%20%20%20%20Let%20%24f%3A%20%5Cmathbb%7BR%7D%5Ep%20%5Cto%20%5B0%2C%201%5D%24%20be%20a%20trained%20binary%20classifier%20outputting%20the%20probability%20of%20a%20positive%20outcome.%20Let%20%24x%20%5Cin%20%5Cmathbb%7BR%7D%5Ep%24%20denote%20the%20factual%20observation%20where%20%24f(x)%20%3C%200.5%24%20(e.g.%20loan%20rejected).%20Let%20%24y%5E*%20%3D%201%24%20denote%20the%20desired%20target%20label.%0A%0A%20%20%20%20Finding%20a%20counterfactual%20point%20%24x%5E*%20%5Cin%20%5Cmathbb%7BR%7D%5Ep%24%20is%20formulated%20as%20an%20unconstrained%20optimization%20problem%3A%0A%0A%20%20%20%20%24%24x%5E*%20%3D%20%5Carg%5Cmin_%7Bx'%7D%20%5Coperatorname%7Bdist%7D(x%2C%20x')%20%2B%20%5Clambda%20%5Ccdot%20%5Cell(f(x')%2C%20y%5E*)%24%24%0A%0A%20%20%20%20where%3A%0A%20%20%20%20-%20%24%5Cell(f(x')%2C%20y%5E*)%24%20is%20a%20loss%20function%20penalizing%20deviation%20from%20the%20desired%20prediction%3A%0A%0A%20%20%20%20%24%24%5Cell(f(x')%2C%201)%20%3D%20%5Cmax%5Cleft(0%2C%20%5C%200.5%20-%20f(x')%5Cright)%5E2%20%5Cquad%20%5Ctext%7Bor%7D%20%5Cquad%20-%5Cln(f(x'))%24%24%0A%0A%20%20%20%20-%20%24%5Coperatorname%7Bdist%7D(x%2C%20x')%24%20is%20a%20normalized%20distance%20metric%20in%20feature%20space.%0A%20%20%20%20-%20%24%5Clambda%20%3E%200%24%20is%20a%20regularizing%20hyperparameter%20that%20balances%20proximity%20to%20the%20original%20factual%20instance%20against%20confidence%20in%20crossing%20the%20decision%20boundary.%0A%0A%20%20%20%20%23%23%23%202.%20Distance%20Metrics%3A%20The%20MAD-Normalized%20Manhattan%20Metric%0A%0A%20%20%20%20Using%20standard%20Euclidean%20distance%20(%24L_2%24)%20causes%20high-variance%20features%20to%20dominate%20the%20optimization%20and%20produces%20dense%20solutions%20where%20every%20feature%20is%20perturbed%20by%20a%20tiny%20fraction.%0A%0A%20%20%20%20To%20encourage%20**sparsity**%20(changing%20as%20few%20attributes%20as%20possible)%20and%20account%20for%20feature%20scales%2C%20Wachter%20proposed%20the%20%24L_1%24%20distance%20normalized%20by%20the%20**Median%20Absolute%20Deviation%20(MAD)**%20of%20each%20feature%20across%20the%20training%20population%3A%0A%0A%20%20%20%20%24%24%5Coperatorname%7Bdist%7D_%7B%5Ctext%7BMAD%7D%7D(x%2C%20x')%20%3D%20%5Csum_%7Bj%3D1%7D%5Ep%20%5Cfrac%7B%7Cx_j%20-%20x'_j%7C%7D%7B%5Coperatorname%7BMAD%7D_j%7D%24%24%0A%0A%20%20%20%20where%20the%20Median%20Absolute%20Deviation%20for%20feature%20%24j%24%20is%3A%0A%0A%20%20%20%20%24%24%5Coperatorname%7BMAD%7D_j%20%3D%20%5Coperatorname%7Bmedian%7D_%7Bi%3D1%2C%5Cdots%2CN%7D%20%5Cleft%7C%20x_%7Bij%7D%20-%20%5Coperatorname%7Bmedian%7D_%7Bk%3D1%2C%5Cdots%2CN%7D(x_%7Bkj%7D)%20%5Cright%7C%24%24%0A%0A%20%20%20%20Unlike%20the%20standard%20deviation%2C%20MAD%20is%20robust%20to%20extreme%20training%20outliers.%0A%0A%20%20%20%20%23%23%23%203.%20DiCE%3A%20Multi-Objective%20Diversity%20Optimization%0A%0A%20%20%20%20Rather%20than%20finding%20a%20single%20counterfactual%2C%20DiCE%20generates%20%24K%24%20counterfactuals%20%24%5Cmathcal%7BC%7D%20%3D%20%5C%7Bc_1%2C%20c_2%2C%20%5Cdots%2C%20c_K%5C%7D%24%20by%20optimizing%20a%20joint%20objective%20function%3A%0A%0A%20%20%20%20%24%24%5Cmin_%7Bc_1%2C%20%5Cdots%2C%20c_K%7D%20%5Cfrac%7B1%7D%7BK%7D%5Csum_%7Bk%3D1%7D%5EK%20%5Cell(f(c_k)%2C%20y%5E*)%20%2B%20%5Cfrac%7B%5Clambda_1%7D%7BK%7D%5Csum_%7Bk%3D1%7D%5EK%20%5Coperatorname%7Bdist%7D_%7B%5Ctext%7BMAD%7D%7D(x%2C%20c_k)%20-%20%5Clambda_2%20%5Ccdot%20%5Coperatorname%7Bdpp%5C_diversity%7D(c_1%2C%20%5Cdots%2C%20c_K)%24%24%0A%0A%20%20%20%20The%20diversity%20term%20utilizes%20a%20**Determinantal%20Point%20Process%20(DPP)**.%20Let%20%24%5Cmathbf%7BK%7D%20%5Cin%20%5Cmathbb%7BR%7D%5E%7BK%20%5Ctimes%20K%7D%24%20be%20a%20kernel%20similarity%20matrix%20between%20counterfactual%20candidates%2C%20with%20entries%3A%0A%0A%20%20%20%20%24%24K_%7Bi%2C%20j%7D%20%3D%20%5Cfrac%7B1%7D%7B1%20%2B%20%5Coperatorname%7Bdist%7D(c_i%2C%20c_j)%7D%24%24%0A%0A%20%20%20%20The%20diversity%20reward%20is%20defined%20as%20the%20determinant%20of%20%24%5Cmathbf%7BK%7D%24%3A%0A%0A%20%20%20%20%24%24%5Coperatorname%7Bdpp%5C_diversity%7D(c_1%2C%20%5Cdots%2C%20c_K)%20%3D%20%5Cdet(%5Cmathbf%7BK%7D)%24%24%0A%0A%20%20%20%20-%20If%20two%20counterfactual%20candidates%20%24c_i%24%20and%20%24c_j%24%20are%20nearly%20identical%2C%20the%20rows%20of%20%24%5Cmathbf%7BK%7D%24%20become%20linearly%20dependent%2C%20driving%20%24%5Cdet(%5Cmathbf%7BK%7D)%20%5Cto%200%24.%0A%20%20%20%20-%20Maximizing%20%24%5Cdet(%5Cmathbf%7BK%7D)%24%20repels%20counterfactuals%20from%20one%20another%20in%20feature%20space%2C%20providing%20the%20user%20with%20distinct%20recourse%20strategies.%0A%0A%20%20%20%20%23%23%23%204.%20Feasibility%20and%20Actionability%20Constraints%0A%0A%20%20%20%20Real-world%20recourse%20must%20respect%20domain%20realities%3A%0A%0A%20%20%20%20%24%24%5Cbegin%7Baligned%7D%0A%20%20%20%20c_%7Bk%2C%20j%7D%20%26%3D%20x_j%20%5Cquad%20%5Cforall%20j%20%5Cin%20%5Cmathcal%7BF%7D_%7B%5Ctext%7Bimmutable%7D%7D%20%5Cquad%20%26%5Ctext%7B(e.g.%20Country%20of%20Origin%2C%20Race)%7D%20%5C%5C%0A%20%20%20%20c_%7Bk%2C%20j%7D%20%26%5Cge%20x_j%20%5Cquad%20%5Cforall%20j%20%5Cin%20%5Cmathcal%7BF%7D_%7B%5Ctext%7Bmonotonic%7D%7D%20%5Cquad%20%26%5Ctext%7B(e.g.%20Education%20Level%2C%20Work%20Experience)%7D%20%5C%5C%0A%20%20%20%20L_j%20%26%5Cle%20c_%7Bk%2C%20j%7D%20%5Cle%20U_j%20%5Cquad%20%5Cforall%20j%20%5Cin%20%5C%7B1%2C%20%5Cdots%2C%20p%5C%7D%20%5Cquad%20%26%5Ctext%7B(Physical%20bounds%2C%20e.g.%20%7D%200%20%5Cle%20%5Ctext%7BCredit%20Score%7D%20%5Cle%20850)%0A%20%20%20%20%5Cend%7Baligned%7D%24%24%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20LogisticRegression%2C%0A%20%20%20%20StandardScaler%2C%0A%20%20%20%20dice_ml%2C%0A%20%20%20%20load_wine%2C%0A%20%20%20%20np%2C%0A%20%20%20%20pd%2C%0A%20%20%20%20train_test_split%2C%0A)%3A%0A%20%20%20%20%23%20Load%20standardized%20tabular%20dataset%20(Wine%20classification%3A%20Class%200%20vs%20Other%20classes)%0A%20%20%20%20wine%20%3D%20load_wine(as_frame%3DTrue)%0A%20%20%20%20df_raw%20%3D%20wine.frame%0A%0A%20%20%20%20%23%20Focus%20on%20two%20primary%20continuous%20features%20for%20visual%20geometric%20intuition%3A%0A%20%20%20%20%23%20'alcohol'%20and%20'flavanoids'%0A%20%20%20%20features_subset%20%3D%20%5B%22alcohol%22%2C%20%22flavanoids%22%5D%0A%20%20%20%20x_data%20%3D%20df_raw%5Bfeatures_subset%5D.copy()%0A%20%20%20%20%23%20Binary%20outcome%3A%20Class%200%20(Cultivar%201)%20vs%20Other%20Cultivars%0A%20%20%20%20y_binary%20%3D%20(df_raw%5B%22target%22%5D%20%3D%3D%200).astype(int)%0A%0A%20%20%20%20%23%20Standardize%20features%20for%20linear%20model%20training%0A%20%20%20%20scaler%20%3D%20StandardScaler()%0A%20%20%20%20x_scaled_arr%20%3D%20scaler.fit_transform(x_data)%0A%20%20%20%20df_scaled%20%3D%20pd.DataFrame(x_scaled_arr%2C%20columns%3D%5B%22Alcohol_Std%22%2C%20%22Flavanoids_Std%22%5D)%0A%20%20%20%20df_scaled%5B%22Target%22%5D%20%3D%20y_binary.values%0A%0A%20%20%20%20%23%20Train-test%20split%0A%20%20%20%20x_train%2C%20x_test%2C%20y_train%2C%20y_test%20%3D%20train_test_split(%0A%20%20%20%20%20%20%20%20df_scaled%5B%5B%22Alcohol_Std%22%2C%20%22Flavanoids_Std%22%5D%5D%2C%0A%20%20%20%20%20%20%20%20df_scaled%5B%22Target%22%5D%2C%0A%20%20%20%20%20%20%20%20test_size%3D0.25%2C%0A%20%20%20%20%20%20%20%20random_state%3D42%2C%0A%20%20%20%20%20%20%20%20stratify%3Ddf_scaled%5B%22Target%22%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Train%20logistic%20regression%20classifier%0A%20%20%20%20clf_model%20%3D%20LogisticRegression(random_state%3D42)%0A%20%20%20%20clf_model.fit(x_train%2C%20y_train)%0A%0A%20%20%20%20%23%20Select%20a%20rejected%20factual%20instance%20(Target%20%3D%200%20with%20high%20confidence)%0A%20%20%20%20%23%20Find%20a%20test%20sample%20with%20low%20predicted%20probability%0A%20%20%20%20test_probs%20%3D%20clf_model.predict_proba(x_test)%5B%3A%2C%201%5D%0A%20%20%20%20neg_idx%20%3D%20np.argmin(test_probs)%0A%20%20%20%20factual_sample%20%3D%20x_test.iloc%5Bneg_idx%20%3A%20neg_idx%20%2B%201%5D.copy()%0A%20%20%20%20factual_prob%20%3D%20float(test_probs%5Bneg_idx%5D)%0A%0A%20%20%20%20%23%20Setup%20DiCE%20framework%0A%20%20%20%20d_data%20%3D%20dice_ml.Data(%0A%20%20%20%20%20%20%20%20dataframe%3Dpd.concat(%5Bx_train%2C%20y_train%5D%2C%20axis%3D1)%2C%0A%20%20%20%20%20%20%20%20continuous_features%3D%5B%22Alcohol_Std%22%2C%20%22Flavanoids_Std%22%5D%2C%0A%20%20%20%20%20%20%20%20outcome_name%3D%22Target%22%2C%0A%20%20%20%20)%0A%20%20%20%20d_model%20%3D%20dice_ml.Model(model%3Dclf_model%2C%20backend%3D%22sklearn%22%2C%20model_type%3D%22classifier%22)%0A%20%20%20%20dice_exp%20%3D%20dice_ml.Dice(d_data%2C%20d_model%2C%20method%3D%22random%22)%0A%0A%20%20%20%20%23%20Generate%203%20diverse%20counterfactuals%20targeting%20Class%201%20(approval%20threshold%20p%20%3E%3D%200.5)%0A%20%20%20%20cf_res%20%3D%20dice_exp.generate_counterfactuals(%0A%20%20%20%20%20%20%20%20factual_sample%2C%20total_CFs%3D3%2C%20desired_class%3D1%0A%20%20%20%20)%0A%20%20%20%20df_cfs%20%3D%20cf_res.cf_examples_list%5B0%5D.final_cfs_df%0A%0A%20%20%20%20%23%20Extract%20coordinates%0A%20%20%20%20factual_coords%20%3D%20factual_sample%5B%5B%22Alcohol_Std%22%2C%20%22Flavanoids_Std%22%5D%5D.values%5B0%5D%0A%20%20%20%20cf_coords%20%3D%20df_cfs%5B%5B%22Alcohol_Std%22%2C%20%22Flavanoids_Std%22%5D%5D.values%0A%20%20%20%20return%20cf_coords%2C%20clf_model%2C%20factual_coords%2C%20factual_prob%2C%20x_train%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20cf_coords%2C%0A%20%20%20%20clf_model%2C%0A%20%20%20%20factual_coords%2C%0A%20%20%20%20go%2C%0A%20%20%20%20make_subplots%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20np%2C%0A%20%20%20%20pd%2C%0A%20%20%20%20x_train%2C%0A)%3A%0A%20%20%20%20%23%202D%20Grid%20for%20Decision%20Boundary%0A%20%20%20%20x_min%2C%20x_max%20%3D%20x_train%5B%22Alcohol_Std%22%5D.min()%20-%200.8%2C%20x_train%5B%22Alcohol_Std%22%5D.max()%20%2B%200.8%0A%20%20%20%20y_min%2C%20y_max%20%3D%20x_train%5B%22Flavanoids_Std%22%5D.min()%20-%200.8%2C%20x_train%5B%22Flavanoids_Std%22%5D.max()%20%2B%200.8%0A%0A%20%20%20%20grid_x%2C%20grid_y%20%3D%20np.meshgrid(np.linspace(x_min%2C%20x_max%2C%20100)%2C%20np.linspace(y_min%2C%20y_max%2C%20100))%0A%20%20%20%20grid_points%20%3D%20np.c_%5Bgrid_x.ravel()%2C%20grid_y.ravel()%5D%0A%20%20%20%20grid_df%20%3D%20pd.DataFrame(grid_points%2C%20columns%3D%5B%22Alcohol_Std%22%2C%20%22Flavanoids_Std%22%5D)%0A%20%20%20%20prob_surface%20%3D%20clf_model.predict_proba(grid_df)%5B%3A%2C%201%5D.reshape(grid_x.shape)%0A%0A%20%20%20%20fig%20%3D%20make_subplots(%0A%20%20%20%20%20%20%20%20rows%3D1%2C%0A%20%20%20%20%20%20%20%20cols%3D2%2C%0A%20%20%20%20%20%20%20%20subplot_titles%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cb%3EDecision%20Boundary%20and%20Counterfactual%20Recourse%20Vectors%3C%2Fb%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cb%3EFeature%20Perturbation%20Magnitude%20by%20Recourse%20Option%3C%2Fb%3E%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20horizontal_spacing%3D0.14%2C%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Left%3A%20Decision%20surface%20contour%0A%20%20%20%20fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Contour(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dnp.linspace(x_min%2C%20x_max%2C%20100)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dnp.linspace(y_min%2C%20y_max%2C%20100)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20z%3Dprob_surface%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colorscale%3D%22RdBu%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20contours%3Ddict(start%3D0.1%2C%20end%3D0.9%2C%20size%3D0.1%2C%20showlabels%3DTrue)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colorbar%3Ddict(title%3D%22P(Approved)%22%2C%20x%3D0.44%2C%20len%3D0.8)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Model%20Probability%20P(Y%3D1)%22%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20row%3D1%2C%0A%20%20%20%20%20%20%20%20col%3D1%2C%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Decision%20Boundary%20Line%20(p%20%3D%200.5)%0A%20%20%20%20fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Contour(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Dnp.linspace(x_min%2C%20x_max%2C%20100)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dnp.linspace(y_min%2C%20y_max%2C%20100)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20z%3Dprob_surface%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20contours%3Ddict(type%3D%22constraint%22%2C%20value%3D0.5)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20line%3Ddict(color%3D%22%2310B981%22%2C%20width%3D3)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Decision%20Boundary%20(p%3D0.5)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20showlegend%3DTrue%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20row%3D1%2C%0A%20%20%20%20%20%20%20%20col%3D1%2C%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Plot%20factual%20rejected%20sample%0A%20%20%20%20fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D%5Bfactual_coords%5B0%5D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D%5Bfactual_coords%5B1%5D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%2Btext%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3Ddict(color%3D%22%23DC2626%22%2C%20size%3D14%2C%20symbol%3D%22diamond%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20text%3D%5B%22Factual%20(Rejected)%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20textposition%3D%22bottom%20right%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Factual%20Instance%22%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20row%3D1%2C%0A%20%20%20%20%20%20%20%20col%3D1%2C%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Plot%20counterfactual%20approved%20points%0A%20%20%20%20cf_colors%20%3D%20%5B%22%232563EB%22%2C%20%22%238B5CF6%22%2C%20%22%23F59E0B%22%5D%0A%20%20%20%20for%20i%2C%20(cf%2C%20color)%20in%20enumerate(zip(cf_coords%2C%20cf_colors))%3A%0A%20%20%20%20%20%20%20%20%23%20Point%0A%20%20%20%20%20%20%20%20fig.add_trace(%0A%20%20%20%20%20%20%20%20%20%20%20%20go.Scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3D%5Bcf%5B0%5D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3D%5Bcf%5B1%5D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%2Btext%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20marker%3Ddict(color%3Dcolor%2C%20size%3D12%2C%20symbol%3D%22star%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%3D%5Bf%22CF%20%7Bi%2B1%7D%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20textposition%3D%22top%20left%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3Df%22Counterfactual%20%7Bi%2B1%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20row%3D1%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20col%3D1%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%23%20Vector%20line%20connecting%20factual%20to%20counterfactual%0A%20%20%20%20%20%20%20%20fig.add_trace(%0A%20%20%20%20%20%20%20%20%20%20%20%20go.Scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3D%5Bfactual_coords%5B0%5D%2C%20cf%5B0%5D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3D%5Bfactual_coords%5B1%5D%2C%20cf%5B1%5D%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22lines%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20line%3Ddict(color%3Dcolor%2C%20width%3D2%2C%20dash%3D%22dot%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20showlegend%3DFalse%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20row%3D1%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20col%3D1%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%23%20Right%20Panel%3A%20Feature%20shift%20delta%20bar%20chart%20across%20counterfactuals%0A%20%20%20%20features%20%3D%20%5B%22Alcohol%20(Std)%22%2C%20%22Flavanoids%20(Std)%22%5D%0A%20%20%20%20for%20i%2C%20(cf%2C%20color)%20in%20enumerate(zip(cf_coords%2C%20cf_colors))%3A%0A%20%20%20%20%20%20%20%20deltas%20%3D%20cf%20-%20factual_coords%0A%20%20%20%20%20%20%20%20fig.add_trace(%0A%20%20%20%20%20%20%20%20%20%20%20%20go.Bar(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3Dfeatures%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3Ddeltas%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3Df%22Recourse%20Option%20%7Bi%2B1%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20marker_color%3Dcolor%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20row%3D1%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20col%3D2%2C%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20fig.update_xaxes(title_text%3D%22Standardized%20Alcohol%22%2C%20row%3D1%2C%20col%3D1)%0A%20%20%20%20fig.update_yaxes(title_text%3D%22Standardized%20Flavanoids%22%2C%20row%3D1%2C%20col%3D1)%0A%20%20%20%20fig.update_xaxes(title_text%3D%22Feature%20Dimension%22%2C%20row%3D1%2C%20col%3D2)%0A%20%20%20%20fig.update_yaxes(title_text%3D%22Required%20Shift%20Delta%20(x*%20-%20x)%22%2C%20row%3D1%2C%20col%3D2)%0A%0A%20%20%20%20fig.update_layout(%0A%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20height%3D520%2C%0A%20%20%20%20%20%20%20%20margin%3Ddict(l%3D40%2C%20r%3D40%2C%20t%3D70%2C%20b%3D50)%2C%0A%20%20%20%20%20%20%20%20legend%3Ddict(orientation%3D%22h%22%2C%20yanchor%3D%22bottom%22%2C%20y%3D-0.28%2C%20xanchor%3D%22center%22%2C%20x%3D0.5)%2C%0A%20%20%20%20%20%20%20%20barmode%3D%22group%22%2C%0A%20%20%20%20)%0A%0A%20%20%20%20viz%20%3D%20mo.ui.plotly(fig)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(cf_coords%2C%20clf_model%2C%20factual_coords%2C%20factual_prob%2C%20mo%2C%20np%2C%20pd%2C%20x_train)%3A%0A%20%20%20%20%23%20Example%201%3A%20Pure%20NumPy%20Gradient%20Descent%20Solver%20for%20Wachter%20Counterfactual%0A%20%20%20%20def%20wachter_counterfactual_solver(model%2C%20x_fact%2C%20lr%3D0.08%2C%20max_iter%3D200%2C%20lam%3D2.5)%3A%0A%20%20%20%20%20%20%20%20w%20%3D%20model.coef_%5B0%5D%0A%20%20%20%20%20%20%20%20b%20%3D%20model.intercept_%5B0%5D%0A%20%20%20%20%20%20%20%20x_cf%20%3D%20x_fact.copy()%0A%0A%20%20%20%20%20%20%20%20for%20_%20in%20range(max_iter)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Probability%3A%20sigma(w%5ET%20x%20%2B%20b)%0A%20%20%20%20%20%20%20%20%20%20%20%20logit_val%20%3D%20np.dot(w%2C%20x_cf)%20%2B%20b%0A%20%20%20%20%20%20%20%20%20%20%20%20prob%20%3D%201.0%20%2F%20(1.0%20%2B%20np.exp(-logit_val))%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20prob%20%3E%3D%200.505%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Distance%20loss%3A%20%7C%7Cx_cf%20-%20x_fact%7C%7C_2%5E2%0A%20%20%20%20%20%20%20%20%20%20%20%20grad_dist%20%3D%202.0%20*%20(x_cf%20-%20x_fact)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Target%20loss%3A%20(0.5%20-%20prob)%5E2%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20d%2Fdx%20prob%20%3D%20prob%20*%20(1%20-%20prob)%20*%20w%0A%20%20%20%20%20%20%20%20%20%20%20%20d_loss_d_prob%20%3D%20-2.0%20*%20(0.5%20-%20prob)%0A%20%20%20%20%20%20%20%20%20%20%20%20grad_target%20%3D%20d_loss_d_prob%20*%20(prob%20*%20(1.0%20-%20prob))%20*%20w%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20total_grad%20%3D%20grad_dist%20%2B%20lam%20*%20grad_target%0A%20%20%20%20%20%20%20%20%20%20%20%20x_cf%20%3D%20x_cf%20-%20lr%20*%20total_grad%0A%0A%20%20%20%20%20%20%20%20final_prob%20%3D%201.0%20%2F%20(1.0%20%2B%20np.exp(-(np.dot(w%2C%20x_cf)%20%2B%20b)))%0A%20%20%20%20%20%20%20%20return%20x_cf%2C%20final_prob%0A%0A%20%20%20%20scratch_cf%2C%20scratch_prob%20%3D%20wachter_counterfactual_solver(clf_model%2C%20factual_coords)%0A%0A%20%20%20%20df_solver_verif%20%3D%20pd.DataFrame(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Candidate%22%3A%20%22Factual%20(Rejected)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Alcohol_Std%22%3A%20round(factual_coords%5B0%5D%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Flavanoids_Std%22%3A%20round(factual_coords%5B1%5D%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Model_Probability%22%3A%20f%22%7Bfactual_prob%20*%20100%3A.2f%7D%25%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Decision%22%3A%20%22Rejected%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Candidate%22%3A%20%22Wachter%20Solver%20(From%20Scratch)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Alcohol_Std%22%3A%20round(scratch_cf%5B0%5D%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Flavanoids_Std%22%3A%20round(scratch_cf%5B1%5D%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Model_Probability%22%3A%20f%22%7Bscratch_prob%20*%20100%3A.2f%7D%25%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Decision%22%3A%20%22Approved%20(Crossed%20p%3D0.5)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Example%202%3A%20MAD-Normalized%20Distance%20and%20Recourse%20Metric%20Comparison%0A%20%20%20%20mad_values%20%3D%20np.median(%0A%20%20%20%20%20%20%20%20np.abs(x_train.values%20-%20np.median(x_train.values%2C%20axis%3D0))%2C%20axis%3D0%0A%20%20%20%20)%0A%20%20%20%20%23%20Prevent%20divide%20by%20zero%0A%20%20%20%20mad_values%20%3D%20np.maximum(mad_values%2C%201e-4)%0A%0A%20%20%20%20recourse_records%20%3D%20%5B%5D%0A%20%20%20%20for%20idx%2C%20cf_pt%20in%20enumerate(cf_coords)%3A%0A%20%20%20%20%20%20%20%20cf_df_pt%20%3D%20pd.DataFrame(%5Bcf_pt%5D%2C%20columns%3D%5B%22Alcohol_Std%22%2C%20%22Flavanoids_Std%22%5D)%0A%20%20%20%20%20%20%20%20p_cf%20%3D%20clf_model.predict_proba(cf_df_pt)%5B0%2C%201%5D%0A%20%20%20%20%20%20%20%20l1_dist%20%3D%20np.sum(np.abs(cf_pt%20-%20factual_coords))%0A%20%20%20%20%20%20%20%20mad_dist%20%3D%20np.sum(np.abs(cf_pt%20-%20factual_coords)%20%2F%20mad_values)%0A%20%20%20%20%20%20%20%20num_changes%20%3D%20int(np.sum(np.abs(cf_pt%20-%20factual_coords)%20%3E%200.05))%0A%0A%20%20%20%20%20%20%20%20recourse_records.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Recourse_Option%22%3A%20f%22Counterfactual%20%7Bidx%20%2B%201%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Alcohol_Target%22%3A%20round(cf_pt%5B0%5D%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Flavanoids_Target%22%3A%20round(cf_pt%5B1%5D%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Predicted_Probability%22%3A%20f%22%7Bp_cf%20*%20100%3A.2f%7D%25%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22L1_Distance%22%3A%20round(l1_dist%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22MAD_Normalized_Cost%22%3A%20round(mad_dist%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Features_Altered%22%3A%20f%22%7Bnum_changes%7D%20%2F%202%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20df_recourse%20%3D%20pd.DataFrame(recourse_records)%0A%0A%20%20%20%20%23%20Example%203%3A%20Comparison%20between%20Model%20Counterfactuals%20and%20Causal%20Counterfactuals%0A%20%20%20%20df_comparison%20%3D%20pd.DataFrame(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Dimension%22%3A%20%22Operational%20Context%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Model_Counterfactual%22%3A%20%22Inside%20frozen%20ML%20model%20boundary%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Causal_Counterfactual%22%3A%20%22In%20real-world%20physical%20universe%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Dimension%22%3A%20%22Primary%20Objective%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Model_Counterfactual%22%3A%20%22Explain%2Freverse%20model%20prediction%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Causal_Counterfactual%22%3A%20%22Estimate%20intervention%20effect%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Dimension%22%3A%20%22Structural%20Assumption%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Model_Counterfactual%22%3A%20%22Smooth%20classifier%20manifold%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Causal_Counterfactual%22%3A%20%22Structural%20Causal%20Model%20%2F%20DAG%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Dimension%22%3A%20%22Typical%20Use%20Case%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Model_Counterfactual%22%3A%20%22User%20algorithmic%20recourse%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Causal_Counterfactual%22%3A%20%22Policy%20impact%20and%20medical%20treatment%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%0A%20%20%20%20table_solver%20%3D%20mo.ui.table(df_solver_verif)%0A%20%20%20%20table_recourse%20%3D%20mo.ui.table(df_recourse)%0A%20%20%20%20table_comp%20%3D%20mo.ui.table(df_comparison)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
462b459fe7db3f0ae45ecf3a3852ce2c