Blog / Technical / Flow Diagrams: Statistical Analysis Pipelines

Flow Diagrams: Statistical Analysis Pipelines

This document contains workflow diagrams for the three main analysis patterns in this project.

probability-statisticsdocs

This document contains workflow diagrams for the three main analysis patterns in this project.


1. Statistical Analysis Pipeline

The full end-to-end pipeline from raw data to actionable insights.

flowchart TD RAW["Raw Data\n(CSV, DB, API, stream)"] EDA["Exploratory Data Analysis\n\n- Shape and dtypes\n- Missing value audit\n- Duplicate check\n- Value distributions"] DESC["Descriptive Statistics\n\nstatistics_calculator.py\n\n- Central tendency: mean, median, mode\n- Spread: std, IQR, MAD, CV\n- Shape: skewness, kurtosis\n- Percentiles: P25, P50, P75, P99"] DIST["Distribution Analysis\n\ndistribution_analyzer.py\n\n- Fit: Normal, Log-Normal,\n Gamma, Exponential, Beta\n- Goodness-of-fit: KS test\n- Model selection: AIC\n- QQ plot for normality check"] NORM{Data\nnormally\ndistributed?} PARAM["Parametric Methods\n\n- t-tests (Welch's)\n- ANOVA\n- Pearson correlation\n- Linear regression"] NONPAR["Non-parametric Methods\n\n- Mann-Whitney U\n- Kruskal-Wallis\n- Spearman correlation\n- Bootstrap CI"] HYPO["Hypothesis Testing\n\ntest_runner.py\n\n- Formulate H0 and H1\n- Choose test statistic\n- Compute p-value\n- Check power"] MULTI{Multiple\nhypotheses?} MTC["Multiple Testing Correction\n\n- Bonferroni (FWER)\n- Benjamini-Hochberg (FDR)"] EFFECT["Effect Size Analysis\n\n- Cohen's d (continuous)\n- Cohen's h (proportions)\n- Cramér's V (categorical)\n- Rank-biserial r (non-param)"] BAYES["Bayesian Analysis\n\nbayesian_ab_test.py\nconjugate_priors.py\n\n- Posterior distribution\n- Credible intervals\n- P(effect exists)\n- Expected loss"] SQL["SQL Analytics\n\nsql_statistics.py\n\n- Scalable aggregations\n- Window functions\n- Outlier detection\n- Cohort analysis"] VIZ["Visualisation\n\nmatplotlib / seaborn\n\n- Histograms + fitted PDFs\n- QQ plots\n- Power curves\n- Posterior distributions\n- Heatmaps"] REPORT["Report & Decision\n\n- Statistical significance\n- Practical significance\n- Confidence/credible intervals\n- Recommendations"] RAW --> EDA --> DESC --> DIST DIST --> NORM NORM -->|Yes| PARAM NORM -->|No| NONPAR PARAM --> HYPO NONPAR --> HYPO HYPO --> MULTI MULTI -->|Yes| MTC --> EFFECT MULTI -->|No| EFFECT EFFECT --> BAYES EFFECT --> SQL BAYES --> VIZ SQL --> VIZ VIZ --> REPORT style RAW fill:#34495e,color:#fff style REPORT fill:#2d6a4f,color:#fff style HYPO fill:#4a90d9,color:#fff style BAYES fill:#e06c1a,color:#fff style SQL fill:#6a3d9a,color:#fff

2. Hypothesis Testing Decision Flow

Step-by-step process for running a principled hypothesis test.

