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%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.linear_model%20import%20LogisticRegression%0A%20%20%20%20from%20statsmodels.discrete.discrete_model%20import%20Logit%0A%0A%20%20%20%20return%20Logit%2C%20go%2C%20make_subplots%2C%20mo%2C%20np%2C%20pd%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%2040%20PCA%20vs%20Feature%20Agglomeration%5D(40_pca_vs_feat_ag.py)%20%7C%20%5BIndex%5D(..%2Findex.html)%20%7C%20%5B42%20Multiclass%20Classification%20%E2%86%92%5D(42_multiclass_classification.py)%0A%0A%20%20%20%20%23%20Pseudo%20R-Squared%3A%20Goodness-of-Fit%20in%20Logistic%20Regression%20and%20Discrete%20Choice%20Models%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%20In%20Ordinary%20Least%20Squares%20(OLS)%20linear%20regression%2C%20the%20coefficient%20of%20determination%20%24R%5E2%24%20provides%20an%20intuitive%2C%20universally%20understood%20metric%3A%0A%0A%20%20%20%20%24%24R%5E2%20%3D%201%20-%20%5Cfrac%7B%5Ctext%7BSS%7D_%7B%5Ctext%7Bres%7D%7D%7D%7B%5Ctext%7BSS%7D_%7B%5Ctext%7Btot%7D%7D%7D%20%3D%20%5Cfrac%7B%5Ctext%7BSS%7D_%7B%5Ctext%7Breg%7D%7D%7D%7B%5Ctext%7BSS%7D_%7B%5Ctext%7Btot%7D%7D%7D%20%3D%20r%5E2_%7By%2C%20%5Chat%7By%7D%7D%24%24%0A%0A%20%20%20%20It%20quantifies%20the%20exact%20proportion%20of%20target%20variance%20explained%20by%20linear%20predictors%2C%20equals%20the%20squared%20Pearson%20correlation%20between%20true%20and%20predicted%20outcomes%2C%20and%20scales%20strictly%20between%20%240%24%20and%20%241%24.%0A%0A%20%20%20%20%23%23%23%23%20The%20Collapse%20of%20OLS%20%24R%5E2%24%20in%20Discrete%20Choice%20Models%0A%20%20%20%20In%20logistic%20regression%2C%20probit%20models%2C%20and%20generalized%20linear%20models%20(GLMs)%2C%20outcomes%20%24y_i%20%5Cin%20%5C%7B0%2C%201%5C%7D%24%20are%20binary.%20The%20conditional%20variance%20is%20fundamentally%20dependent%20on%20the%20predicted%20probability%3A%0A%0A%20%20%20%20%24%24%5Coperatorname%7BVar%7D(y_i%20%7C%20x_i)%20%3D%20p_i(1%20-%20p_i)%24%24%0A%0A%20%20%20%20Because%20errors%20are%20non-Gaussian%20and%20heteroscedastic%2C%20models%20are%20estimated%20via%20Maximum%20Likelihood%20Estimation%20(MLE)%20rather%20than%20residual%20sum%20of%20squares%20minimization.%20Consequently%2C%20no%20single%20metric%20simultaneously%20satisfies%20all%20mathematical%20properties%20of%20classical%20%24R%5E2%24.%0A%0A%20%20%20%20%23%23%23%23%20The%20Four%20Major%20Pseudo%20%24R%5E2%24%20Formulations%0A%20%20%20%20To%20assess%20model%20fit%20and%20compare%20non-nested%20specifications%2C%20statisticians%20formulated%20**Pseudo%20%24R%5E2%24%20metrics**%3A%0A%20%20%20%201.%20**McFadden's%20%24R%5E2%24**%3A%20Measures%20relative%20deviance%20reduction%20compared%20to%20an%20intercept-only%20(null)%20model.%20In%20econometric%20practice%2C%20McFadden%20values%20between%20%240.20%24%20and%20%240.40%24%20represent%20excellent%20fit%2C%20roughly%20corresponding%20to%20an%20OLS%20%24R%5E2%24%20of%20%240.70%20-%200.90%24.%0A%20%20%20%202.%20**Cox%20%26%20Snell%20%24R%5E2%24**%3A%20Extends%20the%20likelihood%20ratio%20test%20statistic%20across%20observations.%20However%2C%20its%20theoretical%20upper%20bound%20is%20strictly%20less%20than%201.0%20(often%20capping%20around%20%240.75%24%20for%20balanced%20binary%20data)%2C%20making%20a%20%22perfect%22%20model%20appear%20defective.%0A%20%20%20%203.%20**Nagelkerke%20(Cragg%20%26%20Uhler)%20%24R%5E2%24**%3A%20Rescales%20Cox%20%26%20Snell%20by%20dividing%20by%20its%20theoretical%20maximum%2C%20restoring%20a%20%24%5B0%2C%201%5D%24%20interval.%0A%20%20%20%204.%20**Efron's%20%24R%5E2%24**%3A%20Evaluates%20squared%20residual%20reduction%20between%20binary%20outcomes%20and%20predicted%20probability%20values.%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%20Likelihood%20Mechanics%0A%0A%20%20%20%20%23%23%23%201.%20The%20Maximum%20Likelihood%20Framework%0A%0A%20%20%20%20Let%20%24%5Cmathcal%7BD%7D%20%3D%20%5C%7B(x_i%2C%20y_i)%5C%7D_%7Bi%3D1%7D%5EN%24%20with%20%24y_i%20%5Cin%20%5C%7B0%2C%201%5C%7D%24.%20For%20a%20fitted%20logistic%20model%20with%20coefficients%20%24%5Chat%7B%5Cbeta%7D%24%2C%20the%20predicted%20probability%20for%20observation%20%24i%24%20is%3A%0A%0A%20%20%20%20%24%24%5Chat%7Bp%7D_i%20%3D%20%5Csigma(x_i%5E%5Ctop%20%5Chat%7B%5Cbeta%7D)%20%3D%20%5Cfrac%7B1%7D%7B1%20%2B%20e%5E%7B-x_i%5E%5Ctop%20%5Chat%7B%5Cbeta%7D%7D%7D%24%24%0A%0A%20%20%20%20The%20log-likelihood%20of%20the%20fitted%20model%20is%3A%0A%0A%20%20%20%20%24%24%5Cln%20L_M%20%3D%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cleft%5B%20y_i%20%5Cln%20%5Chat%7Bp%7D_i%20%2B%20(1%20-%20y_i)%20%5Cln%20(1%20-%20%5Chat%7Bp%7D_i)%20%5Cright%5D%24%24%0A%0A%20%20%20%20For%20the%20**null%20model**%20(containing%20only%20an%20intercept%20%24%5Cbeta_0%24%2C%20where%20every%20observation%20receives%20predicted%20probability%20equal%20to%20the%20sample%20base%20rate%20%24%5Cbar%7By%7D%20%3D%20%5Cfrac%7B1%7D%7BN%7D%5Csum%20y_i%24)%3A%0A%0A%20%20%20%20%24%24%5Cln%20L_0%20%3D%20%5Csum_%7Bi%3D1%7D%5EN%20%5Cleft%5B%20y_i%20%5Cln%20%5Cbar%7By%7D%20%2B%20(1%20-%20y_i)%20%5Cln%20(1%20-%20%5Cbar%7By%7D)%20%5Cright%5D%20%3D%20N%20%5Cleft%5B%20%5Cbar%7By%7D%20%5Cln%20%5Cbar%7By%7D%20%2B%20(1%20-%20%5Cbar%7By%7D)%20%5Cln%20(1%20-%20%5Cbar%7By%7D)%20%5Cright%5D%24%24%0A%0A%20%20%20%20Since%20probabilities%20lie%20in%20%24(0%2C%201)%24%2C%20both%20log-likelihoods%20are%20strictly%20negative%3A%0A%0A%20%20%20%20%24%24%5Cln%20L_0%20%5Cle%20%5Cln%20L_M%20%5Cle%200%24%24%0A%0A%20%20%20%20%23%23%23%202.%20McFadden's%20Pseudo%20%24R%5E2%24%20(Deviance%20Reduction)%0A%0A%20%20%20%20McFadden's%20%24R%5E2%24%20compares%20the%20log-likelihood%20of%20the%20fitted%20model%20to%20the%20null%20baseline%3A%0A%0A%20%20%20%20%24%24R%5E2_%7B%5Ctext%7BMcF%7D%7D%20%3D%201%20-%20%5Cfrac%7B%5Cln%20L_M%7D%7B%5Cln%20L_0%7D%20%3D%20%5Cfrac%7B%5Cln%20L_M%20-%20%5Cln%20L_0%7D%7B-%5Cln%20L_0%7D%24%24%0A%0A%20%20%20%20-%20If%20the%20predictors%20provide%20zero%20explanatory%20value%2C%20%24%5Cln%20L_M%20%3D%20%5Cln%20L_0%20%5Cimplies%20R%5E2_%7B%5Ctext%7BMcF%7D%7D%20%3D%200%24.%0A%20%20%20%20-%20If%20the%20model%20achieves%20perfect%20separation%20(%24%5Chat%7Bp%7D_i%20%5Cto%20y_i%24)%2C%20%24%5Cln%20L_M%20%5Cto%200%20%5Cimplies%20R%5E2_%7B%5Ctext%7BMcF%7D%7D%20%5Cto%201%24.%0A%0A%20%20%20%20To%20penalize%20for%20the%20number%20of%20estimated%20parameters%20%24K%24%2C%20McFadden%20proposed%20the%20adjusted%20version%3A%0A%0A%20%20%20%20%24%24R%5E2_%7B%5Ctext%7BMcF%2C%20adj%7D%7D%20%3D%201%20-%20%5Cfrac%7B%5Cln%20L_M%20-%20K%7D%7B%5Cln%20L_0%7D%24%24%0A%0A%20%20%20%20%23%23%23%203.%20Cox%20%26%20Snell%20Pseudo%20%24R%5E2%24%0A%0A%20%20%20%20Derived%20from%20the%20likelihood%20ratio%20test%20statistic%20%24G%5E2%20%3D%20-2(%5Cln%20L_0%20-%20%5Cln%20L_M)%20%3D%202(%5Cln%20L_M%20-%20%5Cln%20L_0)%24%3A%0A%0A%20%20%20%20%24%24R%5E2_%7B%5Ctext%7BCS%7D%7D%20%3D%201%20-%20%5Cleft(%20%5Cfrac%7BL_0%7D%7BL_M%7D%20%5Cright)%5E%7B2%2FN%7D%20%3D%201%20-%20%5Cexp%5Cleft(%20-%5Cfrac%7B2%7D%7BN%7D%20(%5Cln%20L_M%20-%20%5Cln%20L_0)%20%5Cright)%24%24%0A%0A%20%20%20%20Under%20a%20hypothetical%20perfect%20model%20where%20%24%5Cln%20L_M%20%3D%200%24%20(%24L_M%20%3D%201%24)%3A%0A%0A%20%20%20%20%24%24%5Cmax%20R%5E2_%7B%5Ctext%7BCS%7D%7D%20%3D%201%20-%20L_0%5E%7B2%2FN%7D%20%3D%201%20-%20%5Cexp%5Cleft(%20%5Cfrac%7B2%7D%7BN%7D%20%5Cln%20L_0%20%5Cright)%20%3D%201%20-%20%5B%5Cbar%7By%7D%5E%7B%5Cbar%7By%7D%7D%20(1%20-%20%5Cbar%7By%7D)%5E%7B1%20-%20%5Cbar%7By%7D%7D%5D%5E2%24%24%0A%0A%20%20%20%20For%20a%20balanced%20dataset%20where%20%24%5Cbar%7By%7D%20%3D%200.5%24%3A%0A%0A%20%20%20%20%24%24%5Cmax%20R%5E2_%7B%5Ctext%7BCS%7D%7D%20%3D%201%20-%20(0.5%5E%7B0.5%7D%20%5Ctimes%200.5%5E%7B0.5%7D)%5E2%20%3D%201%20-%20(0.5)%5E2%20%3D%200.75%24%24%0A%0A%20%20%20%20Even%20with%20flawless%20100%25%20accuracy%2C%20Cox%20%26%20Snell%20cannot%20exceed%20%240.75%24.%0A%0A%20%20%20%20%23%23%23%204.%20Nagelkerke%20%2F%20Cragg%20%26%20Uhler%20Pseudo%20%24R%5E2%24%0A%0A%20%20%20%20Nagelkerke%20renormalized%20Cox%20%26%20Snell%20by%20dividing%20by%20its%20theoretical%20maximum%3A%0A%0A%20%20%20%20%24%24R%5E2_%7B%5Ctext%7BNag%7D%7D%20%3D%20%5Cfrac%7BR%5E2_%7B%5Ctext%7BCS%7D%7D%7D%7B%5Cmax%20R%5E2_%7B%5Ctext%7BCS%7D%7D%7D%20%3D%20%5Cfrac%7B1%20-%20%5Cleft(%20%5Cfrac%7BL_0%7D%7BL_M%7D%20%5Cright)%5E%7B2%2FN%7D%7D%7B1%20-%20L_0%5E%7B2%2FN%7D%7D%20%3D%20%5Cfrac%7B1%20-%20%5Cexp%5Cleft(-%5Cfrac%7B2%7D%7BN%7D(%5Cln%20L_M%20-%20%5Cln%20L_0)%5Cright)%7D%7B1%20-%20%5Cexp%5Cleft(%5Cfrac%7B2%7D%7BN%7D%5Cln%20L_0%5Cright)%7D%24%24%0A%0A%20%20%20%20This%20ensures%20%24R%5E2_%7B%5Ctext%7BNag%7D%7D%20%5Cin%20%5B0%2C%201%5D%24%20regardless%20of%20the%20underlying%20class%20balance.%0A%0A%20%20%20%20%23%23%23%205.%20Efron's%20Pseudo%20%24R%5E2%24%20(Sum%20of%20Squared%20Residuals)%0A%0A%20%20%20%20Efron's%20metric%20directly%20mimics%20the%20OLS%20variance%20reduction%20formula%20using%20predicted%20probabilities%20%24%5Chat%7Bp%7D_i%24%3A%0A%0A%20%20%20%20%24%24R%5E2_%7B%5Ctext%7BEfron%7D%7D%20%3D%201%20-%20%5Cfrac%7B%5Csum_%7Bi%3D1%7D%5EN%20(y_i%20-%20%5Chat%7Bp%7D_i)%5E2%7D%7B%5Csum_%7Bi%3D1%7D%5EN%20(y_i%20-%20%5Cbar%7By%7D)%5E2%7D%24%24%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20np.random.seed(42)%0A%0A%20%20%20%20%23%20Simulate%20metric%20trajectories%20across%20varying%20signal-to-noise%20ratios%20(class%20separation%20delta)%0A%20%20%20%20n_pts%20%3D%20400%0A%20%20%20%20deltas%20%3D%20np.linspace(0.0%2C%204.5%2C%2040)%0A%0A%20%20%20%20mcf_vals%20%3D%20%5B%5D%0A%20%20%20%20cs_vals%20%3D%20%5B%5D%0A%20%20%20%20nag_vals%20%3D%20%5B%5D%0A%20%20%20%20efron_vals%20%3D%20%5B%5D%0A%20%20%20%20cs_max_vals%20%3D%20%5B%5D%0A%0A%20%20%20%20for%20d%20in%20deltas%3A%0A%20%20%20%20%20%20%20%20%23%20Generate%20two%20Gaussians%20with%20separation%20d%0A%20%20%20%20%20%20%20%20x_neg%20%3D%20np.random.normal(-d%20%2F%202.0%2C%201.0%2C%20n_pts%20%2F%2F%202)%0A%20%20%20%20%20%20%20%20x_pos%20%3D%20np.random.normal(d%20%2F%202.0%2C%201.0%2C%20n_pts%20%2F%2F%202)%0A%0A%20%20%20%20%20%20%20%20x_sim%20%3D%20np.concatenate(%5Bx_neg%2C%20x_pos%5D)%0A%20%20%20%20%20%20%20%20y_sim%20%3D%20np.concatenate(%5Bnp.zeros(n_pts%20%2F%2F%202)%2C%20np.ones(n_pts%20%2F%2F%202)%5D)%0A%0A%20%20%20%20%20%20%20%20%23%20Logistic%20fit%20probabilities%20via%20direct%20sigmoid%20of%20optimal%20LDA%20score%0A%20%20%20%20%20%20%20%20%23%20For%20equal%20variance%20normals%2C%20log-odds%20is%20exactly%20delta%20*%20x%0A%20%20%20%20%20%20%20%20p_sim%20%3D%201.0%20%2F%20(1.0%20%2B%20np.exp(-d%20*%20x_sim))%0A%20%20%20%20%20%20%20%20p_sim%20%3D%20np.clip(p_sim%2C%201e-12%2C%201.0%20-%201e-12)%0A%0A%20%20%20%20%20%20%20%20%23%20Log-likelihoods%0A%20%20%20%20%20%20%20%20ll_m%20%3D%20np.sum(y_sim%20*%20np.log(p_sim)%20%2B%20(1.0%20-%20y_sim)%20*%20np.log(1.0%20-%20p_sim))%0A%20%20%20%20%20%20%20%20y_bar%20%3D%20np.mean(y_sim)%0A%20%20%20%20%20%20%20%20ll_0%20%3D%20n_pts%20*%20(y_bar%20*%20np.log(y_bar)%20%2B%20(1.0%20-%20y_bar)%20*%20np.log(1.0%20-%20y_bar))%0A%0A%20%20%20%20%20%20%20%20%23%20Metrics%0A%20%20%20%20%20%20%20%20r2_mcf%20%3D%201.0%20-%20(ll_m%20%2F%20ll_0)%0A%20%20%20%20%20%20%20%20r2_cs%20%3D%201.0%20-%20np.exp(-(2.0%20%2F%20n_pts)%20*%20(ll_m%20-%20ll_0))%0A%20%20%20%20%20%20%20%20max_cs%20%3D%201.0%20-%20np.exp((2.0%20%2F%20n_pts)%20*%20ll_0)%0A%20%20%20%20%20%20%20%20r2_nag%20%3D%20r2_cs%20%2F%20max_cs%0A%20%20%20%20%20%20%20%20r2_efron%20%3D%201.0%20-%20np.sum((y_sim%20-%20p_sim)%20**%202)%20%2F%20np.sum((y_sim%20-%20y_bar)%20**%202)%0A%0A%20%20%20%20%20%20%20%20mcf_vals.append(max(0.0%2C%20min(1.0%2C%20r2_mcf)))%0A%20%20%20%20%20%20%20%20cs_vals.append(max(0.0%2C%20min(1.0%2C%20r2_cs)))%0A%20%20%20%20%20%20%20%20nag_vals.append(max(0.0%2C%20min(1.0%2C%20r2_nag)))%0A%20%20%20%20%20%20%20%20efron_vals.append(max(0.0%2C%20min(1.0%2C%20r2_efron)))%0A%20%20%20%20%20%20%20%20cs_max_vals.append(max_cs)%0A%0A%20%20%20%20deltas%20%3D%20np.array(deltas)%0A%20%20%20%20mcf_vals%20%3D%20np.array(mcf_vals)%0A%20%20%20%20cs_vals%20%3D%20np.array(cs_vals)%0A%20%20%20%20nag_vals%20%3D%20np.array(nag_vals)%0A%20%20%20%20efron_vals%20%3D%20np.array(efron_vals)%0A%20%20%20%20cs_max_bound%20%3D%20cs_max_vals%5B0%5D%0A%20%20%20%20return%20cs_max_bound%2C%20cs_vals%2C%20deltas%2C%20efron_vals%2C%20mcf_vals%2C%20nag_vals%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20cs_max_bound%2C%0A%20%20%20%20cs_vals%2C%0A%20%20%20%20deltas%2C%0A%20%20%20%20efron_vals%2C%0A%20%20%20%20go%2C%0A%20%20%20%20make_subplots%2C%0A%20%20%20%20mcf_vals%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20nag_vals%2C%0A)%3A%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%3EPseudo%20R%5E2%20Trajectories%20Across%20Class%20Separation%3C%2Fb%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cb%3EDeviance%20Reduction%20Breakdown%20(Null%20to%20Saturated)%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.12%2C%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Left%3A%20Trajectories%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%3Ddeltas%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dnag_vals%2C%0A%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%20line%3Ddict(color%3D%22%2310B981%22%2C%20width%3D2.5)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Nagelkerke%20(Normalized%20to%201.0)%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%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%3Ddeltas%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dmcf_vals%2C%0A%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%20line%3Ddict(color%3D%22%232563EB%22%2C%20width%3D2.5)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22McFadden%20(Log-Likelihood%20Ratio)%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%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%3Ddeltas%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Defron_vals%2C%0A%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%20line%3Ddict(color%3D%22%238B5CF6%22%2C%20width%3D2%2C%20dash%3D%22dot%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Efron%20(Residual%20Variance)%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%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%3Ddeltas%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Dcs_vals%2C%0A%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%20line%3Ddict(color%3D%22%23F59E0B%22%2C%20width%3D2.5%2C%20dash%3D%22dash%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Cox%20%26%20Snell%20(Bounded%20Metric)%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%20Cox%20%26%20Snell%20Theoretical%20Max%20Horizontal%20Line%0A%20%20%20%20fig.add_hline(%0A%20%20%20%20%20%20%20%20y%3Dcs_max_bound%2C%0A%20%20%20%20%20%20%20%20line%3Ddict(color%3D%22%23DC2626%22%2C%20width%3D1.5%2C%20dash%3D%22dash%22)%2C%0A%20%20%20%20%20%20%20%20annotation_text%3Df%22Cox%20%26%20Snell%20Max%20Bound%20(%7Bcs_max_bound%3A.2f%7D)%22%2C%0A%20%20%20%20%20%20%20%20annotation_position%3D%22bottom%20right%22%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%20Right%3A%20Waterfall%20of%20Deviance%0A%20%20%20%20deviance_labels%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%22Null%20Deviance%20(-2%20ln%20L0)%22%2C%0A%20%20%20%20%20%20%20%20%22Model%20Deviance%20(-2%20ln%20LM)%22%2C%0A%20%20%20%20%20%20%20%20%22Deviance%20Explained%20(G%5E2)%22%2C%0A%20%20%20%20%5D%0A%20%20%20%20deviance_vals%20%3D%20%5B554.5%2C%20142.1%2C%20412.4%5D%0A%20%20%20%20deviance_colors%20%3D%20%5B%22%2394A3B8%22%2C%20%22%233B82F6%22%2C%20%22%2310B981%22%5D%0A%0A%20%20%20%20fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Bar(%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3Ddeviance_labels%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3Ddeviance_vals%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker_color%3Ddeviance_colors%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20text%3D%5Bf%22%7Bv%3A.1f%7D%22%20for%20v%20in%20deviance_vals%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20textposition%3D%22auto%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Deviance%20Values%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20showlegend%3DFalse%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%3D2%2C%0A%20%20%20%20)%0A%0A%20%20%20%20fig.update_xaxes(title_text%3D%22Class%20Separation%20Delta%20(Signal%20Strength)%22%2C%20row%3D1%2C%20col%3D1)%0A%20%20%20%20fig.update_yaxes(title_text%3D%22Pseudo%20R%5E2%20Value%22%2C%20range%3D%5B0%2C%201.05%5D%2C%20row%3D1%2C%20col%3D1)%0A%20%20%20%20fig.update_yaxes(title_text%3D%22Deviance%20(-2%20ln%20L)%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%3D500%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)%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_(Logit%2C%20mo%2C%20np%2C%20pd)%3A%0A%20%20%20%20%23%20Example%201%3A%20Pure%20NumPy%20Implementation%20of%20all%20Pseudo%20R2%20metrics%20from%20scratch%0A%20%20%20%20def%20calculate_all_pseudo_r2(y_true%2C%20p_pred)%3A%0A%20%20%20%20%20%20%20%20n%20%3D%20len(y_true)%0A%20%20%20%20%20%20%20%20p_clipped%20%3D%20np.clip(p_pred%2C%201e-15%2C%201.0%20-%201e-15)%0A%0A%20%20%20%20%20%20%20%20%23%20Fitted%20model%20log-likelihood%0A%20%20%20%20%20%20%20%20ll_model%20%3D%20np.sum(y_true%20*%20np.log(p_clipped)%20%2B%20(1.0%20-%20y_true)%20*%20np.log(1.0%20-%20p_clipped))%0A%0A%20%20%20%20%20%20%20%20%23%20Null%20model%20log-likelihood%0A%20%20%20%20%20%20%20%20y_bar%20%3D%20np.mean(y_true)%0A%20%20%20%20%20%20%20%20ll_null%20%3D%20n%20*%20(y_bar%20*%20np.log(y_bar)%20%2B%20(1.0%20-%20y_bar)%20*%20np.log(1.0%20-%20y_bar))%0A%0A%20%20%20%20%20%20%20%20%23%201.%20McFadden%0A%20%20%20%20%20%20%20%20mcfadden%20%3D%201.0%20-%20(ll_model%20%2F%20ll_null)%0A%0A%20%20%20%20%20%20%20%20%23%202.%20Cox%20%26%20Snell%0A%20%20%20%20%20%20%20%20cox_snell%20%3D%201.0%20-%20np.exp(-(2.0%20%2F%20n)%20*%20(ll_model%20-%20ll_null))%0A%0A%20%20%20%20%20%20%20%20%23%203.%20Nagelkerke%0A%20%20%20%20%20%20%20%20max_cs%20%3D%201.0%20-%20np.exp((2.0%20%2F%20n)%20*%20ll_null)%0A%20%20%20%20%20%20%20%20nagelkerke%20%3D%20cox_snell%20%2F%20max_cs%0A%0A%20%20%20%20%20%20%20%20%23%204.%20Efron%0A%20%20%20%20%20%20%20%20efron%20%3D%201.0%20-%20np.sum((y_true%20-%20p_clipped)%20**%202)%20%2F%20np.sum((y_true%20-%20y_bar)%20**%202)%0A%0A%20%20%20%20%20%20%20%20return%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Log_Likelihood_Model%22%3A%20round(ll_model%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Log_Likelihood_Null%22%3A%20round(ll_null%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22McFadden_R2%22%3A%20round(mcfadden%2C%204)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Cox_Snell_R2%22%3A%20round(cox_snell%2C%204)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Nagelkerke_R2%22%3A%20round(nagelkerke%2C%204)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Efron_R2%22%3A%20round(efron%2C%204)%2C%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%23%20Generate%20synthetic%20validation%20dataset%0A%20%20%20%20np.random.seed(42)%0A%20%20%20%20n_obs%20%3D%20300%0A%20%20%20%20f1%20%3D%20np.random.normal(0%2C%201%2C%20n_obs)%0A%20%20%20%20f2%20%3D%20np.random.normal(0%2C%201%2C%20n_obs)%0A%20%20%20%20f3%20%3D%20np.random.normal(0%2C%201%2C%20n_obs)%0A%20%20%20%20y_obs%20%3D%20(1.8%20*%20f1%20-%201.2%20*%20f2%20%2B%200.4%20*%20f3%20%2B%20np.random.normal(0%2C%201%2C%20n_obs)%20%3E%200).astype(int)%0A%0A%20%20%20%20x_mat%20%3D%20np.column_stack(%5Bnp.ones(n_obs)%2C%20f1%2C%20f2%2C%20f3%5D)%0A%0A%20%20%20%20%23%20Fit%20statsmodels%20Logit%20for%20exact%20verification%0A%20%20%20%20sm_model%20%3D%20Logit(y_obs%2C%20x_mat).fit(disp%3DFalse)%0A%20%20%20%20p_fitted%20%3D%20sm_model.predict(x_mat)%0A%0A%20%20%20%20scratch_metrics%20%3D%20calculate_all_pseudo_r2(y_obs%2C%20p_fitted)%0A%0A%20%20%20%20df_verification%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%22Metric%22%3A%20%22McFadden%20R%5E2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22From_Scratch_Value%22%3A%20scratch_metrics%5B%22McFadden_R2%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Statsmodels_Value%22%3A%20round(sm_model.prsquared%2C%204)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Formula%22%3A%20%221%20-%20ln(L_M)%20%2F%20ln(L_0)%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%22Metric%22%3A%20%22Cox%20%26%20Snell%20R%5E2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22From_Scratch_Value%22%3A%20scratch_metrics%5B%22Cox_Snell_R2%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Statsmodels_Value%22%3A%20round(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%201.0%20-%20np.exp(-(2.0%20%2F%20n_obs)%20*%20(sm_model.llf%20-%20sm_model.llnull))%2C%204%0A%20%20%20%20%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%20%20%20%20%20%22Formula%22%3A%20%221%20-%20(L_0%20%2F%20L_M)%5E(2%2Fn)%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%22Metric%22%3A%20%22Nagelkerke%20R%5E2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22From_Scratch_Value%22%3A%20scratch_metrics%5B%22Nagelkerke_R2%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Statsmodels_Value%22%3A%20round(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(1.0%20-%20np.exp(-(2.0%20%2F%20n_obs)%20*%20(sm_model.llf%20-%20sm_model.llnull)))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%20(1.0%20-%20np.exp((2.0%20%2F%20n_obs)%20*%20sm_model.llnull))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%204%2C%0A%20%20%20%20%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%20%20%20%20%20%22Formula%22%3A%20%22R%5E2_CS%20%2F%20(1%20-%20L_0%5E(2%2Fn))%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%22Metric%22%3A%20%22Efron%20R%5E2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22From_Scratch_Value%22%3A%20scratch_metrics%5B%22Efron_R2%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Statsmodels_Value%22%3A%20round(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%201.0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20np.sum((y_obs%20-%20p_fitted)%20**%202)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%20np.sum((y_obs%20-%20np.mean(y_obs))%20**%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%204%2C%0A%20%20%20%20%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%20%20%20%20%20%22Formula%22%3A%20%221%20-%20sum(y%20-%20p)%5E2%20%2F%20sum(y%20-%20y_bar)%5E2%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%20Nested%20Model%20Comparison%20Table%0A%20%20%20%20m_null%20%3D%20Logit(y_obs%2C%20x_mat%5B%3A%2C%20%3A1%5D).fit(disp%3DFalse)%0A%20%20%20%20m_single%20%3D%20Logit(y_obs%2C%20x_mat%5B%3A%2C%20%3A2%5D).fit(disp%3DFalse)%0A%20%20%20%20m_full%20%3D%20sm_model%0A%0A%20%20%20%20df_nested%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%22Model_Specification%22%3A%20%22Null%20(Intercept%20Only)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Log_Likelihood%22%3A%20round(m_null.llf%2C%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22McFadden_R2%22%3A%20round(m_null.prsquared%2C%204)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22AIC%22%3A%20round(m_null.aic%2C%201)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22BIC%22%3A%20round(m_null.bic%2C%201)%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%22Model_Specification%22%3A%20%22Univariate%20(F1%20Only)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Log_Likelihood%22%3A%20round(m_single.llf%2C%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22McFadden_R2%22%3A%20round(m_single.prsquared%2C%204)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22AIC%22%3A%20round(m_single.aic%2C%201)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22BIC%22%3A%20round(m_single.bic%2C%201)%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%22Model_Specification%22%3A%20%22Full%20Multivariable%20(F1%20%2B%20F2%20%2B%20F3)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Log_Likelihood%22%3A%20round(m_full.llf%2C%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22McFadden_R2%22%3A%20round(m_full.prsquared%2C%204)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22AIC%22%3A%20round(m_full.aic%2C%201)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22BIC%22%3A%20round(m_full.bic%2C%201)%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_verif%20%3D%20mo.ui.table(df_verification)%0A%20%20%20%20table_nested%20%3D%20mo.ui.table(df_nested)%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
e32ec95c58b9480039e75e0435acd562