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%20import%20prince%0A%0A%20%20%20%20return%20go%2C%20make_subplots%2C%20mo%2C%20np%2C%20pd%2C%20prince%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Note%2030%3A%20Correspondence%20Analysis%2C%20Contingency%20Tables%2C%20and%20the%20Chi-Square%20Geometry%0A%0A%20%20%20%20%26larr%3B%20Previous%20Note%3A%20%5B29%20Canonical%20Correlation%20Analysis%5D(29_canonical_correlation_analysis.py)%20%7C%20Next%20Note%3A%20%5B31%20Gaussian%20Mixture%20Models%5D(31_gaussian_mixture_models.py)%20%26rarr%3B%0A%0A%20%20%20%20---%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%20Principal%20Component%20Analysis%20(PCA)%20assumes%20continuous%20numerical%20variables%20endowed%20with%20standard%20Euclidean%20geometry.%20However%2C%20tabular%20data%20in%20market%20research%2C%20natural%20language%20processing%2C%20sports%20analytics%2C%20and%20survey%20science%20often%20consists%20of%20contingency%20tables%20(cross-tabulated%20non-negative%20counts%20or%20frequency%20matrices).%0A%0A%20%20%20%20Applying%20ordinary%20Euclidean%20distance%20to%20frequency%20tables%20produces%20severe%20distortions%3A%20categories%20with%20large%20absolute%20counts%20dominate%20the%20projection%2C%20while%20rare%20but%20highly%20diagnostic%20categories%20are%20crushed.%0A%0A%20%20%20%20**Correspondence%20Analysis%20(CA)**%2C%20formulated%20by%20Jean-Paul%20Benz%C3%A9cri%20(1973)%2C%20is%20the%20foundational%20dimensionality%20reduction%20method%20for%20categorical%20contingency%20tables%3A%0A%20%20%20%201.%20**The%20Chi-Square%20(%24%5Cchi%5E2%24)%20Metric**%3A%20CA%20replaces%20Euclidean%20distance%20with%20the%20%24%5Cchi%5E2%24-distance%20between%20relative%20frequency%20profiles.%20By%20weighting%20each%20column%20coordinate%20by%20the%20inverse%20of%20its%20marginal%20frequency%20(%241%20%2F%20c_j%24)%2C%20rare%20features%20are%20properly%20scaled%2C%20satisfying%20the%20%22principle%20of%20distributional%20equivalence%22.%0A%20%20%20%202.%20**Decomposition%20of%20Total%20Inertia**%3A%20The%20total%20variance%20in%20a%20contingency%20table%20is%20quantified%20by%20the%20total%20inertia%20%24%5Cphi%5E2%20%3D%20%5Cfrac%7B%5Cchi%5E2%7D%7Bn%7D%24%2C%20measuring%20the%20global%20departure%20from%20statistical%20independence.%20CA%20uses%20the%20Generalized%20Singular%20Value%20Decomposition%20(GSVD)%20to%20decompose%20this%20total%20%24%5Cchi%5E2%24%20into%20orthogonal%20principal%20components.%0A%20%20%20%203.%20**Dual%20Symmetric%20Biplots**%3A%20CA%20projects%20both%20row%20categories%20(e.g.%20Football%20Clubs%20or%20Brands)%20and%20column%20categories%20(e.g.%20Match%20Performance%20Metrics%20or%20Consumer%20Traits)%20into%20a%20shared%20low-dimensional%20map.%20Proximity%20between%20a%20row%20and%20a%20column%20indicates%20positive%20association%20(over-representation%20relative%20to%20independence).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%20%5Bb%5D%20Concept%20explanation%20with%20their%20role%20in%20ML%2FAI%2FStats%3F%0A%0A%20%20%20%20%23%23%23%201.%20The%20Correspondence%20Matrix%20and%20Marginals%0A%0A%20%20%20%20Let%20%24%5Cmathbf%7BN%7D%20%5Cin%20%5Cmathbb%7BR%7D%5E%7BI%20%5Ctimes%20J%7D%24%20be%20an%20%24I%20%5Ctimes%20J%24%20contingency%20table%20of%20non-negative%20counts%2C%20with%20grand%20total%20%24n%20%3D%20%5Csum_%7Bi%3D1%7D%5EI%20%5Csum_%7Bj%3D1%7D%5EJ%20N_%7Bij%7D%20%3D%20%5Cmathbf%7B1%7D_I%5E%5Ctop%20%5Cmathbf%7BN%7D%20%5Cmathbf%7B1%7D_J%24.%0A%0A%20%20%20%20The%20**correspondence%20matrix**%20%24%5Cmathbf%7BP%7D%20%5Cin%20%5Cmathbb%7BR%7D%5E%7BI%20%5Ctimes%20J%7D%24%20represents%20the%20empirical%20joint%20probability%20distribution%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%7BP%7D%20%3D%20%5Cfrac%7B1%7D%7Bn%7D%20%5Cmathbf%7BN%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20row%20masses%20%24%5Cmathbf%7Br%7D%20%5Cin%20%5Cmathbb%7BR%7D%5EI%24%20and%20column%20masses%20%24%5Cmathbf%7Bc%7D%20%5Cin%20%5Cmathbb%7BR%7D%5EJ%24%20are%20the%20marginal%20probability%20vectors%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%7Br%7D%20%3D%20%5Cmathbf%7BP%7D%20%5Cmathbf%7B1%7D_J%2C%20%5Cquad%20%5Cmathbf%7Bc%7D%20%3D%20%5Cmathbf%7BP%7D%5E%5Ctop%20%5Cmathbf%7B1%7D_I%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Let%20%24%5Cmathbf%7BD%7D_r%20%3D%20%5Coperatorname%7Bdiag%7D(%5Cmathbf%7Br%7D)%24%20and%20%24%5Cmathbf%7BD%7D_c%20%3D%20%5Coperatorname%7Bdiag%7D(%5Cmathbf%7Bc%7D)%24%20denote%20the%20diagonal%20mass%20matrices.%0A%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%23%202.%20Row%20and%20Column%20Profiles%0A%0A%20%20%20%20-%20The%20**row%20profiles**%20%24%5Cmathbf%7BR%7D%20%5Cin%20%5Cmathbb%7BR%7D%5E%7BI%20%5Ctimes%20J%7D%24%20are%20the%20conditional%20distributions%20of%20columns%20given%20each%20row%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%7BR%7D%20%3D%20%5Cmathbf%7BD%7D_r%5E%7B-1%7D%20%5Cmathbf%7BP%7D%2C%20%5Cquad%20R_%7Bij%7D%20%3D%20%5Cfrac%7BP_%7Bij%7D%7D%7Br_i%7D%20%3D%20%5Cfrac%7BN_%7Bij%7D%7D%7BN_%7Bi%5Ccdot%7D%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20-%20The%20**column%20profiles**%20%24%5Cmathbf%7BC%7D%20%5Cin%20%5Cmathbb%7BR%7D%5E%7BJ%20%5Ctimes%20I%7D%24%20are%20the%20conditional%20distributions%20of%20rows%20given%20each%20column%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%7BC%7D%20%3D%20%5Cmathbf%7BD%7D_c%5E%7B-1%7D%20%5Cmathbf%7BP%7D%5E%5Ctop%2C%20%5Cquad%20C_%7Bji%7D%20%3D%20%5Cfrac%7BP_%7Bij%7D%7D%7Bc_j%7D%20%3D%20%5Cfrac%7BN_%7Bij%7D%7D%7BN_%7B%5Ccdot%20j%7D%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20average%20row%20profile%20is%20the%20column%20marginal%20%24%5Cmathbf%7Bc%7D%5E%5Ctop%24%2C%20and%20the%20average%20column%20profile%20is%20the%20row%20marginal%20%24%5Cmathbf%7Br%7D%5E%5Ctop%24.%0A%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%23%203.%20The%20Chi-Square%20Metric%20and%20Total%20Inertia%0A%0A%20%20%20%20The%20squared%20%24%5Cchi%5E2%24-distance%20between%20two%20row%20profiles%20%24i%24%20and%20%24i'%24%20is%20weighted%20by%20the%20inverse%20of%20column%20masses%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20d_%7B%5Cchi%5E2%7D%5E2(i%2C%20i')%20%3D%20%5Csum_%7Bj%3D1%7D%5EJ%20%5Cfrac%7B1%7D%7Bc_j%7D%20%5Cleft(R_%7Bij%7D%20-%20R_%7Bi'j%7D%5Cright)%5E2%20%3D%20%5Cleft(%5Cmathbf%7BR%7D_%7Bi%3A%7D%20-%20%5Cmathbf%7BR%7D_%7Bi'%3A%7D%5Cright)%20%5Cmathbf%7BD%7D_c%5E%7B-1%7D%20%5Cleft(%5Cmathbf%7BR%7D_%7Bi%3A%7D%20-%20%5Cmathbf%7BR%7D_%7Bi'%3A%7D%5Cright)%5E%5Ctop%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20**total%20inertia**%20%24%5Cphi%5E2%24%20measures%20the%20weighted%20sum%20of%20squared%20distances%20of%20all%20row%20profiles%20from%20their%20centroid%20%24%5Cmathbf%7Bc%7D%24%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cphi%5E2%20%3D%20%5Csum_%7Bi%3D1%7D%5EI%20r_i%20%5C%2C%20d_%7B%5Cchi%5E2%7D%5E2(%5Cmathbf%7BR%7D_%7Bi%3A%7D%2C%20%5Cmathbf%7Bc%7D)%20%3D%20%5Csum_%7Bi%3D1%7D%5EI%20%5Csum_%7Bj%3D1%7D%5EJ%20%5Cfrac%7B(P_%7Bij%7D%20-%20r_i%20c_j)%5E2%7D%7Br_i%20c_j%7D%20%3D%20%5Cfrac%7B%5Cchi%5E2%7D%7Bn%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Total%20inertia%20is%20identically%20Pearson's%20%24%5Cchi%5E2%24%20statistic%20divided%20by%20the%20grand%20total%20%24n%24.%0A%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%23%204.%20Standardized%20Residuals%20and%20Generalized%20SVD%0A%0A%20%20%20%20To%20find%20the%20optimal%20low-dimensional%20representation%2C%20CA%20computes%20the%20Singular%20Value%20Decomposition%20of%20the%20**standardized%20residual%20matrix**%20%24%5Cmathbf%7BS%7D%24%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%7BS%7D%20%3D%20%5Cmathbf%7BD%7D_r%5E%7B-1%2F2%7D%20%5Cleft(%5Cmathbf%7BP%7D%20-%20%5Cmathbf%7Br%7D%20%5Cmathbf%7Bc%7D%5E%5Ctop%5Cright)%20%5Cmathbf%7BD%7D_c%5E%7B-1%2F2%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Notice%20that%20%24S_%7Bij%7D%20%3D%20%5Cfrac%7BP_%7Bij%7D%20-%20r_i%20c_j%7D%7B%5Csqrt%7Br_i%20c_j%7D%7D%20%3D%20%5Cfrac%7BN_%7Bij%7D%20-%20E_%7Bij%7D%7D%7B%5Csqrt%7Bn%20E_%7Bij%7D%7D%7D%24%2C%20which%20is%20the%20standardized%20Pearson%20residual%20scaled%20by%20%24%5Cfrac%7B1%7D%7B%5Csqrt%7Bn%7D%7D%24.%0A%0A%20%20%20%20Computing%20the%20thin%20SVD%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%7BS%7D%20%3D%20%5Cmathbf%7BU%7D%20%5Cboldsymbol%7B%5CGamma%7D%20%5Cmathbf%7BV%7D%5E%5Ctop%0A%20%20%20%20%24%24%0A%0A%20%20%20%20where%20%24%5Cboldsymbol%7B%5CGamma%7D%20%3D%20%5Coperatorname%7Bdiag%7D(%5Cgamma_1%2C%20%5Cgamma_2%2C%20%5Cdots%2C%20%5Cgamma_K)%24%20contains%20the%20singular%20values.%20The%20**principal%20inertias**%20(eigenvalues)%20are%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Clambda_k%20%3D%20%5Cgamma_k%5E2%2C%20%5Cquad%20%5Csum_%7Bk%3D1%7D%5EK%20%5Clambda_k%20%3D%20%5Cphi%5E2%0A%20%20%20%20%24%24%0A%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%23%205.%20Principal%20Coordinates%20and%20the%20Symmetric%20Biplot%0A%0A%20%20%20%20To%20project%20both%20row%20and%20column%20points%20into%20the%20same%20orthogonal%20coordinate%20space%3A%0A%0A%20%20%20%20-%20**Principal%20Row%20Coordinates%20(%24%5Cmathbf%7BF%7D%24)**%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%7BF%7D%20%3D%20%5Cmathbf%7BD%7D_r%5E%7B-1%2F2%7D%20%5Cmathbf%7BU%7D%20%5Cboldsymbol%7B%5CGamma%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20-%20**Principal%20Column%20Coordinates%20(%24%5Cmathbf%7BG%7D%24)**%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathbf%7BG%7D%20%3D%20%5Cmathbf%7BD%7D_c%5E%7B-1%2F2%7D%20%5Cmathbf%7BV%7D%20%5Cboldsymbol%7B%5CGamma%7D%0A%20%20%20%20%24%24%0A%0A%20%20%20%20In%20the%20**Symmetric%20Biplot**%2C%20rows%20and%20columns%20are%20simultaneously%20plotted%20along%20the%20first%20two%20principal%20axes%3A%0A%20%20%20%20-%20Proximity%20between%20two%20row%20points%20indicates%20that%20they%20share%20similar%20proportional%20distributions%20across%20column%20categories.%0A%20%20%20%20-%20Proximity%20between%20a%20row%20point%20and%20a%20column%20point%20indicates%20positive%20association%20(the%20count%20%24N_%7Bij%7D%24%20exceeds%20the%20expected%20count%20under%20independence%20%24E_%7Bij%7D%24).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(prince)%3A%0A%20%20%20%20%23%20Data%20Cell%3A%20Premier%20League%202023-24%20Season%20Performance%20Contingency%20Table%0A%20%20%20%20_raw_dataset%20%3D%20prince.datasets.load_premier_league()%0A%20%20%20%20_table_2024%20%3D%20_raw_dataset.loc%5B%3A%2C%20%5B%222023-24%22%5D%5D.copy()%0A%20%20%20%20_table_2024.columns%20%3D%20_table_2024.columns.droplevel(0)%0A%20%20%20%20_table_2024.columns%20%3D%20%5B%22Wins%22%2C%20%22Draws%22%2C%20%22Losses%22%2C%20%22Goals%22%2C%20%22Conceded%22%2C%20%22Points%22%5D%0A%20%20%20%20_table_2024.columns.name%20%3D%20%22Metric%22%0A%0A%20%20%20%20%23%20Select%20representative%20clubs%20for%20a%20clean%2C%20highly%20interpretable%20biplot%0A%20%20%20%20_clubs%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%22Arsenal%22%2C%0A%20%20%20%20%20%20%20%20%22Manchester%20City%22%2C%0A%20%20%20%20%20%20%20%20%22Liverpool%22%2C%0A%20%20%20%20%20%20%20%20%22Aston%20Villa%22%2C%0A%20%20%20%20%20%20%20%20%22Tottenham%20Hotspur%22%2C%0A%20%20%20%20%20%20%20%20%22Chelsea%22%2C%0A%20%20%20%20%20%20%20%20%22Newcastle%20United%22%2C%0A%20%20%20%20%20%20%20%20%22Manchester%20United%22%2C%0A%20%20%20%20%20%20%20%20%22West%20Ham%20United%22%2C%0A%20%20%20%20%20%20%20%20%22Everton%22%2C%0A%20%20%20%20%20%20%20%20%22Brentford%22%2C%0A%20%20%20%20%20%20%20%20%22Wolverhampton%20Wanderers%22%2C%0A%20%20%20%20%5D%0A%20%20%20%20df_pl%20%3D%20_table_2024.loc%5B_clubs%5D.copy()%0A%20%20%20%20return%20(df_pl%2C)%0A%0A%0A%40app.cell%0Adef%20_(df_pl%2C%20go%2C%20make_subplots%2C%20np)%3A%0A%20%20%20%20%23%20Interactive%20Visualizations%20Cell%3A%0A%20%20%20%20%23%20Subplot%201%3A%20Symmetric%20Biplot%20(Clubs%20in%20blue%2C%20Performance%20Metrics%20in%20red)%0A%20%20%20%20%23%20Subplot%202%3A%20Scree%20Plot%20of%20Principal%20Inertias%20%26%20Cumulative%20Variance%20Explained%0A%20%20%20%20%23%20Subplot%203%3A%20Standardized%20Chi-Square%20Residuals%20Heatmap%20(N_ij%20-%20E_ij)%20%2F%20sqrt(E_ij)%0A%0A%20%20%20%20_fig%20%3D%20make_subplots(%0A%20%20%20%20%20%20%20%20rows%3D1%2C%0A%20%20%20%20%20%20%20%20cols%3D3%2C%0A%20%20%20%20%20%20%20%20subplot_titles%3D(%0A%20%20%20%20%20%20%20%20%20%20%20%20%221.%20Correspondence%20Analysis%20Symmetric%20Biplot%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%222.%20Principal%20Inertia%20Scree%20Plot%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%223.%20Standardized%20Chi-Square%20Residuals%22%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20horizontal_spacing%3D0.09%2C%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Step-by-step%20CA%20Computation%20in%20pure%20NumPy%0A%20%20%20%20_N%20%3D%20df_pl.to_numpy()%0A%20%20%20%20_n%20%3D%20np.sum(_N)%0A%20%20%20%20_P%20%3D%20_N%20%2F%20_n%0A%0A%20%20%20%20_r%20%3D%20np.sum(_P%2C%20axis%3D1)%0A%20%20%20%20_c%20%3D%20np.sum(_P%2C%20axis%3D0)%0A%0A%20%20%20%20_Dr_inv_sqrt%20%3D%20np.diag(1.0%20%2F%20np.sqrt(_r))%0A%20%20%20%20_Dc_inv_sqrt%20%3D%20np.diag(1.0%20%2F%20np.sqrt(_c))%0A%0A%20%20%20%20%23%20Standardized%20residual%20matrix%20S%0A%20%20%20%20_S%20%3D%20_Dr_inv_sqrt%20%40%20(_P%20-%20np.outer(_r%2C%20_c))%20%40%20_Dc_inv_sqrt%0A%20%20%20%20_U%2C%20_gamma%2C%20_Vt%20%3D%20np.linalg.svd(_S%2C%20full_matrices%3DFalse)%0A%0A%20%20%20%20%23%20Principal%20coordinates%0A%20%20%20%20_F%20%3D%20_Dr_inv_sqrt%20%40%20_U%20%40%20np.diag(_gamma)%0A%20%20%20%20_G%20%3D%20_Dc_inv_sqrt%20%40%20_Vt.T%20%40%20np.diag(_gamma)%0A%0A%20%20%20%20_inertias%20%3D%20_gamma**2%0A%20%20%20%20_total_inertia%20%3D%20np.sum(_inertias)%0A%20%20%20%20_pve%20%3D%20_inertias%20%2F%20_total_inertia%0A%0A%20%20%20%20_club_names%20%3D%20list(df_pl.index)%0A%20%20%20%20_metric_names%20%3D%20list(df_pl.columns)%0A%0A%20%20%20%20%23%20Subplot%201%3A%20Biplot%0A%20%20%20%20%23%20Plot%20Row%20Points%20(Clubs)%0A%20%20%20%20_fig.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_F%5B%3A%2C%200%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D_F%5B%3A%2C%201%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(size%3D9%2C%20color%3D%22%232563eb%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20text%3D_club_names%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20textposition%3D%22top%20right%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20textfont%3Ddict(size%3D8%2C%20color%3D%22%231e3a8a%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Clubs%20(Row%20Profiles)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20hovertemplate%3D%22Club%3A%20%25%7Btext%7D%3Cbr%3EDim%201%3A%20%25%7Bx%3A.3f%7D%3Cbr%3EDim%202%3A%20%25%7By%3A.3f%7D%3Cextra%3E%3C%2Fextra%3E%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%20Column%20Points%20(Metrics)%0A%20%20%20%20_fig.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_G%5B%3A%2C%200%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D_G%5B%3A%2C%201%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(size%3D11%2C%20symbol%3D%22diamond%22%2C%20color%3D%22%23dc2626%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20text%3D_metric_names%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20textposition%3D%22bottom%20left%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20textfont%3Ddict(size%3D9%2C%20color%3D%22%23991b1b%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Metrics%20(Col%20Profiles)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20hovertemplate%3D%22Metric%3A%20%25%7Btext%7D%3Cbr%3EDim%201%3A%20%25%7Bx%3A.3f%7D%3Cbr%3EDim%202%3A%20%25%7By%3A.3f%7D%3Cextra%3E%3C%2Fextra%3E%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%20Reference%20axis%20lines%0A%20%20%20%20_fig.add_shape(type%3D%22line%22%2C%20x0%3D-0.6%2C%20x1%3D0.6%2C%20y0%3D0%2C%20y1%3D0%2C%20line%3Ddict(color%3D%22%23cbd5e1%22%2C%20width%3D1)%2C%20row%3D1%2C%20col%3D1)%0A%20%20%20%20_fig.add_shape(type%3D%22line%22%2C%20x0%3D0%2C%20x1%3D0%2C%20y0%3D-0.4%2C%20y1%3D0.4%2C%20line%3Ddict(color%3D%22%23cbd5e1%22%2C%20width%3D1)%2C%20row%3D1%2C%20col%3D1)%0A%0A%20%20%20%20%23%20Subplot%202%3A%20Scree%20Plot%0A%20%20%20%20_dim_labels%20%3D%20%5Bf%22Dim%20%7Bi%2B1%7D%22%20for%20i%20in%20range(len(_inertias))%5D%0A%20%20%20%20_cum_pve%20%3D%20np.cumsum(_pve)%20*%20100.0%0A%0A%20%20%20%20_fig.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%3D_dim_labels%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D_pve%20*%20100.0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker_color%3D%22%236366f1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Inertia%20PVE%20(%25)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20text%3D%5Bf%22%7Bp*100%3A.1f%7D%25%22%20for%20p%20in%20_pve%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)%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%20_fig.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_dim_labels%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D_cum_pve%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22lines%2Bmarkers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20line%3Ddict(color%3D%22%23f59e0b%22%2C%20width%3D2)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Cumulative%20PVE%20(%25)%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%3D2%2C%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Subplot%203%3A%20Standardized%20Pearson%20Residuals%20(N%20-%20E)%20%2F%20sqrt(E)%0A%20%20%20%20_E%20%3D%20np.outer(_r%2C%20_c)%20*%20_n%0A%20%20%20%20_pearson_residuals%20%3D%20(_N%20-%20_E)%20%2F%20np.sqrt(_E)%0A%0A%20%20%20%20_fig.add_trace(%0A%20%20%20%20%20%20%20%20go.Heatmap(%0A%20%20%20%20%20%20%20%20%20%20%20%20z%3D_pearson_residuals%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D_metric_names%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3D_club_names%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%20zmid%3D0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colorbar%3Ddict(title%3D%22Residual%22%2C%20x%3D1.02%2C%20len%3D0.7)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Pearson%20Residuals%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20hovertemplate%3D%22%25%7By%7D%20-%20%25%7Bx%7D%3A%20Residual%20%3D%20%25%7Bz%3A.2f%7D%3Cextra%3E%3C%2Fextra%3E%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%3D3%2C%0A%20%20%20%20)%0A%0A%20%20%20%20_fig.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%20title%3Ddict(%0A%20%20%20%20%20%20%20%20%20%20%20%20text%3Df%22Correspondence%20Analysis%3A%20Premier%20League%202023-24%20(Total%20Inertia%20%3D%20%7B_total_inertia%3A.4f%7D)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20x%3D0.5%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20xanchor%3D%22center%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20font%3Ddict(size%3D16%2C%20family%3D%22Inter%2C%20system-ui%2C%20sans-serif%22)%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20legend%3Ddict(orientation%3D%22h%22%2C%20yanchor%3D%22bottom%22%2C%20y%3D-0.25%2C%20xanchor%3D%22center%22%2C%20x%3D0.5)%2C%0A%20%20%20%20%20%20%20%20margin%3Ddict(l%3D40%2C%20r%3D40%2C%20t%3D75%2C%20b%3D80)%2C%0A%20%20%20%20)%0A%0A%20%20%20%20_fig.update_xaxes(title_text%3Df%22Dimension%201%20(%7B_pve%5B0%5D*100%3A.1f%7D%25)%22%2C%20row%3D1%2C%20col%3D1)%0A%20%20%20%20_fig.update_yaxes(title_text%3Df%22Dimension%202%20(%7B_pve%5B1%5D*100%3A.1f%7D%25)%22%2C%20row%3D1%2C%20col%3D1)%0A%0A%20%20%20%20_fig.update_xaxes(title_text%3D%22Principal%20Dimension%22%2C%20row%3D1%2C%20col%3D2)%0A%20%20%20%20_fig.update_yaxes(title_text%3D%22Explained%20Inertia%20(%25)%22%2C%20range%3D%5B0%2C%20110%5D%2C%20row%3D1%2C%20col%3D2)%0A%0A%20%20%20%20_fig.update_xaxes(title_text%3D%22Performance%20Metric%22%2C%20tickangle%3D45%2C%20row%3D1%2C%20col%3D3)%0A%20%20%20%20_fig.update_yaxes(title_text%3D%22Football%20Club%22%2C%20row%3D1%2C%20col%3D3)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%20%5Bd%5D%20Code%20Examples%0A%0A%20%20%20%20Below%20we%20implement%20two%20rigorous%2C%20production-grade%20demonstrations%3A%0A%20%20%20%201.%20**Full%20Correspondence%20Analysis%20Algorithm%20from%20Scratch**%3A%20Step-by-step%20computation%20of%20correspondence%20matrix%20%24%5Cmathbf%7BP%7D%24%2C%20marginal%20masses%20%24%5Cmathbf%7Br%7D%2C%20%5Cmathbf%7Bc%7D%24%2C%20standardized%20residual%20matrix%20%24%5Cmathbf%7BS%7D%24%2C%20SVD%20decomposition%2C%20principal%20inertias%2C%20and%20principal%20coordinates%20%24%5Cmathbf%7BF%7D%2C%20%5Cmathbf%7BG%7D%24%2C%20verified%20against%20%60prince.CA%60.%0A%20%20%20%202.%20**Premier%20League%20Archetype%20Interpretation%20Table**%3A%20Formatted%20table%20quantifying%20each%20club's%20coordinate%20along%20Dimension%201%20(Attacking%20Power%20%26%20Victory%20vs.%20Defensive%20Vulnerability)%20and%20Dimension%202%20(Draws%20vs.%20Polarized%20Outcomes).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df_pl%2C%20np%2C%20pd%2C%20prince)%3A%0A%20%20%20%20%23%20Example%201%3A%20Pure%20NumPy%20Step-by-Step%20CA%20from%20Scratch%20vs%20Prince%0A%20%20%20%20_N%20%3D%20df_pl.to_numpy()%0A%20%20%20%20_n%20%3D%20np.sum(_N)%0A%20%20%20%20_P%20%3D%20_N%20%2F%20_n%0A%0A%20%20%20%20_r%20%3D%20np.sum(_P%2C%20axis%3D1)%0A%20%20%20%20_c%20%3D%20np.sum(_P%2C%20axis%3D0)%0A%0A%20%20%20%20_Dr_inv_sqrt%20%3D%20np.diag(1.0%20%2F%20np.sqrt(_r))%0A%20%20%20%20_Dc_inv_sqrt%20%3D%20np.diag(1.0%20%2F%20np.sqrt(_c))%0A%0A%20%20%20%20_S%20%3D%20_Dr_inv_sqrt%20%40%20(_P%20-%20np.outer(_r%2C%20_c))%20%40%20_Dc_inv_sqrt%0A%20%20%20%20_U%2C%20_gamma%2C%20_Vt%20%3D%20np.linalg.svd(_S%2C%20full_matrices%3DFalse)%0A%0A%20%20%20%20_inertias_scratch%20%3D%20_gamma**2%0A%20%20%20%20_total_inertia%20%3D%20np.sum(_inertias_scratch)%0A%20%20%20%20_chi2_stat%20%3D%20_total_inertia%20*%20_n%0A%0A%20%20%20%20%23%20Reference%20fit%20from%20prince%20library%0A%20%20%20%20_ca_prince%20%3D%20prince.CA(n_components%3D2%2C%20engine%3D%22sklearn%22%2C%20random_state%3D42)%0A%20%20%20%20_ca_prince.fit(df_pl)%0A%20%20%20%20_eigen_summary%20%3D%20_ca_prince.eigenvalues_summary%0A%0A%20%20%20%20_df_inertias%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%22Principal%20Dimension%22%3A%20f%22Dimension%20%7Bi%20%2B%201%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Principal%20Inertia%20(lambda)%22%3A%20f%22%7B_inertias_scratch%5Bi%5D%3A.5f%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Percent%20of%20Inertia%22%3A%20f%22%7B(_inertias_scratch%5Bi%5D%20%2F%20_total_inertia)%20*%20100.0%3A.2f%7D%25%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Cumulative%20Inertia%22%3A%20f%22%7B(np.sum(_inertias_scratch%5B%3Ai%2B1%5D)%20%2F%20_total_inertia)%20*%20100.0%3A.2f%7D%25%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%20%20%20%20for%20i%20in%20range(len(_inertias_scratch))%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%0A%20%20%20%20_df_chi2_summary%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%22Metric%22%3A%20%22Grand%20Total%20Table%20Sum%20(n)%22%2C%20%22Value%22%3A%20str(int(_n))%2C%20%22Description%22%3A%20%22Sum%20of%20all%20table%20cells%22%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Total%20Inertia%20(phi%5E2)%22%2C%20%22Value%22%3A%20f%22%7B_total_inertia%3A.5f%7D%22%2C%20%22Description%22%3A%20%22Sum%20of%20all%20principal%20inertias%22%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Pearson%20Chi-Square%20Statistic%22%2C%20%22Value%22%3A%20f%22%7B_chi2_stat%3A.2f%7D%22%2C%20%22Description%22%3A%20%22Total%20departure%20from%20independence%22%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%22Metric%22%3A%20%22Degrees%20of%20Freedom%20(I-1)(J-1)%22%2C%20%22Value%22%3A%20str((df_pl.shape%5B0%5D%20-%201)%20*%20(df_pl.shape%5B1%5D%20-%201))%2C%20%22Description%22%3A%20%22Table%20degrees%20of%20freedom%22%7D%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(df_pl%2C%20np%2C%20pd)%3A%0A%20%20%20%20%23%20Example%202%3A%20Club%20Archetype%20Interpretation%20along%20Dimension%201%20and%202%0A%20%20%20%20_N%20%3D%20df_pl.to_numpy()%0A%20%20%20%20_n%20%3D%20np.sum(_N)%0A%20%20%20%20_P%20%3D%20_N%20%2F%20_n%0A%20%20%20%20_r%20%3D%20np.sum(_P%2C%20axis%3D1)%0A%20%20%20%20_c%20%3D%20np.sum(_P%2C%20axis%3D0)%0A%0A%20%20%20%20_Dr_inv_sqrt%20%3D%20np.diag(1.0%20%2F%20np.sqrt(_r))%0A%20%20%20%20_Dc_inv_sqrt%20%3D%20np.diag(1.0%20%2F%20np.sqrt(_c))%0A%0A%20%20%20%20_S%20%3D%20_Dr_inv_sqrt%20%40%20(_P%20-%20np.outer(_r%2C%20_c))%20%40%20_Dc_inv_sqrt%0A%20%20%20%20_U%2C%20_gamma%2C%20_%20%3D%20np.linalg.svd(_S%2C%20full_matrices%3DFalse)%0A%20%20%20%20_F%20%3D%20_Dr_inv_sqrt%20%40%20_U%20%40%20np.diag(_gamma)%0A%0A%20%20%20%20_records%20%3D%20%5B%5D%0A%20%20%20%20for%20_i%2C%20_club%20in%20enumerate(df_pl.index)%3A%0A%20%20%20%20%20%20%20%20_d1%20%3D%20_F%5B_i%2C%200%5D%0A%20%20%20%20%20%20%20%20_d2%20%3D%20_F%5B_i%2C%201%5D%0A%0A%20%20%20%20%20%20%20%20if%20_d1%20%3C%20-0.15%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_archetype%20%3D%20%22Elite%20Title%20Contender%20(High%20Wins%2C%20Goals%2C%20Points)%22%0A%20%20%20%20%20%20%20%20elif%20_d1%20%3E%200.15%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_archetype%20%3D%20%22Relegation%20Struggler%20(High%20Losses%2C%20Conceded)%22%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_archetype%20%3D%20%22Mid-Table%20Stability%22%0A%0A%20%20%20%20%20%20%20%20_records.append(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Football%20Club%22%3A%20_club%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Dimension%201%20Coordinate%22%3A%20f%22%7B_d1%3A%2B.3f%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Dimension%202%20Coordinate%22%3A%20f%22%7B_d2%3A%2B.3f%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Relative%20Row%20Mass%20(r_i)%22%3A%20f%22%7B_r%5B_i%5D%3A.3f%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Identified%20Performance%20Cluster%22%3A%20_archetype%2C%0A%20%20%20%20%20%20%20%20%7D)%0A%0A%20%20%20%20_df_archetypes%20%3D%20pd.DataFrame(_records).sort_values(%22Dimension%201%20Coordinate%22)%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
fad9df3d007120f28709ade9ce4cfe3d