flowchart TD START(["State the Research Question\nExample: Does email subject line B\nincrease open rate over A?"]) H0["Define Hypotheses\n\nH0 (Null): pA = pB\nH1 (Alt): pA ≠ pB\n(two-sided)"] ALPHA["Set Significance Level\nalpha = 0.05\n(acceptable Type I error rate)"] POWER["Power Analysis\nSet target power = 0.80\nEstimate effect size (MDE)\nCompute required n"] COLLECT["Collect Data\n- Random assignment\n- Full exposure period\n- No peeking (sequential testing requires\n different stopping rules)"] ASSUME["Check Assumptions\n\nFor t-test:\n - Independence\n - Normality (or n > 30 by CLT)\n\nFor z-test (proportions):\n - np ≥ 10 and n(1-p) ≥ 10\n\nFor chi-squared:\n - Expected cell counts ≥ 5"] ASSUME_OK{Assumptions\nmet?} ASSUME_OK -->|No| TRANSFORM["Transform Data or\nUse Non-Parametric Test"] ASSUME_OK -->|Yes| COMPUTE COMPUTE["Compute Test Statistic\n\nt = (x̄A - x̄B) / SE\nz = (p̂A - p̂B) / SE_pool\nchi2 = Σ(O-E)²/E"] PVAL["Compute P-value\n\np = P(|T| ≥ |t_obs| | H0)\n\nTwo-sided: multiply by 2\nOne-sided: use tail directly"] CI["Compute Confidence Interval\n\nCI = estimate ± z_{alpha/2} · SE\n\nExample for difference in means:\n95% CI = (x̄B - x̄A) ± 1.96 · SE"] EFFECT_SZ["Compute Effect Size\n\nContinuous: Cohen's d = Δμ / σ_pooled\nProportions: Cohen's h\nCategorical: Cramér's V"] DECISION{"Decision Rule\np < alpha AND\nCI excludes 0 AND\neffect_size > practical threshold"} REJECT["Reject H0\nStatistically significant\nREPORT effect size and CI\nDo not claim 'proof'"] FAIL["Fail to Reject H0\nInsufficient evidence\nDo NOT say 'H0 is proven'\nConsider power and effect size"] INTERPRET["Interpret Results\n\n- Statistical significance ≠ practical significance\n- Large n can make tiny effects 'significant'\n- Always report effect size\n- Replicate before acting on findings"] START --> H0 --> ALPHA --> POWER --> COLLECT --> ASSUME TRANSFORM --> COMPUTE COMPUTE --> PVAL --> CI --> EFFECT_SZ --> DECISION DECISION -->|"p < alpha"| REJECT --> INTERPRET DECISION -->|"p ≥ alpha"| FAIL --> INTERPRET style START fill:#2d6a4f,color:#fff style REJECT fill:#c0392b,color:#fff style FAIL fill:#f39c12,color:#000 style INTERPRET fill:#1a535c,color:#fff

3. Bayesian A/B Test Workflow

End-to-end Bayesian A/B testing from prior specification to decision.

flowchart TD DEFINE(["Define A/B Test\nControl A: current version\nVariant B: new version\nMetric: conversion rate"]) PRIOR["Specify Prior\n\nChoose Beta(alpha0, beta0)\n\nVague prior: Beta(1, 1)\n- No prior knowledge\n- Uniform over [0,1]\n\nInformative prior: Beta(10, 90)\n- Believe ~10% base rate\n- Strong prior certainty\n\nPrior mean = alpha0 / (alpha0 + beta0)"] DEPLOY["Deploy Experiment\n- Randomise users to A/B\n- Track conversions\n- No fixed stopping rule needed"] DATA["Observe Data\n\nGroup A: nA users, sA conversions\nGroup B: nB users, sB conversions"] UPDATE["Bayesian Update\n\nPosterior A: Beta(alpha0 + sA, beta0 + fA)\nPosterior B: Beta(alpha0 + sB, beta0 + fB)\n\nwhere fA = nA - sA, fB = nB - sB\n\nConjugate: posterior is also Beta!"] SUMMARIES["Posterior Summaries\n\nMean A = (alpha0+sA)/(alpha0+beta0+nA)\nMean B = (alpha0+sB)/(alpha0+beta0+nB)\n\n95% Credible Interval:\n[Beta_PPF(0.025), Beta_PPF(0.975)]"] MC["Monte Carlo Estimation\nDraw M=100,000 samples from each posterior\n\nsamples_A ~ Beta(posterior_A)\nsamples_B ~ Beta(posterior_B)\n\nlift_samples = samples_B - samples_A"] METRICS["Compute Decision Metrics\n\nP(B > A) = mean(samples_B > samples_A)\n\nExpected Loss(A) = mean(max(0, samples_B - samples_A))\nExpected Loss(B) = mean(max(0, samples_A - samples_B))\n\nCredible interval for lift:\n[P2.5(lift_samples), P97.5(lift_samples)]"] STOP{"Stopping Rule\n\nP(B > A) > 0.95\nOR\nP(A > B) > 0.95\nOR\nMax sample size reached"} CONTINUE["Continue Collecting Data\nSequential updating: no fixed n!"] DECIDE{"Decision\n\nWhich variant has\nlower expected loss?"} SHIP_B["Ship B\nExpected loss(A) > threshold\nP(B > A) > 0.95"] SHIP_A["Keep A\nExpected loss(B) > threshold\nP(A > B) > 0.95"] INCONCLUSIVE["Inconclusive\nCollect more data or\nReduce prior uncertainty"] COMPARE["Compare with Frequentist\n\nTwo-proportion z-test:\nz = (p̂B - p̂A) / SE_pool\np-value = 2*(1 - Phi(|z|))\n\nTypically agrees with Bayesian\nbut different interpretation"] DEFINE --> PRIOR --> DEPLOY --> DATA DATA --> UPDATE --> SUMMARIES --> MC --> METRICS --> STOP STOP -->|Not reached| CONTINUE --> DATA STOP -->|Reached| DECIDE DECIDE -->|"loss(A) minimal"| SHIP_B DECIDE -->|"loss(B) minimal"| SHIP_A DECIDE -->|"Both losses\nequally small"| INCONCLUSIVE SHIP_B --> COMPARE SHIP_A --> COMPARE style DEFINE fill:#2d6a4f,color:#fff style UPDATE fill:#27ae60,color:#fff style MC fill:#4a90d9,color:#fff style SHIP_B fill:#c0392b,color:#fff style SHIP_A fill:#f39c12,color:#000 style INCONCLUSIVE fill:#6a3d9a,color:#fff

