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.metrics%20import%20average_precision_score%2C%20precision_recall_fscore_support%2C%20roc_auc_score%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20average_precision_score%2C%0A%20%20%20%20%20%20%20%20go%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%20precision_recall_fscore_support%2C%0A%20%20%20%20%20%20%20%20roc_auc_score%2C%0A%20%20%20%20)%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%5B%E2%86%90%2057%20Autoencoder%20Latent%20Space%5D(57_autoencoder_latent_space.py)%20%7C%20%5BIndex%5D(..%2Findex.html)%20%7C%20%5B59%20VAE%20on%20MNIST%20%E2%86%92%5D(59_vae_mnist.py)%0A%0A%20%20%20%20%23%2058.%20PCA%20for%20Anomaly%20Detection%3A%20Subspace%20Reconstruction%20Error%20and%20SPE%20%2F%20Q-Residual%20Analysis%0A%0A%20%20%20%20%23%23%23%20Executive%20Summary%0A%0A%20%20%20%20In%20industrial%20telemetry%2C%20network%20security%2C%20and%20financial%20fraud%20surveillance%2C%20multivariate%20observations%20routinely%20encompass%20dozens%20or%20hundreds%20of%20correlated%20sensor%20streams.%20Under%20nominal%20operating%20conditions%2C%20physical%20laws%20and%20structural%20couplings%20constrain%20observations%20to%20reside%20along%20a%20low-dimensional%20linear%20subspace%20%24%5Cmathcal%7BS%7D_k%24.%0A%0A%20%20%20%20**Principal%20Component%20Analysis%20(PCA)%20for%20Anomaly%20Detection**%20leverages%20this%20geometric%20constraint%20by%20decomposing%20ambient%20observation%20space%20into%20two%20orthogonal%20subspaces%3A%20the%20**Principal%20Subspace**%20(%24%5Cmathcal%7BS%7D_k%24)%2C%20capturing%20normal%20shared%20variance%2C%20and%20the%20**Residual%20Subspace**%20(%24%5Cmathcal%7BS%7D_k%5E%5Cperp%24)%2C%20capturing%20unmodeled%20noise%20and%20anomalies.%20By%20projecting%20data%20into%20%24%5Cmathcal%7BS%7D_k%24%20and%20evaluating%20the%20**Squared%20Prediction%20Error%20(SPE%20%2F%20%24Q%24-statistic)**%2C%20the%20algorithm%20detects%20structural%20faults%20that%20violate%20normal%20correlation%20patterns%2C%20while%20the%20**Hotelling's%20%24T%5E2%24%20statistic**%20pinpoints%20extreme%20in-plane%20deviations.%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%23%23%20%5Bb%5D%20Mathematical%20Foundations%20of%20Subspace%20Anomaly%20Detection%0A%0A%20%20%20%20%23%23%23%201.%20Orthogonal%20Subspace%20Decomposition%0A%0A%20%20%20%20Let%20%24X%20%5Cin%20%5Cmathbb%7BR%7D%5E%7BN%20%5Ctimes%20p%7D%24%20represent%20a%20standardized%20dataset%20of%20%24N%24%20observations%20across%20%24p%24%20features%2C%20with%20sample%20mean%20%24%5Cmu%20%3D%20%5Cmathbf%7B0%7D%24%20and%20unit%20standard%20deviation.%20The%20sample%20covariance%20(correlation)%20matrix%20%24R%20%5Cin%20%5Cmathbb%7BR%7D%5E%7Bp%20%5Ctimes%20p%7D%24%20is%3A%0A%0A%20%20%20%20%24%24R%20%3D%20%5Cfrac%7B1%7D%7BN%20-%201%7D%20X%5E%5Ctop%20X%24%24%0A%0A%20%20%20%20Applying%20spectral%20decomposition%3A%0A%0A%20%20%20%20%24%24R%20%3D%20V%20%5CLambda%20V%5E%5Ctop%20%3D%20%5Cbegin%7Bbmatrix%7D%20V_k%20%26%20V_%5Cperp%20%5Cend%7Bbmatrix%7D%20%5Cbegin%7Bbmatrix%7D%20%5CLambda_k%20%26%200%20%5C%5C%200%20%26%20%5CLambda_%5Cperp%20%5Cend%7Bbmatrix%7D%20%5Cbegin%7Bbmatrix%7D%20V_k%5E%5Ctop%20%5C%5C%20V_%5Cperp%5E%5Ctop%20%5Cend%7Bbmatrix%7D%24%24%0A%0A%20%20%20%20where%3A%0A%20%20%20%20-%20%24V_k%20%5Cin%20%5Cmathbb%7BR%7D%5E%7Bp%20%5Ctimes%20k%7D%24%20contains%20the%20top%20%24k%24%20eigenvectors%20corresponding%20to%20dominant%20eigenvalues%20%24%5Clambda_1%20%5Cge%20%5Cdots%20%5Cge%20%5Clambda_k%24.%0A%20%20%20%20-%20%24V_%5Cperp%20%5Cin%20%5Cmathbb%7BR%7D%5E%7Bp%20%5Ctimes%20(p%20-%20k)%7D%24%20contains%20the%20remaining%20%24p%20-%20k%24%20eigenvectors%20capturing%20residual%20noise.%0A%20%20%20%20-%20%24%5CLambda_k%20%3D%20%5Coperatorname%7Bdiag%7D(%5Clambda_1%2C%20%5Cdots%2C%20%5Clambda_k)%24%20represents%20the%20variance%20along%20each%20principal%20axis.%0A%0A%20%20%20%20This%20decomposes%20the%20ambient%20space%20%24%5Cmathbb%7BR%7D%5Ep%24%20into%20mutually%20orthogonal%20subspaces%3A%0A%0A%20%20%20%20%24%24%5Cmathbb%7BR%7D%5Ep%20%3D%20%5Cmathcal%7BS%7D_k%20%5Coplus%20%5Cmathcal%7BS%7D_k%5E%5Cperp%24%24%0A%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%23%202.%20Projection%20and%20Reconstruction%20Operators%0A%0A%20%20%20%20For%20any%20new%20observation%20%24x%20%5Cin%20%5Cmathbb%7BR%7D%5Ep%24%3A%0A%0A%20%20%20%201.%20**Latent%20Code**%3A%20%24z%20%3D%20x%20V_k%20%5Cin%20%5Cmathbb%7BR%7D%5Ek%24%0A%20%20%20%202.%20**Orthogonal%20Projection%20onto%20%24%5Cmathcal%7BS%7D_k%24**%3A%20%24P_k%20%3D%20V_k%20V_k%5E%5Ctop%20%5Cin%20%5Cmathbb%7BR%7D%5E%7Bp%20%5Ctimes%20p%7D%24%0A%20%20%20%203.%20**Reconstructed%20Observation**%3A%0A%0A%20%20%20%20%24%24%5Chat%7Bx%7D%20%3D%20z%20V_k%5E%5Ctop%20%3D%20x%20V_k%20V_k%5E%5Ctop%20%3D%20x%20P_k%20%5Cin%20%5Cmathbb%7BR%7D%5Ep%24%24%0A%0A%20%20%20%204.%20**Residual%20Error%20Vector**%3A%0A%0A%20%20%20%20%24%24e%20%3D%20x%20-%20%5Chat%7Bx%7D%20%3D%20x%20(I%20-%20P_k)%20%3D%20x%20V_%5Cperp%20V_%5Cperp%5E%5Ctop%20%5Cin%20%5Cmathcal%7BS%7D_k%5E%5Cperp%24%24%0A%0A%20%20%20%20If%20an%20observation%20conforms%20to%20the%20nominal%20correlation%20structure%2C%20its%20energy%20is%20almost%20entirely%20contained%20within%20%24%5Cmathcal%7BS%7D_k%24%2C%20yielding%20%24%5C%7Ce%5C%7C_2%20%5Capprox%200%24.%20If%20an%20observation%20violates%20the%20correlation%20structure%20(e.g.%2C%20an%20abnormal%20sensor%20reading%20uncoupled%20from%20its%20correlated%20neighbors)%2C%20it%20projects%20heavily%20into%20%24%5Cmathcal%7BS%7D_k%5E%5Cperp%24%2C%20triggering%20a%20large%20residual%20%24%5C%7Ce%5C%7C_2%24.%0A%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%23%203.%20Complementary%20Anomaly%20Statistics%3A%20SPE%20(%24Q%24)%20vs%20Hotelling's%20%24T%5E2%24%0A%0A%20%20%20%20Comprehensive%20fault%20detection%20employs%20two%20complementary%20metrics%3A%0A%0A%20%20%20%20%23%23%23%23%20A.%20Squared%20Prediction%20Error%20(SPE%20%2F%20%24Q%24-Statistic)%0A%20%20%20%20The%20%24Q%24-statistic%20measures%20the%20squared%20Euclidean%20distance%20from%20the%20observation%20to%20the%20principal%20hyperplane%3A%0A%0A%20%20%20%20%24%24Q(x)%20%3D%20%5C%7C%20e%20%5C%7C_2%5E2%20%3D%20%5C%7C%20x%20-%20%5Chat%7Bx%7D%20%5C%7C_2%5E2%20%3D%20x%20(I%20-%20P_k)%20x%5E%5Ctop%20%3D%20%5Csum_%7Bj%3D1%7D%5Ep%20(x_j%20-%20%5Chat%7Bx%7D_j)%5E2%24%24%0A%0A%20%20%20%20-%20**Diagnostic%20Role**%3A%20Detects%20**out-of-model%20structural%20anomalies**%E2%80%94events%20where%20the%20underlying%20physical%20process%20changes%20or%20correlations%20break%20down.%0A%0A%20%20%20%20%23%23%23%23%20B.%20Hotelling's%20%24T%5E2%24%20Statistic%0A%20%20%20%20The%20%24T%5E2%24%20statistic%20measures%20the%20normalized%20Mahalanobis%20distance%20**within**%20the%20principal%20subspace%3A%0A%0A%20%20%20%20%24%24T%5E2(x)%20%3D%20z%20%5CLambda_k%5E%7B-1%7D%20z%5E%5Ctop%20%3D%20%5Csum_%7Bj%3D1%7D%5Ek%20%5Cfrac%7Bz_j%5E2%7D%7B%5Clambda_j%7D%24%24%0A%0A%20%20%20%20-%20**Diagnostic%20Role**%3A%20Detects%20**in-model%20leverage%20anomalies**%E2%80%94events%20that%20obey%20the%20normal%20correlation%20structure%20but%20exhibit%20extreme%20magnitudes%20(e.g.%2C%20high-throughput%20surges).%0A%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%23%204.%20Statistical%20Control%20Limits%20and%20Fault%20Localization%0A%0A%20%20%20%20To%20automate%20alert%20generation%20without%20manual%20threshold%20tuning%2C%20Jackson%20%26%20Mudholkar%20(1979)%20derived%20the%20theoretical%20upper%20control%20limit%20%24Q_%5Calpha%24%20at%20significance%20level%20%24%5Calpha%24%3A%0A%0A%20%20%20%20%24%24%5Ctheta_i%20%3D%20%5Csum_%7Bj%3Dk%2B1%7D%5Ep%20%5Clambda_j%5Ei%2C%20%5Cqquad%20h_0%20%3D%201%20-%20%5Cfrac%7B2%20%5Ctheta_1%20%5Ctheta_3%7D%7B3%20%5Ctheta_2%5E2%7D%24%24%0A%0A%20%20%20%20%24%24Q_%5Calpha%20%3D%20%5Ctheta_1%20%5Cleft%5B%201%20-%20%5Cfrac%7B%5Ctheta_2%20h_0%20(1%20-%20h_0)%7D%7B%5Ctheta_1%5E2%7D%20%2B%20%5Cfrac%7Bz_%5Calpha%20%5Csqrt%7B2%20%5Ctheta_2%20h_0%5E2%7D%7D%7B%5Ctheta_1%7D%20%5Cright%5D%5E%7B%5Cfrac%7B1%7D%7Bh_0%7D%7D%24%24%0A%0A%20%20%20%20Once%20an%20anomaly%20is%20flagged%20(%24Q(x)%20%3E%20Q_%5Calpha%24)%2C%20the%20fault%20is%20localized%20to%20individual%20variables%20by%20decomposing%20the%20scalar%20%24Q%24%20into%20feature%20contributions%3A%0A%0A%20%20%20%20%24%24%5Coperatorname%7BContribution%7D(j)%20%3D%20e_j%5E2%20%3D%20(x_j%20-%20%5Chat%7Bx%7D_j)%5E2%24%24%0A%0A%20%20%20%20The%20feature%20with%20the%20largest%20contribution%20indicates%20the%20root-cause%20faulty%20sensor.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(go%2C%20make_subplots%2C%20mo%2C%20np)%3A%0A%20%20%20%20%23%20Simulate%20a%203D%20physical%20system%20(e.g.%203%20correlated%20temperature%20sensors)%0A%20%20%20%20np.random.seed(42)%0A%20%20%20%20n_samples%20%3D%20300%0A%0A%20%20%20%20%23%20True%20correlation%3A%20sensors%20lie%20near%20a%202D%20plane%20in%203D%20space%0A%20%20%20%20%23%20x1%20%3D%20t1%2C%20x2%20%3D%200.8%20*%20t1%20%2B%20t2%2C%20x3%20%3D%200.6%20*%20t1%20-%200.5%20*%20t2%0A%20%20%20%20t1%20%3D%20np.random.normal(0%2C%202.5%2C%20n_samples)%0A%20%20%20%20t2%20%3D%20np.random.normal(0%2C%201.2%2C%20n_samples)%0A%0A%20%20%20%20x1%20%3D%20t1%20%2B%20np.random.normal(0%2C%200.15%2C%20n_samples)%0A%20%20%20%20x2%20%3D%200.85%20*%20t1%20%2B%200.9%20*%20t2%20%2B%20np.random.normal(0%2C%200.15%2C%20n_samples)%0A%20%20%20%20x3%20%3D%200.65%20*%20t1%20-%200.7%20*%20t2%20%2B%20np.random.normal(0%2C%200.15%2C%20n_samples)%0A%0A%20%20%20%20X_nom%20%3D%20np.column_stack(%5Bx1%2C%20x2%2C%20x3%5D)%0A%0A%20%20%20%20%23%20Inject%20distinct%20anomaly%20classes%3A%0A%20%20%20%20%23%201.%20Structural%20Anomaly%20(Sensor%203%20fails%20and%20outputs%20%2B7.0%2C%20breaking%20correlation)%0A%20%20%20%20anom_struct%20%3D%20np.array(%5B%5B2.0%2C%201.8%2C%207.5%5D%2C%20%5B-2.2%2C%20-1.9%2C%20-6.8%5D%2C%20%5B0.5%2C%200.4%2C%205.2%5D%5D)%0A%20%20%20%20%23%202.%20In-Subspace%20Leverage%20Outlier%20(Sensors%20spike%20along%20valid%20correlation%20plane)%0A%20%20%20%20anom_leverage%20%3D%20np.array(%5B%5B8.0%2C%207.2%2C%205.4%5D%2C%20%5B-7.5%2C%20-6.8%2C%20-5.0%5D%5D)%0A%0A%20%20%20%20X_all%20%3D%20np.vstack(%5BX_nom%2C%20anom_struct%2C%20anom_leverage%5D)%0A%20%20%20%20true_labels%20%3D%20np.array(%5B0%5D%20*%20n_samples%20%2B%20%5B1%5D%20*%20len(anom_struct)%20%2B%20%5B2%5D%20*%20len(anom_leverage))%0A%0A%20%20%20%20%23%20Standardize%20data%0A%20%20%20%20mu_vec%20%3D%20np.mean(X_all%2C%20axis%3D0)%0A%20%20%20%20std_vec%20%3D%20np.std(X_all%2C%20axis%3D0)%0A%20%20%20%20X_std%20%3D%20(X_all%20-%20mu_vec)%20%2F%20std_vec%0A%0A%20%20%20%20%23%20Fit%20PCA%20on%20nominal%20data%0A%20%20%20%20X_nom_std%20%3D%20(X_nom%20-%20mu_vec)%20%2F%20std_vec%0A%20%20%20%20cov_mat%20%3D%20np.cov(X_nom_std%2C%20rowvar%3DFalse)%0A%20%20%20%20eigvals%2C%20eigvecs%20%3D%20np.linalg.eigh(cov_mat)%0A%20%20%20%20sort_idx%20%3D%20np.argsort(eigvals)%5B%3A%3A-1%5D%0A%20%20%20%20eigvals%20%3D%20eigvals%5Bsort_idx%5D%0A%20%20%20%20eigvecs%20%3D%20eigvecs%5B%3A%2C%20sort_idx%5D%0A%0A%20%20%20%20%23%20Retain%20k%20%3D%202%20components%20(explaining%20%3E98%25%20of%20variance)%0A%20%20%20%20k_comps%20%3D%202%0A%20%20%20%20V_k%20%3D%20eigvecs%5B%3A%2C%20%3Ak_comps%5D%0A%20%20%20%20Lambda_k%20%3D%20eigvals%5B%3Ak_comps%5D%0A%0A%20%20%20%20%23%20Compute%20Q%20and%20T%5E2%20for%20all%20samples%0A%20%20%20%20Z%20%3D%20np.dot(X_std%2C%20V_k)%20%20%23%20(N%2C%202)%0A%20%20%20%20X_rec%20%3D%20np.dot(Z%2C%20V_k.T)%20%20%23%20(N%2C%203)%0A%20%20%20%20residuals%20%3D%20X_std%20-%20X_rec%0A%0A%20%20%20%20Q_scores%20%3D%20np.sum(residuals**2%2C%20axis%3D1)%0A%20%20%20%20T2_scores%20%3D%20np.sum((Z**2)%20%2F%20Lambda_k%2C%20axis%3D1)%0A%0A%20%20%20%20%23%20Thresholds%20(97.5th%20percentile%20on%20nominal%20set)%0A%20%20%20%20Q_thresh%20%3D%20float(np.percentile(Q_scores%5B%3An_samples%5D%2C%2097.5))%0A%20%20%20%20T2_thresh%20%3D%20float(np.percentile(T2_scores%5B%3An_samples%5D%2C%2097.5))%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%3EReconstruction%20Error%20Residuals%20across%20Observations%3C%2Fb%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cb%3EFour-Quadrant%20Anomaly%20Map%3A%20SPE%20(Q)%20vs%20Hotelling's%20T%5E2%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%20Panel%201%3A%20Bar%20chart%20of%20Q-scores%0A%20%20%20%20nom_idx%20%3D%20np.where(true_labels%20%3D%3D%200)%5B0%5D%0A%20%20%20%20struct_idx%20%3D%20np.where(true_labels%20%3D%3D%201)%5B0%5D%0A%20%20%20%20lev_idx%20%3D%20np.where(true_labels%20%3D%3D%202)%5B0%5D%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%3Dnom_idx%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3DQ_scores%5Bnom_idx%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3Ddict(color%3D%22%231D4ED8%22%2C%20size%3D5%2C%20opacity%3D0.6)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Nominal%20Operating%20Data%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%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%3Dstruct_idx%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3DQ_scores%5Bstruct_idx%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3Ddict(color%3D%22%23DC2626%22%2C%20size%3D10%2C%20symbol%3D%22diamond%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22Structural%20Anomaly%20(Broken%20Correlation)%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%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%3Dlev_idx%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3DQ_scores%5Blev_idx%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3Ddict(color%3D%22%23F59E0B%22%2C%20size%3D10%2C%20symbol%3D%22triangle-up%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20name%3D%22In-Plane%20Leverage%20Outlier%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_hline(%0A%20%20%20%20%20%20%20%20y%3DQ_thresh%2C%0A%20%20%20%20%20%20%20%20line%3Ddict(color%3D%22%23DC2626%22%2C%20dash%3D%22dash%22%2C%20width%3D1.5)%2C%0A%20%20%20%20%20%20%20%20annotation_text%3Df%22Q-Limit%20(%7BQ_thresh%3A.2f%7D)%22%2C%0A%20%20%20%20%20%20%20%20annotation_position%3D%22top%20left%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%20Panel%202%3A%20Q%20vs%20T%5E2%20Four-Quadrant%20Map%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%3DT2_scores%5Bnom_idx%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3DQ_scores%5Bnom_idx%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3Ddict(color%3D%22%231D4ED8%22%2C%20size%3D6%2C%20opacity%3D0.5)%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%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%3DT2_scores%5Bstruct_idx%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3DQ_scores%5Bstruct_idx%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3Ddict(color%3D%22%23DC2626%22%2C%20size%3D11%2C%20symbol%3D%22diamond%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%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%3DT2_scores%5Blev_idx%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20y%3DQ_scores%5Blev_idx%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22markers%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20marker%3Ddict(color%3D%22%23F59E0B%22%2C%20size%3D11%2C%20symbol%3D%22triangle-up%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.add_hline(y%3DQ_thresh%2C%20line%3Ddict(color%3D%22%23DC2626%22%2C%20dash%3D%22dash%22%2C%20width%3D1.5)%2C%20row%3D1%2C%20col%3D2)%0A%20%20%20%20fig.add_vline(%0A%20%20%20%20%20%20%20%20x%3DT2_thresh%2C%0A%20%20%20%20%20%20%20%20line%3Ddict(color%3D%22%23F59E0B%22%2C%20dash%3D%22dash%22%2C%20width%3D1.5)%2C%0A%20%20%20%20%20%20%20%20annotation_text%3Df%22T%5E2%20Limit%20(%7BT2_thresh%3A.1f%7D)%22%2C%0A%20%20%20%20%20%20%20%20annotation_position%3D%22top%20left%22%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%22Sample%20Index%22%2C%20row%3D1%2C%20col%3D1)%0A%20%20%20%20fig.update_yaxes(title_text%3D%22Squared%20Prediction%20Error%20Q%22%2C%20range%3D%5B0%2C%20max(Q_scores)%20*%201.1%5D%2C%20row%3D1%2C%20col%3D1)%0A%20%20%20%20fig.update_xaxes(title_text%3D%22Hotelling's%20T%5E2%20(In-Subspace%20Distance)%22%2C%20type%3D%22log%22%2C%20row%3D1%2C%20col%3D2)%0A%20%20%20%20fig.update_yaxes(title_text%3D%22Squared%20Prediction%20Error%20Q%20(Out-of-Subspace)%22%2C%20type%3D%22log%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)%0A%0A%20%20%20%20viz%20%3D%20mo.ui.plotly(fig)%0A%20%20%20%20return%20Q_scores%2C%20Q_thresh%2C%20T2_scores%2C%20T2_thresh%2C%20residuals%2C%20true_labels%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20Q_scores%2C%0A%20%20%20%20Q_thresh%2C%0A%20%20%20%20T2_scores%2C%0A%20%20%20%20T2_thresh%2C%0A%20%20%20%20average_precision_score%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20np%2C%0A%20%20%20%20pd%2C%0A%20%20%20%20precision_recall_fscore_support%2C%0A%20%20%20%20residuals%2C%0A%20%20%20%20roc_auc_score%2C%0A%20%20%20%20true_labels%2C%0A)%3A%0A%20%20%20%20%23%20Example%201%3A%20Pure%20NumPy%20Vectorized%20PCA%20Anomaly%20Engine%20Implementation%0A%20%20%20%20def%20pca_anomaly_detector_np(X_train%2C%20X_test%2C%20n_components%3D2)%3A%0A%20%20%20%20%20%20%20%20mu%20%3D%20np.mean(X_train%2C%20axis%3D0)%0A%20%20%20%20%20%20%20%20std%20%3D%20np.std(X_train%2C%20axis%3D0)%0A%20%20%20%20%20%20%20%20X_tr_norm%20%3D%20(X_train%20-%20mu)%20%2F%20std%0A%20%20%20%20%20%20%20%20X_te_norm%20%3D%20(X_test%20-%20mu)%20%2F%20std%0A%0A%20%20%20%20%20%20%20%20%23%20SVD%0A%20%20%20%20%20%20%20%20_%2C%20S%2C%20Vt%20%3D%20np.linalg.svd(X_tr_norm%2C%20full_matrices%3DFalse)%0A%20%20%20%20%20%20%20%20eigenvalues%20%3D%20(S**2)%20%2F%20(len(X_train)%20-%201)%0A%20%20%20%20%20%20%20%20V_sub%20%3D%20Vt%5B%3An_components%5D.T%0A%20%20%20%20%20%20%20%20Lambdas%20%3D%20eigenvalues%5B%3An_components%5D%0A%0A%20%20%20%20%20%20%20%20%23%20Project%20and%20reconstruct%0A%20%20%20%20%20%20%20%20Z_te%20%3D%20np.dot(X_te_norm%2C%20V_sub)%0A%20%20%20%20%20%20%20%20X_rec_te%20%3D%20np.dot(Z_te%2C%20V_sub.T)%0A%20%20%20%20%20%20%20%20E_te%20%3D%20X_te_norm%20-%20X_rec_te%0A%0A%20%20%20%20%20%20%20%20Q_stats%20%3D%20np.sum(E_te**2%2C%20axis%3D1)%0A%20%20%20%20%20%20%20%20T2_stats%20%3D%20np.sum((Z_te**2)%20%2F%20Lambdas%2C%20axis%3D1)%0A%0A%20%20%20%20%20%20%20%20return%20Q_stats%2C%20T2_stats%2C%20E_te%0A%0A%20%20%20%20%23%20Example%202%3A%20Benchmark%20Metrics%20on%20Structural%20Anomalies%0A%20%20%20%20binary_ground_truth%20%3D%20(true_labels%20%3D%3D%201).astype(int)%0A%20%20%20%20pred_anomaly%20%3D%20(Q_scores%20%3E%20Q_thresh).astype(int)%0A%0A%20%20%20%20prec%2C%20rec%2C%20f1%2C%20_%20%3D%20precision_recall_fscore_support(%0A%20%20%20%20%20%20%20%20binary_ground_truth%2C%20pred_anomaly%2C%20average%3D%22binary%22%2C%20zero_division%3D0%0A%20%20%20%20)%0A%20%20%20%20roc_auc%20%3D%20roc_auc_score(binary_ground_truth%2C%20Q_scores)%0A%20%20%20%20pr_auc%20%3D%20average_precision_score(binary_ground_truth%2C%20Q_scores)%0A%0A%20%20%20%20df_benchmark%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%22Anomaly_Detector%22%3A%20%22PCA%20Squared%20Prediction%20Error%20(SPE%20%2F%20Q)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Detection_Threshold%22%3A%20f%22Q%20%3E%3D%20%7BQ_thresh%3A.4f%7D%20(97.5th%20percentile)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Precision%22%3A%20f%22%7Bprec%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%22Recall%22%3A%20f%22%7Brec%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%22F1-Score%22%3A%20f%22%7Bf1%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%22ROC_AUC%22%3A%20f%22%7Broc_auc%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%22PR_AUC%22%3A%20f%22%7Bpr_auc%20*%20100%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%5D%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Example%203%3A%20Root-Cause%20Fault%20Localization%20via%20Residual%20Decomposition%0A%20%20%20%20%23%20Examine%20the%20first%20structural%20anomaly%20(Sensor%203%20was%20corrupted)%0A%20%20%20%20target_anom_idx%20%3D%20np.where(true_labels%20%3D%3D%201)%5B0%5D%5B0%5D%0A%20%20%20%20anom_res%20%3D%20residuals%5Btarget_anom_idx%5D%0A%20%20%20%20feature_contributions%20%3D%20anom_res**2%0A%20%20%20%20pct_contributions%20%3D%20(feature_contributions%20%2F%20np.sum(feature_contributions))%20*%20100.0%0A%0A%20%20%20%20df_localization%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%22Sensor_Channel%22%3A%20f%22Sensor%20%7Bch%20%2B%201%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Standardized_Residual_e_j%22%3A%20f%22%7Banom_res%5Bch%5D%3A.4f%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Squared_Contribution_e_j%5E2%22%3A%20f%22%7Bfeature_contributions%5Bch%5D%3A.4f%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Percent_of_Total_Q%22%3A%20f%22%7Bpct_contributions%5Bch%5D%3A.1f%7D%25%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Fault_Diagnosis%22%3A%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Root-Cause%20Sensor%20Fault%20(Isolated)%22%20if%20pct_contributions%5Bch%5D%20%3E%2080.0%20else%20%22Coupled%20Nominal%20Sensor%22%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%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20ch%20in%20range(3)%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20Example%204%3A%20Four-Quadrant%20Category%20Distribution%0A%20%20%20%20is_high_q%20%3D%20Q_scores%20%3E%20Q_thresh%0A%20%20%20%20is_high_t2%20%3D%20T2_scores%20%3E%20T2_thresh%0A%0A%20%20%20%20quad_nominal%20%3D%20np.sum(~is_high_q%20%26%20~is_high_t2)%0A%20%20%20%20quad_structural%20%3D%20np.sum(is_high_q%20%26%20~is_high_t2)%0A%20%20%20%20quad_leverage%20%3D%20np.sum(~is_high_q%20%26%20is_high_t2)%0A%20%20%20%20quad_severe%20%3D%20np.sum(is_high_q%20%26%20is_high_t2)%0A%0A%20%20%20%20df_quadrants%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%22Operating_Quadrant%22%3A%20%22Quadrant%20I%3A%20Low%20Q%20%26%20Low%20T%5E2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Diagnostic_Interpretation%22%3A%20%22Nominal%20In-Control%20Operation%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Sample_Count%22%3A%20int(quad_nominal)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Percent_of_Dataset%22%3A%20f%22%7Bquad_nominal%20%2F%20len(Q_scores)%20*%20100%3A.1f%7D%25%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%22Operating_Quadrant%22%3A%20%22Quadrant%20II%3A%20High%20Q%20%26%20Low%20T%5E2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Diagnostic_Interpretation%22%3A%20%22Broken%20Correlation%20%2F%20Sensor%20Fault%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Sample_Count%22%3A%20int(quad_structural)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Percent_of_Dataset%22%3A%20f%22%7Bquad_structural%20%2F%20len(Q_scores)%20*%20100%3A.1f%7D%25%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%22Operating_Quadrant%22%3A%20%22Quadrant%20III%3A%20Low%20Q%20%26%20High%20T%5E2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Diagnostic_Interpretation%22%3A%20%22In-Model%20Leverage%20Outlier%20%2F%20Surge%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Sample_Count%22%3A%20int(quad_leverage)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Percent_of_Dataset%22%3A%20f%22%7Bquad_leverage%20%2F%20len(Q_scores)%20*%20100%3A.1f%7D%25%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%22Operating_Quadrant%22%3A%20%22Quadrant%20IV%3A%20High%20Q%20%26%20High%20T%5E2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Diagnostic_Interpretation%22%3A%20%22Catastrophic%20Joint%20Failure%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Sample_Count%22%3A%20int(quad_severe)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Percent_of_Dataset%22%3A%20f%22%7Bquad_severe%20%2F%20len(Q_scores)%20*%20100%3A.1f%7D%25%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_bench%20%3D%20mo.ui.table(df_benchmark)%0A%20%20%20%20table_diag%20%3D%20mo.ui.table(df_localization)%0A%20%20%20%20table_quad%20%3D%20mo.ui.table(df_quadrants)%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
5284943edb9eb5d5a2ef09cb50edac18