4. SQL Statistical Analysis Pipeline

How SQL-based statistics flows from raw tables to insights.

flowchart LR RAW_TBL["Raw Tables\nin DuckDB / Warehouse\n\ntransactions\nevents\nusers"] CTE["Common Table Expressions\n(CTEs)\n\nCalculate intermediate\nstatistics reusably\n\nWITH stats AS (...)"] WINDOW["Window Functions\n\nPERCENT_RANK()\nCUME_DIST()\nNTILE(k)\nROW_NUMBER()\nRANK()\nLAG() / LEAD()"] AGG["Aggregate Functions\n\nAVG, STDDEV_SAMP\nVAR_SAMP, COUNT\nPERCENTILE_CONT\nSKEWNESS, KURTOSIS\nCORR, REGR_SLOPE"] BUCKET["Histogram Bucketing\n\nWIDTH_BUCKET(\n value, lo, hi, n_bins\n)\n\nEqual-width bins"] ZSCORE["Z-Score Normalisation\n\n(x - AVG(x)) /\nSTDDEV_SAMP(x)\n\nFlagged: |z| > 3"] IQR["IQR Outlier Detection\n\nQ1 - 1.5*IQR → lower fence\nQ3 + 1.5*IQR → upper fence\n\nRobust to non-normality"] FUNNEL["Funnel Analysis\n\nCOUNT(DISTINCT user_id)\nby step\n\nStep-to-step conversion\nand cumulative rates"] COHORT["Cohort Retention\n\nJOIN users to events\non cohort_week\n\nRetention = users_active_week_k /\ncohort_size"] REGR["SQL Regression\n\nREGR_SLOPE(y, x)\nREGR_INTERCEPT(y, x)\nREGR_R2(y, x)\nCORR(y, x)"] RESULT["Results DataFrame\n\nvia .df() to Pandas\n\nFurther analysis\nVisualisation\nExport"] RAW_TBL --> CTE CTE --> WINDOW CTE --> AGG CTE --> BUCKET CTE --> ZSCORE CTE --> IQR CTE --> FUNNEL CTE --> COHORT CTE --> REGR WINDOW --> RESULT AGG --> RESULT BUCKET --> RESULT ZSCORE --> RESULT IQR --> RESULT FUNNEL --> RESULT COHORT --> RESULT REGR --> RESULT style RAW_TBL fill:#34495e,color:#fff style RESULT fill:#2d6a4f,color:#fff style AGG fill:#4a90d9,color:#fff style WINDOW fill:#6a3d9a,color:#fff style REGR fill:#e06c1a,color:#fff