<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Vasco Yasenov</title>
<link>https://vyasenov.github.io/blog/</link>
<atom:link href="https://vyasenov.github.io/blog/index.xml" rel="self" type="application/rss+xml"/>
<description>Personal Site of Vasco Yasenov</description>
<generator>quarto-1.9.37</generator>
<lastBuildDate>Thu, 09 Jul 2026 07:00:00 GMT</lastBuildDate>
<item>
  <title>Double Descent for Statisticians</title>
  <link>https://vyasenov.github.io/blog/double-descent.html</link>
  <description><![CDATA[ 





<div class="reading-time">7 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Perhaps the first reflex a data scientist learns states a model that fits the training data perfectly has almost certainly overfit and will predict badly out of sample. The bias–variance trade-off draws a tidy <img src="https://latex.codecogs.com/png.latex?U"> — too simple is biased, too flexible explodes the variance — and you aim for the sweet spot between. Interpolation is the cardinal sin.</p>
<p>Modern machine learning violates this reflex daily and gets away with it: enormous neural networks interpolate their training data yet generalize beautifully. Belkin et al.&nbsp;(2019) named the phenomenon <em>double descent</em> — push complexity <em>past</em> the interpolation point and out-of-sample error, after spiking, falls again, sometimes below the classical sweet spot. The bias–variance <img src="https://latex.codecogs.com/png.latex?U"> is only the first half of the story.</p>
<p>Hastie, Montanari, Rosset, and Tibshirani (2022) show the whole phenomenon in the most classical model we have — linear least squares, no networks or kernels. They paint a story about interpolation, the geometry of the <a href="https://vyasenov.github.io/blog/linear-models-p-over-n.html"><img src="https://latex.codecogs.com/png.latex?p%20%3E%20n"> regime</a>, and above all about forgetting to regularize. Let’s take a closer look.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Take the usual linear model with i.i.d. data,</p>
<p><img src="https://latex.codecogs.com/png.latex?y_i%20=%20x_i%5E%5Ctop%20%5Cbeta%20+%20%5Cvarepsilon_i,%20%5Cqquad%20%5Cmathbb%7BE%7D(%5Cvarepsilon_i)%20=%200,%20%5Cquad%20%5Ctext%7BVar%7D(%5Cvarepsilon_i)%20=%20%5Csigma%5E2,"></p>
<p>with <img src="https://latex.codecogs.com/png.latex?x_i%20%5Cin%20%5Cmathbb%7BR%7D%5Ep"> and a design matrix <img src="https://latex.codecogs.com/png.latex?X"> that is <img src="https://latex.codecogs.com/png.latex?n%20%5Ctimes%20p">. The single quantity that organizes everything is the <strong>overparametrization ratio</strong></p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%20p%20/%20n."></p>
<ul>
<li>when <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20%3C%201"> the problem is <em>underparametrized</em> (more rows than columns, ordinary least squares applies);</li>
<li>when <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20%3E%201"> it is <em>overparametrized</em> and least squares no longer has a unique solution. In that regime the natural estimator is the <em>minimum-norm</em>, or <em>ridgeless</em>, least squares solution <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta%20=%20(X%5E%5Ctop%20X)%5E+%20X%5E%5Ctop%20y%20=%20X%5E+%20y,"> the least-squares fit of smallest Euclidean norm, and equivalently the limit of ridge regression as the penalty vanishes, <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta%20=%20%5Clim_%7B%5Clambda%20%5Cto%200%7D%20%5Chat%5Cbeta_%5Clambda">.</li>
</ul>
<p>Write the <em>signal-to-noise ratio</em> as <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BSNR%7D%20=%20%5C%7C%5Cbeta%5C%7C_2%5E2%20/%20%5Csigma%5E2%20=%20r%5E2/%5Csigma%5E2,"> and measure performance by the out-of-sample prediction risk at a fresh test point, <img src="https://latex.codecogs.com/png.latex?R%20=%20%5Cmathbb%7BE%7D%5Cbig%5B(x_0%5E%5Ctop%20%5Chat%5Cbeta%20-%20x_0%5E%5Ctop%5Cbeta)%5E2%5Cbig%5D."></p>
<p>Lastly, we need the covariance matrix of the test point, <img src="https://latex.codecogs.com/png.latex?%5CSigma%20=%20%5Ctext%7BCov%7D(x_0)">.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="the-curve" class="level3">
<h3 class="anchored" data-anchor-id="the-curve">The curve</h3>
<p>Here is the whole phenomenon in one curve. It traces the out-of-sample risk of plain ridgeless least squares as the number of parameters grows relative to the sample size: the risk climbs as the model approaches just enough capacity to interpolate, blows up at that interpolation threshold, and then — against every classical instinct — falls a second time, eventually dipping below the null risk.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="../files/double-descent-curve.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1"><img src="https://vyasenov.github.io/files/double-descent-curve.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:90.0%" alt="Out-of-sample prediction risk of ridgeless least squares as a function of the overparametrization ratio gamma = p/n, showing the classical rise toward the interpolation threshold at gamma = 1, a spike, and a second descent for gamma > 1 that falls below the null risk."></a></p>
</figure>
</div>
<p>In math notation, we fix <img src="https://latex.codecogs.com/png.latex?n">, sweep <img src="https://latex.codecogs.com/png.latex?p">, fit ridgeless least squares at each step, and trace the out-of-sample risk against <img src="https://latex.codecogs.com/png.latex?%5Cgamma"> (isotropic case <img src="https://latex.codecogs.com/png.latex?%5CSigma%20=%20I">, signal norm <img src="https://latex.codecogs.com/png.latex?%5C%7C%5Cbeta%5C%7C%5E2"> held fixed for a fair comparison). The risk climbs toward <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%201">, blows up at the interpolation boundary, then <em>descends a second time</em> for <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20%3E%201">.</p>
<p>Hastie et al.&nbsp;(2022) make this exact in the limit <img src="https://latex.codecogs.com/png.latex?n,%20p%20%5Cto%20%5Cinfty"> with <img src="https://latex.codecogs.com/png.latex?p/n%20%5Cto%20%5Cgamma">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AR%20%5Cto%0A%5Cbegin%7Bcases%7D%0A%5Csigma%5E2%20%5Cdfrac%7B%5Cgamma%7D%7B1%20-%20%5Cgamma%7D,%20&amp;%20%5Cgamma%20%3C%201,%20%5C%5C%5B2ex%5D%0A%5Cunderbrace%7Br%5E2%5CBig(1%20-%20%5Ctfrac%7B1%7D%7B%5Cgamma%7D%5CBig)%7D_%7B%5Ctext%7Bbias%7D%7D%20+%20%5Cunderbrace%7B%5Csigma%5E2%20%5Cdfrac%7B1%7D%7B%5Cgamma%20-%201%7D%7D_%7B%5Ctext%7Bvariance%7D%7D,%20&amp;%20%5Cgamma%20%3E%201.%0A%5Cend%7Bcases%7D%0A"></p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>Below the boundary the risk is pure variance, diverging as <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20%5Cto%201">. Above it, a bias term grows with <img src="https://latex.codecogs.com/png.latex?%5Cgamma"> while a variance term shrinks — and that tension is the engine of the second descent.</p>
</div>
</div>
<hr>
</section>
<section id="bias-up-variance-down" class="level3">
<h3 class="anchored" data-anchor-id="bias-up-variance-down">Bias up, variance down</h3>
<p>Why does the risk fall again past <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%201">? The two components move in opposite directions.</p>
<p>The bias <em>rises</em> with <img src="https://latex.codecogs.com/png.latex?%5Cgamma"> for a reason familiar from the <a href="https://vyasenov.github.io/blog/linear-models-p-over-n.html"><img src="https://latex.codecogs.com/png.latex?p%3En"> regime</a>: the minimum-norm solution lives in the row space of <img src="https://latex.codecogs.com/png.latex?X">, an <img src="https://latex.codecogs.com/png.latex?n">-dimensional slice of <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5Ep">. As <img src="https://latex.codecogs.com/png.latex?p"> grows that slice shrinks relative to the whole, so more of <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> falls in the directions the data never see and the min-norm rule zeroes out. More parameters, more of <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> left on the table, more bias.</p>
<p>The variance <em>falls</em> with <img src="https://latex.codecogs.com/png.latex?%5Cgamma">, which feels backwards — surely more parameters means <em>more</em> variance? Not for the minimum-norm interpolator. Extra columns give the solver more directions to spread the fit across, so the minimum-norm solution to <img src="https://latex.codecogs.com/png.latex?Xb%20=%20y"> generally has <em>smaller</em> norm as <img src="https://latex.codecogs.com/png.latex?p"> grows, and a lower-norm interpolator is smoother and more stable — effectively more regularized, for free.</p>
<p>The spike at <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%201"> is where both forces peak. With <img src="https://latex.codecogs.com/png.latex?p%20%5Capprox%20n"> the model has <em>just barely</em> enough capacity to interpolate and no slack to do it gracefully: <img src="https://latex.codecogs.com/png.latex?X%5E%5Ctop%20X"> is nearly singular and the variance term <img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2/(%5Cgamma-1)"> explodes. The interpolation threshold is not a sweet spot — it is the worst place to be.</p>
<hr>
</section>
<section id="its-mostly-a-regularization-story" class="level3">
<h3 class="anchored" data-anchor-id="its-mostly-a-regularization-story">It’s mostly a regularization story</h3>
<p>The dramatic part of the curve (the divergence at <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%201">) is an artifact of insisting on interpolation, and interpolation is a <em>choice</em>, not a law. Ridgeless least squares is just ridge regression with the penalty dialed to zero, the one setting a statistician would never choose on purpose.</p>
<p>Hastie et al.&nbsp;(2022) prove it: optimally-tuned ridge <em>dominates</em> minimum-norm least squares at every <img src="https://latex.codecogs.com/png.latex?%5Cgamma"> and every SNR, well-specified or not. Its risk has no spike — proper <img src="https://latex.codecogs.com/png.latex?%5Clambda"> smooths the curve into a single well-behaved descent, with the global minimum (under misspecification) sitting right around <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%201">, exactly where ridgeless is worst. And the optimal penalty is estimable: leave-one-out cross-validation recovers it asymptotically.</p>
<p>Double descent is real and the math is beautiful, but the headline (<em>more parameters fix overfitting</em>) gets it backwards. The second descent just shows the minimum-norm interpolator picking up a hidden, growing dose of regularization as <img src="https://latex.codecogs.com/png.latex?%5Cgamma"> rises. You need not climb out to <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%204"> to enjoy it; a ridge penalty and a cross-validation loop dial it in directly, skipping the peak entirely. Less “interpolation is secretly fine” than “under-regularization is bad, and overparametrization happens to re-regularize you on the way out.”</p>
<hr>
</section>
<section id="when-overparametrization-genuinely-helps" class="level3">
<h3 class="anchored" data-anchor-id="when-overparametrization-genuinely-helps">When overparametrization genuinely helps</h3>
<p>That said, the strong claim — that the risk’s <em>global</em> minimum can live deep in the overparametrized regime — is true, but only under structure worth knowing.</p>
<p>In the <em>isotropic, well-specified</em> case it essentially never pays: even when <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BSNR%7D%20%3E%201"> creates a local minimum past <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%201">, the global minimum stays underparametrized, and the risk only approaches the null risk <img src="https://latex.codecogs.com/png.latex?r%5E2"> as <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20%5Cto%20%5Cinfty">. Overparametrization buys nothing you couldn’t get more cheaply.</p>
<p>Two things change the verdict.</p>
<p><em>Misspecification</em>: if the truth has components your features cannot represent, adding features improves the approximation, and with enough signal the global minimum can cross the boundary.</p>
<p><em>Structure in the covariance</em>: when <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> aligns with the leading <a href="https://vyasenov.github.io/blog/flavors-pca.html">eigenvectors of <img src="https://latex.codecogs.com/png.latex?%5CSigma"></a> — the “latent space” model, where each feature carries fresh information about a few latent drivers — the risk can fall monotonically across the whole overparametrized regime, bottoming out as <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20%5Cto%20%5Cinfty">. This is what large networks actually look like, and no accident: a linear model with a learned feature map is exactly the lazy-training (“neural tangent kernel”) linearization of an overparametrized network. Not an analogy — the same story.</p>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>Double descent needs no neural networks — plain ridgeless least squares shows it: the classical <img src="https://latex.codecogs.com/png.latex?U"> for <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20%3C%201">, a blow-up at the interpolation boundary <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%201">, then a second descent for <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20%3E%201">.</li>
<li>Past the boundary, bias rises (min-norm <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> is trapped in the row space) while variance falls (the interpolant smooths as <img src="https://latex.codecogs.com/png.latex?p"> grows). The second descent is their tug-of-war.</li>
<li>The peak at <img src="https://latex.codecogs.com/png.latex?%5Cgamma%20=%201"> is the worst place to be, not a sweet spot: <img src="https://latex.codecogs.com/png.latex?X%5E%5Ctop%20X"> is near-singular and variance explodes.</li>
<li>It is largely a regularization story: optimally-tuned ridge dominates ridgeless least squares everywhere and erases the spike, so tuning <img src="https://latex.codecogs.com/png.latex?%5Clambda"> (e.g.&nbsp;by LOOCV) makes the drama disappear.</li>
<li>Overparametrization wins <em>globally</em> only under structure — misspecification, high SNR, or <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> aligned with the top eigenvectors of <img src="https://latex.codecogs.com/png.latex?%5CSigma">.</li>
</ul>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<ul>
<li><p>Bartlett, P. L., Long, P. M., Lugosi, G., &amp; Tsybakov, A. B. (2020). Benign overfitting in linear regression. <em>Proceedings of the National Academy of Sciences</em>, 117(48), 30063–30070.</p></li>
<li><p>Belkin, M., Hsu, D., Ma, S., &amp; Mandal, S. (2019). Reconciling modern machine-learning practice and the classical bias–variance trade-off. <em>Proceedings of the National Academy of Sciences</em>, 116(32), 15849–15854.</p></li>
<li><p>Hastie, T., Montanari, A., Rosset, S., &amp; Tibshirani, R. J. (2022). Surprises in high-dimensional ridgeless least squares interpolation. <em>The Annals of Statistics</em>, 50(2), 949–986.</p></li>
</ul>


</section>

 ]]></description>
  <category>parametric models</category>
  <category>statistical inference</category>
  <category>machine learning</category>
  <guid>https://vyasenov.github.io/blog/double-descent.html</guid>
  <pubDate>Thu, 09 Jul 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>A Brief Introduction to Sufficient Dimension Reduction</title>
  <link>https://vyasenov.github.io/blog/sufficient-dimension-reduction.html</link>
  <description><![CDATA[ 





<div class="reading-time">6 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Principal component analysis is the reflex answer to “I have too many predictors.” It is also, for regression, the wrong reflex more often than people admit. PCA finds the directions along which <img src="https://latex.codecogs.com/png.latex?X"> varies the most. The problem is that PCA never looks at <img src="https://latex.codecogs.com/png.latex?Y">. I have written about the <a href="https://vyasenov.github.io/blog/flavors-pca.html">many flavors of PCA</a>, and this blind spot is common to all of them.</p>
<p>Sufficient dimension reduction (SDR) fixes the blind spot. The goal is the same as PCA’s — replace a high-dimensional predictor <img src="https://latex.codecogs.com/png.latex?X"> with a handful of linear combinations — but with a sharper contract: the reduced predictors must retain <em>all</em> the information <img src="https://latex.codecogs.com/png.latex?X"> carries about <img src="https://latex.codecogs.com/png.latex?Y">. A sufficient statistic loses nothing about a parameter; a sufficient reduction loses nothing about the response. What makes SDR appealing to a practitioner is that it delivers this without you having to specify a model for how <img src="https://latex.codecogs.com/png.latex?Y"> depends on <img src="https://latex.codecogs.com/png.latex?X"> — it is largely model-free, which is precisely what you want early in an analysis, before you have committed to a functional form.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Let <img src="https://latex.codecogs.com/png.latex?Y"> be a response and <img src="https://latex.codecogs.com/png.latex?X%20%5Cin%20%5Cmathbb%7BR%7D%5Ep"> a predictor vector, jointly distributed. We seek a <img src="https://latex.codecogs.com/png.latex?p%20%5Ctimes%20d"> matrix <img src="https://latex.codecogs.com/png.latex?%5Ceta"> with <img src="https://latex.codecogs.com/png.latex?d%20%5Cle%20p"> such that</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AY%20%5Cperp%5C!%5C!%5C!%5Cperp%20X%20%5Cmid%20%5Ceta%5ET%20X.%0A"></p>
<p>Read this literally: once you know the <img src="https://latex.codecogs.com/png.latex?d"> reduced predictors <img src="https://latex.codecogs.com/png.latex?%5Ceta%5ET%20X">, the original <img src="https://latex.codecogs.com/png.latex?X"> tells you nothing more about <img src="https://latex.codecogs.com/png.latex?Y">. The <img src="https://latex.codecogs.com/png.latex?d"> linear combinations are a <em>sufficient reduction</em>.</p>
<p>Since any nonsingular reparameterization <img src="https://latex.codecogs.com/png.latex?%5Ceta%5ET%20X%20%5Cmapsto%20(A%5Ceta)%5ET%20X"> satisfies the same condition, what is identified is not <img src="https://latex.codecogs.com/png.latex?%5Ceta"> itself but the subspace it spans. The smallest such subspace (the intersection of all of them, when it exists) is the <em>central subspace</em>, written <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BS%7D_%7BY%7CX%7D">, and it is the estimand of the entire field. Its dimension <img src="https://latex.codecogs.com/png.latex?d"> is the number of directions in <img src="https://latex.codecogs.com/png.latex?X"> that genuinely matter for <img src="https://latex.codecogs.com/png.latex?Y">.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="the-central-subspace" class="level3">
<h3 class="anchored" data-anchor-id="the-central-subspace">The central subspace</h3>
<p>The central subspace turns a vague wish (“reduce <img src="https://latex.codecogs.com/png.latex?X"> without losing information”) into a well-defined target. Under mild regularity conditions it exists, is unique, and satisfies the conditional-independence condition above. Estimating it, rather than any particular basis, is what frees SDR from needing a model: two regressions as different as</p>
<p><img src="https://latex.codecogs.com/png.latex?Y%20=%20%5Cbeta%5ET%20X%20+%20%5Cvarepsilon%20%5Ctext%7B%20%20%20%20and%20%20%20%20%7D%20%5Ctext%7Blogit%7D(p)%20=%20%5Calpha%20+%20f(%5Cbeta_1%5ET%20X,%20%5Cbeta_2%5ET%20X)"></p>
<p>can share the same central subspace, and an SDR method estimates that common structure without knowing which regression generated the data. Once you have an estimated basis <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ceta">, plotting <img src="https://latex.codecogs.com/png.latex?Y"> against <img src="https://latex.codecogs.com/png.latex?%5Chat%5Ceta%5ET%20X">, a <em>sufficient summary plot</em>, is often the single most informative diagnostic you can draw, because by construction it hides nothing relevant.</p>
<hr>
</section>
<section id="sliced-inverse-regression" class="level3">
<h3 class="anchored" data-anchor-id="sliced-inverse-regression">Sliced inverse regression</h3>
<p>The foundational method, and still the first one to reach for, is sliced inverse regression (SIR), introduced by Li (1991). Its trick is to run the regression <em>backwards</em>. Modeling <img src="https://latex.codecogs.com/png.latex?Y%20%5Cmid%20X"> in high dimensions is hard; modeling <img src="https://latex.codecogs.com/png.latex?X%20%5Cmid%20Y"> is easy, because <img src="https://latex.codecogs.com/png.latex?Y"> is typically one-dimensional. SIR studies how the mean of <img src="https://latex.codecogs.com/png.latex?X"> shifts as <img src="https://latex.codecogs.com/png.latex?Y"> varies: it slices the range of <img src="https://latex.codecogs.com/png.latex?Y"> into bins, computes the mean of <img src="https://latex.codecogs.com/png.latex?X"> within each slice, and asks which directions those slice-means move along.</p>
<p>Under a mild <em>linearity condition</em> on the distribution of <img src="https://latex.codecogs.com/png.latex?X">, the centered inverse-regression curve <img src="https://latex.codecogs.com/png.latex?E%5BX%20%5Cmid%20Y%5D%20-%20E%5BX%5D"></p>
<p>lies in the central subspace, up to a covariance rescaling. Estimating it reduces to a generalized eigenvalue problem: the leading eigenvectors of the between-slice covariance, relative to <img src="https://latex.codecogs.com/png.latex?%5CSigma_X">, span (a subset of) <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BS%7D_%7BY%7CX%7D">. The eigenvalues themselves suggest <img src="https://latex.codecogs.com/png.latex?d"> — a sharp drop tells you how many directions to keep.</p>
<hr>
</section>
<section id="where-sir-fails-and-what-comes-after" class="level3">
<h3 class="anchored" data-anchor-id="where-sir-fails-and-what-comes-after">Where SIR fails, and what comes after</h3>
<p>SIR has one famous blind spot, and it is instructive. Because it only tracks how the <em>mean</em> of <img src="https://latex.codecogs.com/png.latex?X"> moves with <img src="https://latex.codecogs.com/png.latex?Y">, it is blind to dependence that shifts the <em>variance</em> while leaving the mean fixed.</p>
<p>The textbook example is <img src="https://latex.codecogs.com/png.latex?Y%20=%20X_1%5E2%20+%20%5Cvarepsilon"> with symmetric <img src="https://latex.codecogs.com/png.latex?X_1">: the slice means of <img src="https://latex.codecogs.com/png.latex?X"> barely move, SIR sees nothing, and reports an empty direction. Sliced average variance estimation (SAVE, Cook and Weisberg 1991) was built for exactly this case — it examines the slice-wise <em>covariance</em> of <img src="https://latex.codecogs.com/png.latex?X"> and so detects symmetric, curved dependence that SIR misses. The tradeoff is that SAVE needs more data to work well and leans on a second regularity assumption, the constant-covariance condition.</p>
<p>That tension (capture more structure versus require weaker assumptions) organizes the rest of the field. Later methods (directional regression, minimum discrepancy approaches, and the semiparametric formulations of Ma and Zhu) chip away at the linearity and constant-covariance conditions, extend SDR to the conditional mean alone (the <em>central mean subspace</em>), or push into the high-dimensional <img src="https://latex.codecogs.com/png.latex?p%20%3E%20n"> regime with sparsity. For most applied work, though, SIR is the right starting point and SAVE the right thing to try when SIR comes up empty despite an obvious relationship in the data.</p>
<hr>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>SDR reduces <img src="https://latex.codecogs.com/png.latex?X"> to a few linear combinations that retain <em>all</em> the information about <img src="https://latex.codecogs.com/png.latex?Y"> — unlike PCA, which ignores <img src="https://latex.codecogs.com/png.latex?Y"> and can discard the directions that matter.</li>
<li>The estimand is the central subspace <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BS%7D_%7BY%7CX%7D">, the smallest subspace such that <img src="https://latex.codecogs.com/png.latex?Y%20%5Cperp%5C!%5C!%5C!%5Cperp%20X%20%5Cmid%20%5Ceta%5ET%20X">; its dimension is the number of directions that truly drive the response.</li>
<li>Sliced inverse regression is the workhorse: regress <img src="https://latex.codecogs.com/png.latex?X"> on a sliced <img src="https://latex.codecogs.com/png.latex?Y">, then solve a generalized eigenvalue problem — model-free and computationally trivial.</li>
<li>SIR is blind to variance-only (symmetric, curved) dependence; reach for SAVE when there is obvious structure that SIR fails to detect.</li>
<li>All the classical methods lean on a linearity condition on <img src="https://latex.codecogs.com/png.latex?X">; it is mild but unverifiable, and it is where these methods can quietly break.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>Cook’s (2018) <em>Annual Review of Statistics</em> article, “Principal Components, Sufficient Dimension Reduction, and Envelopes,” is the ideal high-level entry point and the main source for this post — it places PCA, SDR, and envelopes on common footing through Fisher’s sufficiency. Li (1991) is the original SIR paper and remains very readable. For a book-length, code-oriented treatment, Bing Li’s <em>Sufficient Dimension Reduction: Methods and Applications with R</em> (2018) is the standard reference.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Cook, R. D. (2018). Principal components, sufficient dimension reduction, and envelopes. <em>Annual Review of Statistics and Its Application</em>, 5, 533–559.</p>
<p>Cook, R. D., and Weisberg, S. (1991). Discussion of “Sliced inverse regression for dimension reduction.” <em>Journal of the American Statistical Association</em>, 86(414), 328–332.</p>
<p>Li, B. (2018). <em>Sufficient Dimension Reduction: Methods and Applications with R</em>. Chapman and Hall/CRC.</p>
<p>Li, K.-C. (1991). Sliced inverse regression for dimension reduction. <em>Journal of the American Statistical Association</em>, 86(414), 316–327.</p>
<p>Ma, Y., and Zhu, L. (2012). A semiparametric approach to dimension reduction. <em>Journal of the American Statistical Association</em>, 107(497), 168–179.</p>


</section>

 ]]></description>
  <category>machine learning</category>
  <category>statistical inference</category>
  <guid>https://vyasenov.github.io/blog/sufficient-dimension-reduction.html</guid>
  <pubDate>Thu, 09 Jul 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>Propensity Scores When Treatment Isn’t Binary</title>
  <link>https://vyasenov.github.io/blog/generalized-propensity-score.html</link>
  <description><![CDATA[ 





<div class="reading-time">8 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>You know how to work with propensity scores when treatment is binary. Treatment is on or off, you model the probability of being treated given covariates, and then you match, weight, or stratify on that single number to recover a treated-versus-control contrast. I have written about the <a href="https://vyasenov.github.io/blog/flavors-prop-score-methods.html">zoo of methods that build on it</a>, and it is one of the most reliable workhorses in the applied causal toolkit.</p>
<p>But many of the treatments we actually care about are not switches, but dials. Hours of job training, milligrams of a drug, dollars of ad spend, days of hospital stay. The reflex is to dichotomize: call the top half “high dose,” the bottom half “low dose,” and run the familiar binary machinery. This is a mistake I have made myself, and it quietly throws away the most interesting part of the problem. The question with a dial is not “does treatment help?” but <em>what does the whole response curve look like?</em> — does it rise and then plateau, is there a sweet spot, are there diminishing returns? Collapsing the dose into two buckets answers none of that.</p>
<p>So how do we think about propensity scores when treatment goes from a switch to a dial? The reassuring answer is that the <em>logic</em> of the propensity score survives almost entirely intact. Let’s take a closer look.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Let <img src="https://latex.codecogs.com/png.latex?T%20%5Cin%20%5Cmathcal%7BT%7D"> be the treatment, now taking values in an interval <img src="https://latex.codecogs.com/png.latex?%5Bt_0,%20t_1%5D"> rather than <img src="https://latex.codecogs.com/png.latex?%5C%7B0,%201%5C%7D">. For each unit we posit a <em>unit-level dose–response function</em> <img src="https://latex.codecogs.com/png.latex?Y_i(t)">, the potential outcome that would be observed at dose <img src="https://latex.codecogs.com/png.latex?t">. The target is the average dose–response function</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmu(t)%20=%20%5Cmathbb%7BE%7D%5BY_i(t)%5D,%20%5Cqquad%20t%20%5Cin%20%5Cmathcal%7BT%7D,%0A"></p>
<p>an entire curve rather than a single number like <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D%5BY(1)%5D%20-%20%5Cmathbb%7BE%7D%5BY(0)%5D">. We observe covariates <img src="https://latex.codecogs.com/png.latex?X_i">, the realized dose <img src="https://latex.codecogs.com/png.latex?T_i">, and <img src="https://latex.codecogs.com/png.latex?Y_i%20=%20Y_i(T_i)">.</p>
<p>The identifying assumption generalizes unconfoundedness in a subtle way. Hirano and Imbens call it <em>weak unconfoundedness</em>:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AY(t)%20%5Cperp%20T%20%5Cmid%20X%20%5Cquad%20%5Ctext%7Bfor%20all%20%7D%20t%20%5Cin%20%5Cmathcal%7BT%7D.%0A"></p>
<p>The word “weak” matters. We do not require the whole family <img src="https://latex.codecogs.com/png.latex?%5C%7BY(t)%5C%7D_%7Bt%20%5Cin%20%5Bt_0,t_1%5D%7D"> to be jointly independent of <img src="https://latex.codecogs.com/png.latex?T"> given <img src="https://latex.codecogs.com/png.latex?X"> — only that the independence holds separately at each dose level. That is all the machinery needs, and it is a genuinely weaker requirement.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="the-scalar-score-becomes-a-density" class="level3">
<h3 class="anchored" data-anchor-id="the-scalar-score-becomes-a-density">The scalar score becomes a density</h3>
<p>With binary treatment, the propensity score <img src="https://latex.codecogs.com/png.latex?e(X)%20=%20P(T%20=%201%20%5Cmid%20X)"> is a single number in <img src="https://latex.codecogs.com/png.latex?%5B0,1%5D">. Its magic is dimension reduction: Rosenbaum and Rubin showed that conditioning on that one scalar is enough to remove covariate bias, no matter how many covariates went into it.</p>
<p>When <img src="https://latex.codecogs.com/png.latex?T"> is continuous, “the probability of receiving treatment” is no longer a probability — it is a density. The natural object is the conditional density of the treatment given covariates,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ar(t,%20x)%20=%20f_%7BT%20%5Cmid%20X%7D(t%20%5Cmid%20x),%0A"></p>
<p>and the <em>generalized propensity score</em> (GPS) is this density evaluated at the dose a unit actually received:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AR%20=%20r(T,%20X).%0A"></p>
<p>This is the one change that ripples through everything. The score is still a scalar random variable — but it is a scalar you get by plugging into a density, not by reading off a probability, and it now depends on <em>which</em> dose you are asking about.</p>
<hr>
</section>
<section id="what-the-gps-balances" class="level3">
<h3 class="anchored" data-anchor-id="what-the-gps-balances">What the GPS balances</h3>
<p>The binary score’s defining property is balance: within strata of equal <img src="https://latex.codecogs.com/png.latex?e(X)">, treatment is independent of <img src="https://latex.codecogs.com/png.latex?X">. The GPS inherits a version of this, but with a twist worth internalizing:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AX%20%5Cperp%20%5Cmathbf%7B1%7D%5C%7BT%20=%20t%5C%7D%20%5Cmid%20r(t,%20X).%0A"></p>
<p>Read carefully: balance holds <em>at each dose level <img src="https://latex.codecogs.com/png.latex?t"> separately</em>, conditioning on the score evaluated at that same <img src="https://latex.codecogs.com/png.latex?t">. You use as many propensity scores as there are levels of the treatment, yet you never use more than one at a time. This is the mental model shift.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>There is no single number that balances covariates across all doses simultaneously; there is a family of scores, one per dose, each balancing locally.</p>
</div>
</div>
<p>Notably, this balancing property is mechanical — it falls out of the definition and does not itself require unconfoundedness. Combine it with weak unconfoundedness and you get the payoff: assignment is unconfounded given the GPS.</p>
<hr>
</section>
<section id="recovering-the-curve" class="level3">
<h3 class="anchored" data-anchor-id="recovering-the-curve">Recovering the curve</h3>
<p>The estimation strategy is where the GPS earns its keep, and it is pleasingly concrete.</p>
<div class="callout callout-style-default callout-note callout-titled" title="Algorithm: GPS dose–response estimation">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>Algorithm: GPS dose–response estimation
</div>
</div>
<div class="callout-body-container callout-body">
<ol type="1">
<li><strong>Model the treatment.</strong> Estimate the conditional density <img src="https://latex.codecogs.com/png.latex?r(t,%20x)"> — e.g.&nbsp;fit by regression, and form the fitted score <img src="https://latex.codecogs.com/png.latex?%5Chat%20R_i%20=%20%5Chat%20r(T_i,%20X_i)"> for each unit.</li>
<li><strong>Regress outcome on dose and score.</strong> Estimate <img src="https://latex.codecogs.com/png.latex?%5Cbeta(t,%20r)%20=%20%5Cmathbb%7BE%7D%5BY%20%5Cmid%20T%20=%20t,%20R%20=%20r%5D">, treating the two <em>scalars</em> <img src="https://latex.codecogs.com/png.latex?T"> and <img src="https://latex.codecogs.com/png.latex?%5Chat%20R"> as the only regressors (say, a flexible polynomial in both).</li>
<li><strong>Average at each dose.</strong> For a target dose <img src="https://latex.codecogs.com/png.latex?t">, average the fitted surface over the score evaluated at that dose: <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cmu(t)%20=%20%5Cfrac%7B1%7D%7BN%7D%5Csum_i%20%5Chat%5Cbeta%5Cbig(t,%20%5Chat%20r(t,%20X_i)%5Cbig)">. Sweep <img src="https://latex.codecogs.com/png.latex?t"> across its range to trace out the whole curve.</li>
</ol>
</div>
</div>
<p>The step that trips people up is the third one. You do <em>not</em> average over <img src="https://latex.codecogs.com/png.latex?R%20=%20r(T,%20X)">, the score at each unit’s own realized dose. You average over <img src="https://latex.codecogs.com/png.latex?r(t,%20X)">, the score evaluated at the target dose <img src="https://latex.codecogs.com/png.latex?t"> for everyone. Getting this wrong silently biases the curve. Note also that <img src="https://latex.codecogs.com/png.latex?%5Cbeta(t,%20r)"> has no causal meaning on its own — the regression coefficients are not effects. Only after the averaging step does <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cmu(t)"> become interpretable, which is a familiar theme from <a href="https://vyasenov.github.io/blog/interpret-OLS-causal-inference.html">interpreting regression adjustments causally</a>.</p>
<hr>
</section>
<section id="multiple-implementations" class="level3">
<h3 class="anchored" data-anchor-id="multiple-implementations">Multiple implementations</h3>
<p>The GPS defined above is Hirano and Imbens’ route, and it is the cleanest place to build intuition. But the same core idea (reducing the covariates to a low-dimensional score summarizing treatment assignment) shows up in a few different shapes.</p>
<section id="propensity-function" class="level4">
<h4 class="anchored" data-anchor-id="propensity-function">Propensity function</h4>
<p>Imai and van Dyk arrive at the general case from a different angle. Rather than a density, they work with the <em>propensity function</em>: the entire conditional distribution of <img src="https://latex.codecogs.com/png.latex?T%20%5Cmid%20X">. When that distribution belongs to a parametric family, the propensity function collapses to its parameter (e.g.&nbsp;the mean of a normal), and you subclassify or adjust on that parameter. This unifies the ordinal, categorical, and continuous cases under one theory and connects back to Imbens’ original multi-valued treatment argument.</p>
</section>
<section id="weighting" class="level4">
<h4 class="anchored" data-anchor-id="weighting">Weighting</h4>
<p>Then there is the weighting route. Instead of adjusting for the score in a regression, you can weight each observation by the inverse of its GPS — the continuous analog of inverse-probability weighting, which underpins marginal structural models. This is tempting because it mirrors <a href="https://vyasenov.github.io/blog/two-types-weights-causality.html">the weighting logic so central to causal inference</a>, but I would sound a caution: with a continuous treatment the weights are ratios of densities, and they blow up wherever the estimated density is small. Extreme weights are already the <a href="https://vyasenov.github.io/blog/weights-statistics.html">Achilles’ heel of ordinary IPW</a>; with a continuum they can be worse, and stabilized weights become close to mandatory.</p>
</section>
<section id="stratification" class="level4">
<h4 class="anchored" data-anchor-id="stratification">Stratification</h4>
<p>A third route, stratification on the GPS, has been developed more recently as a way to sidestep the instability of weighting while keeping the nonparametric spirit.</p>
</section>
<section id="the-main-pitfall-overlap" class="level4">
<h4 class="anchored" data-anchor-id="the-main-pitfall-overlap">The main pitfall: overlap</h4>
<p>The deeper pitfall cuts across all three implementations: overlap. In the binary world, positivity means every unit has some chance of being treated and untreated. With a dial, you need positive density at <em>every</em> dose for <em>every</em> covariate profile — a far more demanding requirement, and one that is easy to violate without noticing. And because the score rides on a fitted density model, misspecifying <img src="https://latex.codecogs.com/png.latex?T%20%5Cmid%20X"> contaminates everything downstream. Check balance dose-by-dose; do not trust a single global diagnostic.</p>
</section>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>The logic of the propensity score survives the jump from binary to continuous treatment; what changes is that the score becomes a conditional <em>density</em> evaluated at the realized dose.</li>
<li>The estimand is a whole dose–response curve <img src="https://latex.codecogs.com/png.latex?%5Cmu(t)">, not a single contrast — which is exactly what dichotomizing a dose throws away.</li>
<li>Balance holds one dose at a time: there are as many scores as dose levels, but you only ever use one at once.</li>
<li>Estimation is a clean two-step recipe, but you must average the fitted surface over the score at the <em>target</em> dose, not each unit’s own dose.</li>
<li>Overlap is the real bottleneck — positivity at every dose is demanding — and inverse-GPS weighting is fragile, so treat extreme weights with suspicion.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>The foundational trio is short and readable. Imbens (2000) introduces the generalized propensity score for multi-valued treatments in a five-page <em>Biometrika</em> note. Hirano and Imbens (2004) extend it to the continuous case and lay out the two-step estimator and balancing theory — the single best starting point. Imai and van Dyk (2004) give the complementary “propensity function” formulation that unifies the whole family. For an applied illustration, Kluve et al.&nbsp;(2012) estimate the dose–response of training duration on employment, and Brown et al.&nbsp;(2021) develop the stratification variant.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Brown, D. W., Greene, T. J., Swartz, M. D., Wilkinson, A. V., &amp; DeSantis, S. M. (2021). Propensity Score Stratification Methods for Continuous Treatments. <em>Statistics in Medicine</em>, 40(5), 1189–1203.</p>
<p>Hirano, K., &amp; Imbens, G. W. (2004). The Propensity Score with Continuous Treatments. In A. Gelman &amp; X.-L. Meng (Eds.), <em>Applied Bayesian Modeling and Causal Inference from Incomplete-Data Perspectives</em> (pp.&nbsp;73–84). Wiley.</p>
<p>Imai, K., &amp; van Dyk, D. A. (2004). Causal Inference with General Treatment Regimes: Generalizing the Propensity Score. <em>Journal of the American Statistical Association</em>, 99(467), 854–866.</p>
<p>Imbens, G. W. (2000). The Role of the Propensity Score in Estimating Dose-Response Functions. <em>Biometrika</em>, 87(3), 706–710.</p>
<p>Kluve, J., Schneider, H., Uhlendorff, A., &amp; Zhao, Z. (2012). Evaluating Continuous Training Programmes by Using the Generalized Propensity Score. <em>Journal of the Royal Statistical Society: Series A</em>, 175(2), 587–617.</p>
<p>Robins, J. M., Hernán, M. Á., &amp; Brumback, B. (2000). Marginal Structural Models and Causal Inference in Epidemiology. <em>Epidemiology</em>, 11(5), 550–560.</p>
<p>Rosenbaum, P. R., &amp; Rubin, D. B. (1983). The Central Role of the Propensity Score in Observational Studies for Causal Effects. <em>Biometrika</em>, 70(1), 41–55.</p>


</section>

 ]]></description>
  <category>causal inference</category>
  <category>statistical inference</category>
  <guid>https://vyasenov.github.io/blog/generalized-propensity-score.html</guid>
  <pubDate>Wed, 01 Jul 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>Probability Calibration in ML</title>
  <link>https://vyasenov.github.io/blog/probability-calibration.html</link>
  <description><![CDATA[ 





<div class="reading-time">8 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>When are the outputs of <code>predict_proba</code> actual probabilities? If the model says <img src="https://latex.codecogs.com/png.latex?0.9">, should I assume that among all the cases it scored <img src="https://latex.codecogs.com/png.latex?0.9">, roughly <img src="https://latex.codecogs.com/png.latex?90%5C%25"> were positive. <em>Not always</em>!</p>
<p>For a logistic regression that reflex is mostly harmless. For a random forest, it can be badly wrong. The failure is silent, because the model’s accuracy and AUC look perfectly fine while the numbers themselves lie.</p>
<p>That is what calibration is about: whether a predicted probability <em>means</em> what it says. A model can rank cases beautifully (every positive scored above every negative) and still be dangerously miscalibrated, systematically over- or under-stating its confidence. Ranking and calibration are different, and most of machine learning optimizes for the first while quietly assuming the second.</p>
<p>This blog post is a deep dive on calibration in ML models. Calibration is not free, it is not always necessary, and applying it blindly can cost you. So I will walk through when the number actually needs to mean something, how to tell whether it does, and how to fix it when it doesn’t.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Consider binary classification with label <img src="https://latex.codecogs.com/png.latex?Y%20%5Cin%20%5C%7B0,%201%5C%7D"> and a model that outputs a score <img src="https://latex.codecogs.com/png.latex?%5Chat%7Bp%7D(X)%20%5Cin%20%5B0,%201%5D"> meant to estimate <img src="https://latex.codecogs.com/png.latex?P(Y%20=%201%20%5Cmid%20X)">. The model is <em>perfectly calibrated</em> if</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AP%5Cbig(Y%20=%201%20%5Cmid%20%5Chat%7Bp%7D(X)%20=%20p%5Cbig)%20=%20p%20%5Cquad%20%5Ctext%7Bfor%20all%20%7D%20p%20%5Cin%20%5B0,%201%5D.%0A"></p>
<p>In words: of all the cases assigned score <img src="https://latex.codecogs.com/png.latex?p">, a fraction <img src="https://latex.codecogs.com/png.latex?p"> are truly positive. This is a property of the score’s <em>marginal</em> relationship to the outcome, not of individual predictions — which is why a model can be calibrated and useless (predict the base rate for everyone) or sharp and miscalibrated (rank perfectly, wrong magnitudes). Good probabilities need both calibration <em>and</em> resolution (the tendency to push scores away from the base rate toward <img src="https://latex.codecogs.com/png.latex?0"> and <img src="https://latex.codecogs.com/png.latex?1">).</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="when-you-actually-need-it" class="level3">
<h3 class="anchored" data-anchor-id="when-you-actually-need-it">When you actually need it</h3>
<p>The single most useful question is: <em>does a downstream decision depend on the magnitude of the probability, or only on its order?</em></p>
<p>If you only need to <em>rank</em> — show the top-<img src="https://latex.codecogs.com/png.latex?k"> most likely churners, sort leads by score, compute AUC — calibration is irrelevant. Any monotonic transform of the score leaves the ranking, and hence AUC, unchanged. Recalibrating buys you nothing here and, with isotonic regression, can even <em>hurt</em> by introducing ties.</p>
<p>Calibration starts to matter the moment a probability feeds arithmetic. Expected-value decisions (<img src="https://latex.codecogs.com/png.latex?%5Ctext%7Bvalue%7D%20=%20p%20%5Ccdot%20%5Ctext%7Bgain%7D%20-%20(1-p)%20%5Ccdot%20%5Ctext%7Bcost%7D">) need the <img src="https://latex.codecogs.com/png.latex?p"> to be right, not just ordered. Thresholding at a fixed operating point (act when <img src="https://latex.codecogs.com/png.latex?p%20%3E%200.7">) assumes <img src="https://latex.codecogs.com/png.latex?0.7"> means something. Combining model outputs with other probabilities, feeding them to a Bayesian update, or reporting them to a human who will treat <img src="https://latex.codecogs.com/png.latex?0.9"> as “nearly certain” — all of these break under miscalibration. This is closely related to the distinction I drew between <a href="https://vyasenov.github.io/blog/diff-causal-predictive-models.html">causal and predictive models</a>: the use case dictates which properties of the output you are allowed to trust.</p>
<hr>
</section>
<section id="diagnosing-miscalibration" class="level3">
<h3 class="anchored" data-anchor-id="diagnosing-miscalibration">Diagnosing miscalibration</h3>
<p>The workhorse diagnostic is the <em>reliability diagram</em>: bin predictions by score, and for each bin plot the mean predicted probability (<img src="https://latex.codecogs.com/png.latex?x">-axis) against the observed fraction of positives (<img src="https://latex.codecogs.com/png.latex?y">-axis). Perfect calibration lies on the <img src="https://latex.codecogs.com/png.latex?45%5E%5Ccirc"> line. Curves below the diagonal signal over-confidence; curves above it, under-confidence. It is one of the plots I think everyone should have <a href="https://vyasenov.github.io/blog/six-plots-you-should-know.html">in their back pocket</a>.</p>
<p>The two panels below show the contrast. On the left, a well-calibrated model hugs the diagonal — its stated probabilities match observed frequencies. On the right, an over-confident model: it sits above the diagonal for low scores and below it for high ones, the telltale crossing pattern of a classifier whose probabilities are pushed too hard toward the extremes.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="../files/calibration-reliability.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1"><img src="https://vyasenov.github.io/files/calibration-reliability.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:100.0%" alt="Two reliability diagrams side by side. The left panel shows a well-calibrated model whose curve lies on the 45-degree diagonal. The right panel shows an over-confident model whose curve lies above the diagonal for low predicted probabilities and below it for high predicted probabilities."></a></p>
</figure>
</div>
<p>For a single number, use a proper scoring rule—a loss function that is minimized if and only if the predicted probability equals the true probability. The Brier score is the most intuitive: it is simply the mean squared error of the probabilities,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BBrier%7D%20=%20%5Cfrac%7B1%7D%7Bn%7D%20%5Csum_%7Bi=1%7D%5E%7Bn%7D%20%5Cbig(%5Chat%7Bp%7D_i%20-%20y_i%5Cbig)%5E2,%0A"></p>
<p>and log loss is its logarithmic cousin. But mind the trap: a low Brier score does not guarantee good calibration. According to Murphy’s decomposition, the Brier score is a sum of reliability (calibration), resolution (how much the predictions differ from the base rate), and an inherent uncertainty term.</p>
<p>A model that is “sharp” but miscalibrated—one that confidently predicts <img src="https://latex.codecogs.com/png.latex?0.9"> for a group that is actually <img src="https://latex.codecogs.com/png.latex?70%25"> positive—can still achieve a lower Brier score than a perfectly calibrated model that conservatively predicts <img src="https://latex.codecogs.com/png.latex?0.7"> for everyone. In other words, better discrimination can mask poor calibration in a single aggregate metric. To know if your probabilities are actually trustworthy, you cannot rely on the Brier score alone; pair it with a reliability diagram.</p>
<hr>
</section>
<section id="miscalibration-varies-by-model" class="level3">
<h3 class="anchored" data-anchor-id="miscalibration-varies-by-model">Miscalibration varies by model</h3>
<p>Not all classifiers misbehave the same way. Logistic regression is typically well-calibrated out of the box: minimizing log loss with the canonical logit link enforces a balance property that ties predicted probabilities to observed frequencies.</p>
<p>Naive Bayes, on the other hand, is <em>over-confident</em> — its independence assumption compounds evidence it should not, pushing scores toward <img src="https://latex.codecogs.com/png.latex?0"> and <img src="https://latex.codecogs.com/png.latex?1">.</p>
<p>Random forests and bagged ensembles, while extremely popular, are <em>under-confident</em>: averaging many trees pulls probabilities toward the middle, since it is rare for all trees to agree at the extremes, producing a telltale sigmoid reliability curve.</p>
<p>Max-margin methods like SVMs distort further still, because they optimize the decision boundary and never really estimate probabilities at all. Knowing the direction of a model’s bias tells you which fix will suit it.</p>
<hr>
</section>
<section id="fixes" class="level3">
<h3 class="anchored" data-anchor-id="fixes">Fixes</h3>
<p>Calibration is a post-processing step: fit a monotonic map from raw scores to calibrated probabilities on <em>held-out data</em>. The two classic choices trade flexibility against data hunger.</p>
<section id="platt-scaling" class="level4">
<h4 class="anchored" data-anchor-id="platt-scaling">Platt scaling</h4>
<p><em>Platt (sigmoid) scaling</em> fits a one-parameter logistic curve, <img src="https://latex.codecogs.com/png.latex?%5Chat%7Bp%7D%20=%201%20/%20(1%20+%20%5Cexp(A%20f%20+%20B)),"> mapping the raw score <img src="https://latex.codecogs.com/png.latex?f"> to a probability via just two fitted numbers <img src="https://latex.codecogs.com/png.latex?A,%20B">. In practice, take the model’s held-out scores <img src="https://latex.codecogs.com/png.latex?f_i"> and labels <img src="https://latex.codecogs.com/png.latex?y_i">, then choose <img src="https://latex.codecogs.com/png.latex?A"> and <img src="https://latex.codecogs.com/png.latex?B"> by minimizing binary log loss for the calibrated probabilities. Once fitted, the same sigmoid map is applied to future raw scores; <img src="https://latex.codecogs.com/png.latex?A"> controls the curve’s slope and <img src="https://latex.codecogs.com/png.latex?B"> shifts it left or right. It is stable on small samples and ideal for the sigmoid-shaped distortion of under-confident models like random forests — but its rigid parametric shape cannot fix non-sigmoid errors.</p>
</section>
<section id="isotonic-regression" class="level4">
<h4 class="anchored" data-anchor-id="isotonic-regression">Isotonic regression</h4>
<p><em>Isotonic regression</em> fits an arbitrary non-decreasing step function by least squares subject to monotonicity. In practice, take the model’s held-out scores <img src="https://latex.codecogs.com/png.latex?f_i"> and labels <img src="https://latex.codecogs.com/png.latex?y_i">, then estimate a monotone function <img src="https://latex.codecogs.com/png.latex?g"> by solving <img src="https://latex.codecogs.com/png.latex?%0A%5Chat%20g%20=%20%5Carg%5Cmin_%7Bg%20%5C%20%5Cmathrm%7Bnondecreasing%7D%7D%20%5Csum_i%20%5Cbig(y_i%20-%20g(f_i)%5Cbig)%5E2.%0A"> The calibrated probability is then <img src="https://latex.codecogs.com/png.latex?%5Chat%20p_i%20=%20%5Chat%20g(f_i)">. It corrects <em>any</em> monotonic distortion and is more powerful, but it overfits on small datasets and needs a few thousand calibration points to behave.</p>
</section>
<section id="temperature-scaling" class="level4">
<h4 class="anchored" data-anchor-id="temperature-scaling">Temperature scaling</h4>
<p>For multiclass neural networks, <em>temperature scaling</em> (dividing the logits by a single learned scalar <img src="https://latex.codecogs.com/png.latex?T"> before the softmax) is the standard lightweight fix; it sharpens or softens all probabilities at once without changing the predicted class, so accuracy is untouched.</p>
</section>
<section id="what-not-to-do" class="level4">
<h4 class="anchored" data-anchor-id="what-not-to-do">What Not to Do</h4>
<p>The one thing you must not do is calibrate on the data the model trained on. An overfit classifier looks perfectly calibrated on its own training set, so the calibrator learns nothing and you ship overconfidence. Scikit-learn’s <code>CalibratedClassifierCV</code> handles this with cross-validation: it fits the calibrator on out-of-fold predictions, keeping calibration data disjoint from training data.</p>
</section>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>Calibration asks whether a predicted probability means what it says; a model can rank perfectly and still be badly miscalibrated.</li>
<li>If you only need ranking or the argmax class, skip calibration — it changes nothing and can add noise.</li>
<li>Calibrate when magnitudes drive decisions: expected value, fixed thresholds, probability arithmetic, or numbers shown to humans.</li>
<li>Diagnose with a reliability diagram, not a Brier score alone — a proper scoring rule mixes calibration with discrimination.</li>
<li>Fit the calibrator on held-out data: sigmoid for small samples and sigmoid-shaped error, isotonic when you have thousands of points, temperature scaling for neural nets.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>For a hands-on tour, the <a href="https://scikit-learn.org/stable/modules/calibration.html">scikit-learn calibration guide</a> is excellent. For a deeper dive, see the references below.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Guo, C., Pleiss, G., Sun, Y., &amp; Weinberger, K. Q. (2017). On Calibration of Modern Neural Networks. <em>Proceedings of the 34th International Conference on Machine Learning (ICML)</em>, 1321–1330.</p>
<p>Niculescu-Mizil, A., &amp; Caruana, R. (2005). Predicting Good Probabilities with Supervised Learning. <em>Proceedings of the 22nd International Conference on Machine Learning (ICML)</em>, 625–632.</p>
<p>Platt, J. (1999). Probabilistic Outputs for Support Vector Machines and Comparisons to Regularized Likelihood Methods. In <em>Advances in Large Margin Classifiers</em>, MIT Press, 61–74.</p>
<p>Zadrozny, B., &amp; Elkan, C. (2002). Transforming Classifier Scores into Accurate Multiclass Probability Estimates. <em>Proceedings of the 8th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining</em>, 694–699.</p>


</section>

 ]]></description>
  <category>machine learning</category>
  <category>statistical inference</category>
  <guid>https://vyasenov.github.io/blog/probability-calibration.html</guid>
  <pubDate>Wed, 01 Jul 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>Kronecker Products in Econometrics</title>
  <link>https://vyasenov.github.io/blog/kronecker-products.html</link>
  <description><![CDATA[ 





<div class="reading-time">3 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Open any econometrics text past the introductory chapters and you will eventually hit a <img src="https://latex.codecogs.com/png.latex?%5Cotimes"> — the Kronecker product — usually bolted onto a covariance matrix and usually without much explanation. It is the notation econometricians reach for whenever a model has block structure: several equations stacked together, a panel of units tracked over time, a system whose errors are correlated across equations but independent across observations. The symbol looks forbidding, the idea behind it is not, and once you see it a handful of otherwise-dense formulas snap into place. This is a short tour of what the operation is and the three places you are most likely to meet it.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="the-kronecker-product" class="level3">
<h3 class="anchored" data-anchor-id="the-kronecker-product">The Kronecker Product</h3>
<p>Given an <img src="https://latex.codecogs.com/png.latex?m%20%5Ctimes%20n"> matrix <img src="https://latex.codecogs.com/png.latex?A"> and a <img src="https://latex.codecogs.com/png.latex?p%20%5Ctimes%20q"> matrix <img src="https://latex.codecogs.com/png.latex?B">, their <strong>Kronecker product</strong> <img src="https://latex.codecogs.com/png.latex?A%20%5Cotimes%20B"> is the <img src="https://latex.codecogs.com/png.latex?mp%20%5Ctimes%20nq"> block matrix you get by multiplying every entry of <img src="https://latex.codecogs.com/png.latex?A"> by the entire matrix <img src="https://latex.codecogs.com/png.latex?B">:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AA%20%5Cotimes%20B%20=%0A%5Cbegin%7Bpmatrix%7D%0Aa_%7B11%7D%20B%20&amp;%20%5Ccdots%20&amp;%20a_%7B1n%7D%20B%20%5C%5C%0A%5Cvdots%20%20%20&amp;%20%20%20%20%20%20%20%20&amp;%20%5Cvdots%20%20%20%5C%5C%0Aa_%7Bm1%7D%20B%20&amp;%20%5Ccdots%20&amp;%20a_%7Bmn%7D%20B%0A%5Cend%7Bpmatrix%7D.%0A"></p>
<p>A small example makes the pattern obvious:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Bpmatrix%7D%201%20&amp;%202%20%5C%5C%203%20&amp;%204%20%5Cend%7Bpmatrix%7D%20%5Cotimes%20I_2%20=%0A%5Cbegin%7Bpmatrix%7D%0A1%20&amp;%200%20&amp;%202%20&amp;%200%20%5C%5C%0A0%20&amp;%201%20&amp;%200%20&amp;%202%20%5C%5C%0A3%20&amp;%200%20&amp;%204%20&amp;%200%20%5C%5C%0A0%20&amp;%203%20&amp;%200%20&amp;%204%0A%5Cend%7Bpmatrix%7D.%0A"></p>
<hr>
</section>
<section id="working-with-kronecker-products" class="level3">
<h3 class="anchored" data-anchor-id="working-with-kronecker-products">Working with Kronecker products</h3>
<p>Two algebraic facts do almost all the work in applications. The first is the <em>mixed-product rule</em>, <img src="https://latex.codecogs.com/png.latex?(A%20%5Cotimes%20B)(C%20%5Cotimes%20D)%20=%20(AC)%20%5Cotimes%20(BD),"> valid whenever the ordinary products are conformable.</p>
<p>The second is its corollary for inverses, <img src="https://latex.codecogs.com/png.latex?(A%20%5Cotimes%20B)%5E%7B-1%7D%20=%20A%5E%7B-1%7D%20%5Cotimes%20B%5E%7B-1%7D."> That second identity is the reason the operation is so beloved: inverting a giant <img src="https://latex.codecogs.com/png.latex?mp%20%5Ctimes%20mp"> matrix collapses into inverting its two small factors separately. Transposition behaves just as cleanly, <img src="https://latex.codecogs.com/png.latex?(A%20%5Cotimes%20B)'%20=%20A'%20%5Cotimes%20B'."></p>
<hr>
</section>
<section id="where-they-show-up" class="level3">
<h3 class="anchored" data-anchor-id="where-they-show-up">Where They Show Up</h3>
<section id="seemingly-unrelated-regressions" class="level4">
<h4 class="anchored" data-anchor-id="seemingly-unrelated-regressions">Seemingly unrelated regressions</h4>
<p>Zellner’s (1962) SUR model stacks <img src="https://latex.codecogs.com/png.latex?M"> regression equations that may share nothing in their regressors but whose errors are contemporaneously correlated. Across the stacked system of <img src="https://latex.codecogs.com/png.latex?M"> equations and <img src="https://latex.codecogs.com/png.latex?n"> observations, the disturbance covariance is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Coperatorname%7BVar%7D(u)%20=%20%5CSigma%20%5Cotimes%20I_n,%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?%5CSigma"> is the <img src="https://latex.codecogs.com/png.latex?M%20%5Ctimes%20M"> matrix of cross-equation error covariances and <img src="https://latex.codecogs.com/png.latex?I_n"> encodes independence across observations. Efficient (GLS) estimation needs <img src="https://latex.codecogs.com/png.latex?(%5CSigma%20%5Cotimes%20I_n)%5E%7B-1%7D%20=%20%5CSigma%5E%7B-1%7D%20%5Cotimes%20I_n"> — a tiny <img src="https://latex.codecogs.com/png.latex?M%20%5Ctimes%20M"> inverse rather than an <img src="https://latex.codecogs.com/png.latex?Mn%20%5Ctimes%20Mn"> one. The same structure underpins three-stage least squares for systems of simultaneous equations.</p>
</section>
<section id="panel-and-random-effects-models" class="level4">
<h4 class="anchored" data-anchor-id="panel-and-random-effects-models">Panel and random-effects models</h4>
<p>In the one-way error-component model <img src="https://latex.codecogs.com/png.latex?u_%7Bit%7D%20=%20%5Cmu_i%20+%20%5Cvarepsilon_%7Bit%7D">, the <img src="https://latex.codecogs.com/png.latex?NT%20%5Ctimes%20NT"> disturbance covariance for <img src="https://latex.codecogs.com/png.latex?N"> units observed over <img src="https://latex.codecogs.com/png.latex?T"> periods is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5COmega%20=%20%5Csigma_%5Cmu%5E2%20%5C,%20(I_N%20%5Cotimes%20J_T)%20+%20%5Csigma_%5Cvarepsilon%5E2%20%5C,%20(I_N%20%5Cotimes%20I_T),%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?J_T"> is the <img src="https://latex.codecogs.com/png.latex?T%20%5Ctimes%20T"> matrix of ones. The Kronecker form delivers <img src="https://latex.codecogs.com/png.latex?%5COmega%5E%7B-1%7D"> and <img src="https://latex.codecogs.com/png.latex?%5COmega%5E%7B-1/2%7D"> — the latter being the “quasi-demeaning” transform behind the random-effects estimator — in closed form, again by manipulating only the small <img src="https://latex.codecogs.com/png.latex?T%20%5Ctimes%20T"> factors.</p>
</section>
<section id="weak-instruments" class="level4">
<h4 class="anchored" data-anchor-id="weak-instruments">Weak instruments</h4>
<p>The Kronecker product even lurks behind the <a href="https://vyasenov.github.io/blog/weak-instruments.html">weak-instrument</a> critical values. Under homoskedasticity, the joint sampling covariance of the reduced-form and first-stage coefficient estimators factors as <img src="https://latex.codecogs.com/png.latex?%5CSigma%20%5Cotimes%20Q_%7BZZ%7D%5E%7B-1%7D"> — a cross-equation covariance times a design term. It is exactly this separable structure that Stock and Yogo (2005) exploit to tabulate their thresholds. Heteroskedasticity destroys the factorization, which is precisely why those tables stop applying and you have to fall back on the effective <img src="https://latex.codecogs.com/png.latex?F">-statistic.</p>


</section>
</section>
</section>

 ]]></description>
  <category>parametric models</category>
  <category>statistical inference</category>
  <guid>https://vyasenov.github.io/blog/kronecker-products.html</guid>
  <pubDate>Thu, 25 Jun 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>Working with Weak Instruments</title>
  <link>https://vyasenov.github.io/blog/weak-instruments.html</link>
  <description><![CDATA[ 





<div class="reading-time">10 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Weak instruments are not merely unhelpful; they can waste your time <em>and</em> your nerves. With a weak IV in hand, you can spend months trying to “fix” it, only for your paper or analysis to be rejected on the simple grounds that the instrument is weak. For some time, the folk wisdom dictated that if your first-stage <img src="https://latex.codecogs.com/png.latex?F">-statistic cleared <img src="https://latex.codecogs.com/png.latex?10">, your instrument was “strong,” and you could proceed to report your two-stage least squares (2SLS) estimate. The econometrics literature has recently revisited both this rule and the practical recommendations for working with weak instruments.</p>
<p>This post picks up where my earlier note on <a href="https://vyasenov.github.io/blog/iv-randomized-experiments.html">instrumental variables in randomized experiments</a> left off. There I treated the <em>identification</em> side of IV — the local average treatment effect, the Wald ratio, the four assumptions that make it all work. Here I take identification for granted and worry about <em>inference</em>: once you have a just-identified IV estimate in hand, how do you build an honest confidence interval when the instrument is only weakly correlated with the endogenous regressor? The literature has converged on a verdict — the <img src="https://latex.codecogs.com/png.latex?F%3E10"> rule is broken — and then split into two camps over the remedy. One camp says abandon the <img src="https://latex.codecogs.com/png.latex?t">-test and invert the Anderson–Rubin statistic instead. The other says keep the <img src="https://latex.codecogs.com/png.latex?t">-test but stop pretending the critical value is <img src="https://latex.codecogs.com/png.latex?1.96">. I will lay out both, with the mathematics, and let you decide which side is right.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>I stay in the simplest possible setting throughout: one outcome, one endogenous regressor, one instrument — the <em>just-identified</em> case. Index observations by <img src="https://latex.codecogs.com/png.latex?i"> and write the structural equation, first stage, and reduced form as</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbegin%7Baligned%7D%0AY_i%20&amp;=%20%5Cbeta%20X_i%20+%20u_i,%20%5C%5C%0AX_i%20&amp;=%20%5Cpi%20Z_i%20+%20v_i,%20%5C%5C%0AY_i%20&amp;=%20%5Cdelta%20Z_i%20+%20%5Cvarepsilon_i,%0A%5Cend%7Baligned%7D%0A"> where</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?Z_i"> is the instrument,</li>
<li><img src="https://latex.codecogs.com/png.latex?X_i"> the endogenous regressor, and</li>
<li><img src="https://latex.codecogs.com/png.latex?u_i"> correlated with <img src="https://latex.codecogs.com/png.latex?v_i"> — the endogeneity that motivates IV in the first place.</li>
</ul>
<p>Any exogenous controls are partialled out of all three equations; nothing below changes.</p>
<p>The exclusion restriction <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D%5BZ_i%20u_i%5D%20=%200"> ties the three equations together through the single restriction</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cdelta%20=%20%5Cpi%20%5Cbeta.%0A"></p>
<p>The IV estimator is the ratio of the reduced-form to first-stage slopes,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%5Cbeta%20=%20%5Cfrac%7B%5Chat%5Cdelta%7D%7B%5Chat%5Cpi%7D%20=%20%5Cfrac%7B%5Cwidehat%7B%5Ctext%7BCov%7D%7D(Z,%20Y)%7D%7B%5Cwidehat%7B%5Ctext%7BCov%7D%7D(Z,%20X)%7D,%0A"></p>
<p>the Wald estimator.</p>
<p>The trouble lives entirely in that denominator. When <img src="https://latex.codecogs.com/png.latex?%5Cpi"> is small relative to the sampling noise in <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cpi">, we are dividing by something close to zero, and <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> — a ratio of two correlated normals — is badly non-normal. Its <img src="https://latex.codecogs.com/png.latex?t">-statistic does not behave like a standard normal, no matter how large the sample.</p>
<p><em>Weak</em> means exactly this: <img src="https://latex.codecogs.com/png.latex?%5Cpi"> is small relative to <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BSE%7D(%5Chat%5Cpi)">. The standard gauge of instrument strength is the first-stage (partial) <img src="https://latex.codecogs.com/png.latex?F">-statistic, which in this single-instrument world is just the squared <img src="https://latex.codecogs.com/png.latex?t">-statistic on <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cpi">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AF%20=%20%5Cleft(%20%5Cfrac%7B%5Chat%5Cpi%7D%7B%5Ctext%7BSE%7D(%5Chat%5Cpi)%7D%20%5Cright)%5E2%20.%0A"></p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="why-the-f-10-rule-broke" class="level3">
<h3 class="anchored" data-anchor-id="why-the-f-10-rule-broke">Why the “F &gt; 10” rule broke</h3>
<p>The rule of thumb traces to Staiger and Stock (1997), who suggested <img src="https://latex.codecogs.com/png.latex?F%3E10"> as a rough indicator that weak-instrument distortions were tolerable. Stock and Yogo (2005) made it rigorous by defining “weak” through worst-case performance and tabulating critical values under two distinct criteria.</p>
<ul>
<li>The <em>bias</em> criterion asks how large the worst-case 2SLS bias is relative to OLS; its critical values sit near <img src="https://latex.codecogs.com/png.latex?10"> across a range of instrument counts, which is where the folklore comes from.</li>
<li>The <em>size</em> criterion asks how badly a nominal 5% <img src="https://latex.codecogs.com/png.latex?t">-test can over-reject; its critical values are a different animal, rising from about <img src="https://latex.codecogs.com/png.latex?9"> with one instrument to nearly <img src="https://latex.codecogs.com/png.latex?45"> with thirty. Already the single number “10” is doing two incompatible jobs.</li>
</ul>
<p>The deeper problem is that the entire Stock–Yogo apparatus was derived under <em>homoskedasticity</em>. The critical values depend on a Kronecker-product structure in the covariance matrix that simply does not hold once errors are heteroskedastic, clustered, or serially correlated — which is to say, in essentially every applied setting.</p>
<hr>
</section>
<section id="the-effective-f-statistic" class="level3">
<h3 class="anchored" data-anchor-id="the-effective-f-statistic">The effective F-statistic</h3>
<p>The fix for <em>measuring</em> strength is due to Montiel Olea and Pflueger (2013), who introduced what they call the <em>effective <img src="https://latex.codecogs.com/png.latex?F">-statistic</em>. The conventional first-stage <img src="https://latex.codecogs.com/png.latex?F"> and even the naive robust Wald <img src="https://latex.codecogs.com/png.latex?F"> have, as Andrews, Stock, and Sun (2019) put it, “no theoretical justification” for gauging instrument strength under heteroskedasticity — they target the wrong population object or misstate its variance.</p>
<p>The effective <img src="https://latex.codecogs.com/png.latex?F"> replaces the variance term with a heteroskedasticity-robust analogue:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AF_%7B%5Ctext%7Beff%7D%7D%20=%20%5Cfrac%7B%5Chat%5Cpi'%20%5Chat%7BQ%7D_%7BZZ%7D%20%5Chat%5Cpi%7D%7B%5Coperatorname%7Btr%7D%5C!%5Cbig(%5Chat%5CSigma_%7B%5Cpi%5Cpi%7D%5Chat%7BQ%7D_%7BZZ%7D%5Cbig)%7D,%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?%5Chat%7BQ%7D_%7BZZ%7D"> is the instrument second-moment matrix and <img src="https://latex.codecogs.com/png.latex?%5Chat%5CSigma_%7B%5Cpi%5Cpi%7D"> the robust variance of <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cpi">. It collapses to the usual <img src="https://latex.codecogs.com/png.latex?F"> under homoskedasticity and, crucially, “measures the right object and gets the standard errors right on average.” In the just-identified case it coincides with the robust first-stage <img src="https://latex.codecogs.com/png.latex?F">.</p>
<p>The practical instruction is simple: whenever you report a first-stage <img src="https://latex.codecogs.com/png.latex?F"> as a strength diagnostic, it should be the effective one, compared against the appropriate Montiel Olea–Pflueger critical values rather than a remembered “10.”</p>
<hr>
</section>
<section id="the-andersonrubin-test" class="level3">
<h3 class="anchored" data-anchor-id="the-andersonrubin-test">The Anderson–Rubin test</h3>
<p>Measuring strength is only half the battle; the harder question is what to report for <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> when strength is in doubt. The oldest and most robust answer is the <strong>Anderson–Rubin (AR) test</strong>, dating to 1949. Instead of forming <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta%20%5Cpm%201.96%5C,%5Ctext%7BSE%7D">, AR inverts a test. To test <img src="https://latex.codecogs.com/png.latex?H_0:%20%5Cbeta%20=%20%5Cbeta_0">, construct the residual <img src="https://latex.codecogs.com/png.latex?Y_i%20-%20%5Cbeta_0%20X_i"> and ask whether it is correlated with the instrument. Under the null,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AY_i%20-%20%5Cbeta_0%20X_i%20=%20(%5Cdelta%20-%20%5Cbeta_0%20%5Cpi)%20Z_i%20+%20%5Ctext%7Bnoise%7D,%0A"></p>
<p>and the coefficient on <img src="https://latex.codecogs.com/png.latex?Z_i"> is <img src="https://latex.codecogs.com/png.latex?%5Cdelta%20-%20%5Cbeta_0%20%5Cpi">, which equals zero precisely when <img src="https://latex.codecogs.com/png.latex?%5Cbeta_0"> is the true <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> (since <img src="https://latex.codecogs.com/png.latex?%5Cdelta%20=%20%5Cpi%5Cbeta">). So the AR statistic is just the squared <img src="https://latex.codecogs.com/png.latex?t">-statistic for <img src="https://latex.codecogs.com/png.latex?Z"> in the regression of <img src="https://latex.codecogs.com/png.latex?Y%20-%20%5Cbeta_0%20X"> on <img src="https://latex.codecogs.com/png.latex?Z">, and under <img src="https://latex.codecogs.com/png.latex?H_0"> it is distributed <img src="https://latex.codecogs.com/png.latex?%5Cchi%5E2_1"> <em>regardless of the value of <img src="https://latex.codecogs.com/png.latex?%5Cpi"></em> — even at <img src="https://latex.codecogs.com/png.latex?%5Cpi%20=%200">. That is the whole trick: testing whether a coefficient is zero in a clean regression does not care how strong the instrument is.</p>
<p>The confidence set is the collection of nulls the test fails to reject,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0ACS_%7BAR%7D%20=%20%5C%7B%5Cbeta_0%20:%20AR(%5Cbeta_0)%20%5Cle%20%5Cchi%5E2_%7B1,%5C,0.95%7D%5C%7D%20=%20%5C%7B%5Cbeta_0%20:%20AR(%5Cbeta_0)%20%5Cle%203.841%5C%7D.%0A"></p>
<p>The key point is that AR’s occasional unbounded intervals are not a defect: under very weak instruments, any honest procedure must sometimes admit that the data cannot pin <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> down, while AR still works well when identification is strong.</p>
<hr>
</section>
<section id="fix-1-abandon-the-t-test" class="level3">
<h3 class="anchored" data-anchor-id="fix-1-abandon-the-t-test">Fix 1: abandon the <img src="https://latex.codecogs.com/png.latex?t">-test</h3>
<p>The Annual Review tradition — Andrews, Stock, and Sun (2019) as the canonical statement — draws the natural conclusion: in the just-identified case, report AR intervals, and that’s it. Keane and Neal (2024) push this to its sharp edge and argue for abandoning the 2SLS <img src="https://latex.codecogs.com/png.latex?t">-test <em>even when instruments are strong</em>. Their argument is a power asymmetry that the older literature, fixated on bias and size, had missed.</p>
<p>The mechanism is the 2SLS standard error itself. The estimated structural variance entering <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BSE%7D(%5Chat%5Cbeta)"> is a quadratic function of <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> that is <em>minimized at the OLS estimate</em>. So whenever a draw of <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> lands near OLS, its standard error is artificially small, and the <img src="https://latex.codecogs.com/png.latex?t">-test is correspondingly eager to declare significance. The upshot is a test with inflated power to detect false positives in the direction of the OLS bias and almost no power to detect true effects lying away from OLS. Keane and Neal show this distortion persists at first-stage <img src="https://latex.codecogs.com/png.latex?F"> values of <img src="https://latex.codecogs.com/png.latex?30">, <img src="https://latex.codecogs.com/png.latex?50">, even <img src="https://latex.codecogs.com/png.latex?70"> — far above any conventional threshold — and conclude that the bar for the <img src="https://latex.codecogs.com/png.latex?F"> should be raised to roughly <img src="https://latex.codecogs.com/png.latex?50">, and that one should simply use AR throughout. The AR standard error, by contrast, is built around a variance minimized at <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_%7B2SLS%7D"> rather than at OLS, which is exactly what kills the asymmetry.</p>
<hr>
</section>
<section id="fix-2-fix-the-t-test-instead" class="level3">
<h3 class="anchored" data-anchor-id="fix-2-fix-the-t-test-instead">Fix 2: fix the <img src="https://latex.codecogs.com/png.latex?t">-test instead</h3>
<p>Lee, McCrary, Moreira, and Porter (2022) accept the diagnosis and reject the prescription. Their objection is practical: practitioners know and trust the <img src="https://latex.codecogs.com/png.latex?t">-ratio, the entire reporting apparatus is built around it, and throwing it out is a heavy ask. The <img src="https://latex.codecogs.com/png.latex?t">-statistic is not normal under weak instruments — true — but its non-normal distribution is <em>known</em>, and depends on the data only through the observed first-stage <img src="https://latex.codecogs.com/png.latex?F">. So rather than discard it, replace the constant <img src="https://latex.codecogs.com/png.latex?1.96"> with a critical value <img src="https://latex.codecogs.com/png.latex?c_%5Calpha(%5Chat%20F)"> that is a smooth, decreasing function of the first stage. They call this the <em>tF procedure</em>.</p>
<p>The headline number is sobering. For the constant <img src="https://latex.codecogs.com/png.latex?1.96"> to deliver a genuine 5% test, you do not need <img src="https://latex.codecogs.com/png.latex?F%20%3E%2010">, or even Stock and Yogo’s <img src="https://latex.codecogs.com/png.latex?F%20%3E%2016.38"> — you need</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AF%20%5Capprox%20104.7.%0A"></p>
<p>Below that, <img src="https://latex.codecogs.com/png.latex?1.96"> is too small and you must inflate.</p>
<p>Operationally the procedure is a lookup: estimate your usual (robust, clustered) 2SLS standard error, read the adjustment factor off their Table 3 at your observed <img src="https://latex.codecogs.com/png.latex?%5Chat%20F">, and multiply. A few anchor points at the 5% level make the magnitude vivid:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th style="text-align: center;">First-stage <img src="https://latex.codecogs.com/png.latex?%5Chat%20F"></th>
<th style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?tF"> critical value</th>
<th style="text-align: center;">SE multiplier</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?5"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?6.85"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?%5Ctimes%203.50"></td>
</tr>
<tr class="even">
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?10"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?3.43"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?%5Ctimes%201.75"></td>
</tr>
<tr class="odd">
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?16.6"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?2.76"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?%5Ctimes%201.41"></td>
</tr>
<tr class="even">
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?24.6"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?2.46"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?%5Ctimes%201.26"></td>
</tr>
<tr class="odd">
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?104.7"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?1.96"></td>
<td style="text-align: center;"><img src="https://latex.codecogs.com/png.latex?%5Ctimes%201.00"></td>
</tr>
</tbody>
</table>
<p>At the celebrated <img src="https://latex.codecogs.com/png.latex?F=10">, an honest 95% interval is about <img src="https://latex.codecogs.com/png.latex?75%5C%25"> wider than the one most papers report, and <img src="https://latex.codecogs.com/png.latex?tF"> can still be shorter than AR when both intervals are bounded because it reserves its “we cannot learn <img src="https://latex.codecogs.com/png.latex?%5Cbeta">” verdict for the rare cases where <img src="https://latex.codecogs.com/png.latex?%5Chat%20F%20%3C%203.84">.</p>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>The “<img src="https://latex.codecogs.com/png.latex?F%20%3E%2010">” rule is broken: a genuine 5% <img src="https://latex.codecogs.com/png.latex?t">-test needs <img src="https://latex.codecogs.com/png.latex?F%20%5Capprox%20104.7">, not 10.</li>
<li>Gauge instrument strength with the effective <img src="https://latex.codecogs.com/png.latex?F">-statistic (Montiel Olea–Pflueger), not the conventional first-stage <img src="https://latex.codecogs.com/png.latex?F">.</li>
<li>For a robust default, report the Anderson–Rubin interval — valid at any instrument strength, and free of cost when instruments are strong.</li>
<li>To keep the familiar <img src="https://latex.codecogs.com/png.latex?t">-ratio, use <img src="https://latex.codecogs.com/png.latex?tF">: inflate the SE by the Table 3 factor at your observed <img src="https://latex.codecogs.com/png.latex?F">; it even beats AR on interval length.</li>
<li>Either way, heed Young (2022): under non-iid errors a few high-leverage clusters can drive both <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> and the <img src="https://latex.codecogs.com/png.latex?F"> — check leverage before trusting any interval.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>For the canonical survey, Andrews, Stock, and Sun (2019, <em>Annual Review of Economics</em>) is the place to start — comprehensive, careful, and explicit about the heteroskedastic case. Keane and Neal (2024, <em>Annual Review of Economics</em>) is the most accessible statement of the “abandon the <img src="https://latex.codecogs.com/png.latex?t">-test” position and worth reading for the power-asymmetry argument alone. Lee, McCrary, Moreira, and Porter (2022, <em>American Economic Review</em>) lay out the <img src="https://latex.codecogs.com/png.latex?tF"> procedure with its adjustment tables, and their follow-up working paper extends it to the sharper V<img src="https://latex.codecogs.com/png.latex?tF"> refinement. Young (2022, <em>European Economic Review</em>) is a bracing empirical reality check on how fragile published IV results actually are.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<ul>
<li><p>Anderson, T. W., &amp; Rubin, H. (1949). Estimation of the parameters of a single equation in a complete system of stochastic equations. <em>Annals of Mathematical Statistics</em>, 20(1), 46–63.</p></li>
<li><p>Andrews, I., Stock, J. H., &amp; Sun, L. (2019). Weak instruments in instrumental variables regression: Theory and practice. <em>Annual Review of Economics</em>, 11, 727–753.</p></li>
<li><p>Dufour, J.-M. (1997). Some impossibility theorems in econometrics with applications to structural and dynamic models. <em>Econometrica</em>, 65(6), 1365–1387.</p></li>
<li><p>Gleser, L. J., &amp; Hwang, J. T. (1987). The nonexistence of <img src="https://latex.codecogs.com/png.latex?100(1-%5Calpha)%5C%25"> confidence sets of finite expected diameter in errors-in-variables and related models. <em>Annals of Statistics</em>, 15(4), 1351–1362.</p></li>
<li><p>Keane, M. P., &amp; Neal, T. (2024). A practical guide to weak instruments. <em>Annual Review of Economics</em>, 16, 185–212.</p></li>
<li><p>Lee, D. S., McCrary, J., Moreira, M. J., &amp; Porter, J. (2022). Valid <img src="https://latex.codecogs.com/png.latex?t">-ratio inference for IV. <em>American Economic Review</em>, 112(10), 3260–3290.</p></li>
<li><p>Lee, D. S., McCrary, J., Moreira, M. J., Porter, J., &amp; Yap, L. (2023). What to do when you can’t use ‘1.96’ confidence intervals for IV. <em>NBER Working Paper No.&nbsp;31893</em>.</p></li>
<li><p>Montiel Olea, J. L., &amp; Pflueger, C. (2013). A robust test for weak instruments. <em>Journal of Business &amp; Economic Statistics</em>, 31(3), 358–369.</p></li>
<li><p>Moreira, M. J. (2009). Tests with correct size when instruments can be arbitrarily weak. <em>Journal of Econometrics</em>, 152(2), 131–140.</p></li>
<li><p>Staiger, D., &amp; Stock, J. H. (1997). Instrumental variables regression with weak instruments. <em>Econometrica</em>, 65(3), 557–586.</p></li>
<li><p>Stock, J. H., &amp; Yogo, M. (2005). Testing for weak instruments in linear IV regression. In D. W. K. Andrews &amp; J. H. Stock (Eds.), <em>Identification and Inference for Econometric Models</em> (pp.&nbsp;80–108). Cambridge University Press.</p></li>
<li><p>Young, A. (2022). Consistency without inference: Instrumental variables in practical application. <em>European Economic Review</em>, 147, 104112.</p></li>
</ul>


</section>

 ]]></description>
  <category>causal inference</category>
  <category>statistical inference</category>
  <category>hypothesis testing</category>
  <guid>https://vyasenov.github.io/blog/weak-instruments.html</guid>
  <pubDate>Wed, 24 Jun 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>Always-Valid \(p\)-Values and Online Multiple Testing</title>
  <link>https://vyasenov.github.io/blog/online-multiple-testing.html</link>
  <description><![CDATA[ 





<div class="reading-time">10 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>The classical <img src="https://latex.codecogs.com/png.latex?p">-value is built for a world that modern data science has largely abandoned. That world has two defining features. First, you collect a <em>fixed</em> sample, compute <em>one</em> test statistic, and decide <em>once</em>. Second, when you do test many hypotheses, you have all of them—and all their <img src="https://latex.codecogs.com/png.latex?p">-values—sitting in front of you at the same time, so a procedure like Benjamini–Hochberg can sort them and pick a threshold.</p>
<p>Neither feature survives contact with how experiments actually run today. A major tech company runs tens of thousands of A/B tests a year, each one monitored continuously as data trickle in. A genomics platform tests new gene knockouts as they are discovered, with no idea how many tests there will eventually be. Hypotheses arrive in a <em>stream</em>, and decisions have to be made <em>dynamically</em>.</p>
<p>This breaks classical inference in two distinct places, and the single biggest source of confusion in this area is that people use the word “sequential” for both. I have written before about <a href="https://vyasenov.github.io/blog/recent-dev-fdr.html">false discovery rate control</a> and the <a href="https://vyasenov.github.io/blog/flavors-multiple-testing.html">many flavors of multiple testing adjustments</a>; this post is about what happens to all of that machinery when time enters the picture. My goal is to draw a clean map of the terminology—sequential testing, always-valid <img src="https://latex.codecogs.com/png.latex?p">-values, online multiple testing—and then walk through the algorithms that make the streaming world tractable, following the exposition of Robertson, Wason and Ramdas (2023).</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Hypotheses arrive at times <img src="https://latex.codecogs.com/png.latex?t%20=%201,%202,%20%5Cdots">. At each time <img src="https://latex.codecogs.com/png.latex?t"> we observe a <img src="https://latex.codecogs.com/png.latex?p">-value <img src="https://latex.codecogs.com/png.latex?P_t"> for a null hypothesis <img src="https://latex.codecogs.com/png.latex?H_t"> and must decide whether to reject <img src="https://latex.codecogs.com/png.latex?H_t"> <em>before</em> moving on to <img src="https://latex.codecogs.com/png.latex?t+1">. We assume each <img src="https://latex.codecogs.com/png.latex?P_t"> is a valid <img src="https://latex.codecogs.com/png.latex?p">-value, meaning that whenever <img src="https://latex.codecogs.com/png.latex?H_t"> is true, <img src="https://latex.codecogs.com/png.latex?%0A%5CPr(P_t%20%5Cle%20x)%20%5Cle%20x%20%5Cquad%20%5Ctext%7Bfor%20all%20%7D%20x%20%5Cin%20%5B0,1%5D.%0A"></p>
<p>A testing procedure supplies a sequence of test levels <img src="https://latex.codecogs.com/png.latex?%5Calpha_t"> and rejects via the rule <img src="https://latex.codecogs.com/png.latex?%0AR_t%20=%20%5Cmathbb%7B1%7D%5C%7BP_t%20%5Cle%20%5Calpha_t%5C%7D.%0A"> Crucially, <img src="https://latex.codecogs.com/png.latex?%5Calpha_t"> may depend only on the past decisions <img src="https://latex.codecogs.com/png.latex?R_1,%20%5Cdots,%20R_%7Bt-1%7D"> (or <img src="https://latex.codecogs.com/png.latex?p">-values)—not on the future, and not on the total number of tests, which may be unknown or infinite.</p>
<p>Let <img src="https://latex.codecogs.com/png.latex?%0AR(T)%20=%20%5Csum_%7Bt=1%7D%5E%7BT%7D%20R_t%0A"> be the number of rejections (discoveries) by time <img src="https://latex.codecogs.com/png.latex?T">, and let <img src="https://latex.codecogs.com/png.latex?%0AV(T)%20=%20%5Csum_%7Bt=1%7D%5E%7BT%7D%20R_t%20%5Cmathbb%7B1%7D%5C%7BR_t%20=%201%5C%7D%0A"> be the number of those that are false. Write <img src="https://latex.codecogs.com/png.latex?a%20%5Cvee%20b%20=%20%5Cmax(a,b)">.</p>
<p>For the <em>inner</em> process (repeated monitoring within a single experiment) a richer object is needed. An <em>anytime-valid</em> (or <em>always-valid</em>) <img src="https://latex.codecogs.com/png.latex?p">-value is a <em>sequence</em> <img src="https://latex.codecogs.com/png.latex?(P_%7Bt,n%7D)_%7Bn%20%5Cge%201%7D"> indexed by the within-experiment sample size <img src="https://latex.codecogs.com/png.latex?n">, such that <img src="https://latex.codecogs.com/png.latex?%0A%5CPr(P_%7Bt,N%7D%20%5Cle%20x)%20%5Cle%20x%20%5Cquad%20%5Ctext%7Bfor%20all%20%7D%20x%20%5Cin%20%5B0,1%5D%20%5Ctext%7B%20and%20any%20data-dependent%20stopping%20time%20%7D%20N.%0A"> The phrase “any stopping time” is the whole point: the guarantee holds no matter when (or why) you decide to stop looking.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="three-things-people-call-sequential" class="level3">
<h3 class="anchored" data-anchor-id="three-things-people-call-sequential">Three things people call “sequential”</h3>
<p>Untangling the vocabulary is half the battle, so let me be explicit about three ideas that are routinely conflated.</p>
<p><em>Classical sequential testing</em> concerns a <em>single</em> hypothesis whose data accumulate over time, with the sample size <em>not</em> fixed in advance. Wald’s sequential probability ratio test is the canonical example: keep sampling until the evidence is decisive, then stop. The hard part is that naive optional stopping destroys the type I error guarantee—if you re-test after every new observation and stop the first time you see <img src="https://latex.codecogs.com/png.latex?p%20%5Cle%200.05">, you will eventually cross that line even when the null is true.</p>
<p><em>Always-valid p-values</em> are the modern device that <em>fixes</em> optional stopping. They are the inner process: a single experiment, monitored continuously, with a validity guarantee that survives stopping at any time for any reason.</p>
<p><em>Online multiple testing</em> is a different problem entirely. Here a <em>stream of distinct hypotheses</em> <img src="https://latex.codecogs.com/png.latex?H_1,%20H_2,%20%5Cdots"> arrives over time, each tested once, and the goal is to control a false discovery criterion across the whole stream while deciding each case in real time. This is the outer process.</p>
<p>Robertson, Wason and Ramdas call this the <strong>inner/outer</strong> framing: each monitored experiment emits one valid <img src="https://latex.codecogs.com/png.latex?p">-value, and the outer online-testing procedure controls error rates across the resulting stream.</p>
<hr>
</section>
<section id="always-valid-p-values-the-inner-process" class="level3">
<h3 class="anchored" data-anchor-id="always-valid-p-values-the-inner-process">Always-valid <img src="https://latex.codecogs.com/png.latex?p">-values: the inner process</h3>
<p>Peeking breaks a fixed-<img src="https://latex.codecogs.com/png.latex?n"> <img src="https://latex.codecogs.com/png.latex?p">-value because validity applies to one pre-committed look, not to the event “<img src="https://latex.codecogs.com/png.latex?P_n%20%5Cle%20%5Calpha"> at <em>some</em> point along the way.” Repeated looks turn that into a union of events, whose null probability can be much larger than <img src="https://latex.codecogs.com/png.latex?%5Calpha">.</p>
<p>An always-valid <img src="https://latex.codecogs.com/png.latex?p">-value is constructed precisely so that the union is controlled:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5CPr(P_%7Bt,N%7D%20%5Cle%20x)%20%5Cle%20x%20%5Cquad%20%5Ctext%7Bfor%20all%20%7D%20x%20%5Cin%20%5B0,1%5D%20%5Ctext%7B%20and%20any%20data-dependent%20stopping%20time%20%7D%20N.%0A"></p>
<p>The usual construction runs through martingales and e-values. Ville’s inequality bounds the probability that the evidence process ever crosses a threshold, which gives the optional-stopping guarantee. The confidence-interval analog is a <em>confidence sequence</em>: intervals that cover the true parameter simultaneously at all sample sizes with probability <img src="https://latex.codecogs.com/png.latex?1-%5Calpha">.</p>
<p>The payoff is continuous monitoring with valid inference: you can stop when the evidence is decisive and still control type I error. The cost is conservatism. Under the null, always-valid <img src="https://latex.codecogs.com/png.latex?p">-values are typically stochastically larger than uniform, a fact ADDIS later turns into an advantage.</p>
<hr>
</section>
<section id="error-rates-for-the-outer-process" class="level3">
<h3 class="anchored" data-anchor-id="error-rates-for-the-outer-process">Error rates for the outer process</h3>
<p>Now zoom out to the stream. Which error rate should an online procedure control? The false discovery proportion up to time <img src="https://latex.codecogs.com/png.latex?T"> is <img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BFDP%7D(T)%20=%20%5Cfrac%7BV(T)%7D%7BR(T)%20%5Cvee%201%7D,%0A"></p>
<p>and the headline quantity, the false discovery rate, is its expectation, <img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BFDR%7D(T)%20=%20%5Cmathbb%7BE%7D%5B%5Cmathrm%7BFDP%7D(T)%5D.%0A"></p>
<p>The FDR is the right default for most applied work: it has a long track record in genetics, an intuitive reading as the expected share of discoveries that are wrong, and it scales gracefully to large streams.</p>
<p>Two variants show up constantly. The marginal FDR, <img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BmFDR%7D(T)%20=%20%5Cmathbb%7BE%7D%5BV(T)%5D%20/%20%5Cmathbb%7BE%7D%5BR(T)%20%5Cvee%201%5D,%0A"> replaces the expectation of a ratio with a ratio of expectations. It is not identical to the FDR, but it is far more tractable, and many online algorithms can only be <em>proven</em> to control the mFDR. Treat it as a pragmatic stand-in when an FDR proof is unavailable for your setting. The false discovery exceedance goes the other way and controls a tail: <img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BFDX%7D_%5Cepsilon(T)%20=%20%5CPr(%5Csup_%7Bt%20%5Cle%20T%7D%20%5Cmathrm%7BFDP%7D(t)%20%5Cge%20%5Cepsilon).%0A"> This is the right tool when the FDP can swing far from its mean—few hypotheses, or heavy dependence—and you want a guarantee about the realized proportion, not just its average. Finally, the familywise error rate, <img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BFWER%7D(T)%20=%20%5CPr(V(T)%20%5Cge%201),%0A"> the probability of <em>any</em> false rejection, remains the standard in confirmatory clinical trials where regulators demand it.</p>
<p>The defining constraint of the online setting is informational: when deciding on <img src="https://latex.codecogs.com/png.latex?H_t">, you know only the past rejections, not the future and not even the eventual number of tests. The crudest response is alpha-spending—a Bonferroni-type split with <img src="https://latex.codecogs.com/png.latex?%5Csum_%7Bt=1%7D%5E%7B%5Cinfty%7D%20%5Calpha_t%20=%20%5Calpha">. It controls the FWER, and hence the FDR, but at a ruinous price: the levels <img src="https://latex.codecogs.com/png.latex?%5Calpha_t"> must shrink toward zero, so the power to reject <img src="https://latex.codecogs.com/png.latex?H_t"> collapses as <img src="https://latex.codecogs.com/png.latex?t"> grows. A procedure that becomes blind to discoveries simply because they arrive late is not viable. This is what motivates everything that follows.</p>
<hr>
</section>
<section id="alpha-investing" class="level3">
<h3 class="anchored" data-anchor-id="alpha-investing">Alpha-investing</h3>
<p>The breakthrough idea, originating with Foster and Stine (2008) and generalized by Aharoni and Rosset (2014), reframes testing as the management of an error budget called alpha-wealth. You start with wealth <img src="https://latex.codecogs.com/png.latex?W(0)%20=%20w_0%20%5Cle%20%5Calpha">. Testing a hypothesis <em>costs</em> you some wealth <img src="https://latex.codecogs.com/png.latex?%5Cphi_t">—an investment. Making a discovery <em>pays you back</em> a reward <img src="https://latex.codecogs.com/png.latex?%5Cvarphi_t">. The wealth evolves as <img src="https://latex.codecogs.com/png.latex?%0AW(t)%20=%20W(t-1)%20-%20%5Cphi_t%20+%20R_t%20%5Cvarphi_t,%0A"> and must stay nonnegative, which constrains how aggressively you can test (<img src="https://latex.codecogs.com/png.latex?%5Cphi_t%20%5Cle%20W(t-1)">).</p>
<p>The intuition for why a <em>reward</em> on rejection is legitimate—rather than a cheat—is worth internalizing. Look back at <img src="https://latex.codecogs.com/png.latex?%0A%5Cmathrm%7BFDP%7D(T)%20=%20V(T)%20/%20(R(T)%20%5Cvee%201).%0A"></p>
<p>Each genuine rejection enlarges the denominator of the FDP, buying room for continued testing without the power collapse of alpha-spending. This family is known as generalized alpha-investing (GAI); GAI++ (Ramdas et al., 2017) refines the rewards to guarantee FDR control, whereas earlier rules controlled only the mFDR.</p>
<hr>
</section>
<section id="lord-saffron-addis" class="level3">
<h3 class="anchored" data-anchor-id="lord-saffron-addis">LORD, SAFFRON, ADDIS</h3>
<p>The wealth metaphor is intuitive but it was a “statistical” reframing by Ramdas et al.&nbsp;(2017) that produced the algorithms practitioners actually use. The idea is to maintain a running <em>overestimate</em> of the FDP and spend wealth to keep that estimate below <img src="https://latex.codecogs.com/png.latex?%5Calpha">—exactly the logic that powers Benjamini–Hochberg offline.</p>
<p>LORD (Javanmard and Montanari, 2018), and its uniform improvement LORD++, set each test level <img src="https://latex.codecogs.com/png.latex?%5Calpha_t"> from a fixed, non-increasing sequence <img src="https://latex.codecogs.com/png.latex?%5C%7B%5Cgamma_i%5C%7D"> that sums to one, allocating a slice of the initial wealth plus a slice of the reward earned at each past rejection <img src="https://latex.codecogs.com/png.latex?%5Ctau_j">: <img src="https://latex.codecogs.com/png.latex?%0A%5Calpha_t%20=%20w_0%20%5Cgamma_t%20+%20(%5Calpha%20-%20w_0)%5C,%5Cgamma_%7Bt-%5Ctau_1%7D%5Cmathbb%7B1%7D%5C%7B%5Ctau_1%20%3C%20t%5C%7D%20+%20%5Calpha%20%5C!%5C!%5Csum_%7Bj:%5C,%5Ctau_j%20%3C%20t,%5C,%20%5Ctau_j%20%5Cne%20%5Ctau_1%7D%5C!%5C!%20%5Cgamma_%7Bt%20-%20%5Ctau_j%7D.%0A"> Daunting at a glance, but readable: the first term spends a fraction of the starting budget, and every prior rejection injects fresh budget that is then doled out over future tests on the same schedule <img src="https://latex.codecogs.com/png.latex?%5C%7B%5Cgamma_i%5C%7D">. LORD++ never spends more than it has earned, which is exactly why it keeps the FDP estimate below <img src="https://latex.codecogs.com/png.latex?%5Calpha">. It is best understood as the online analog of Benjamini–Hochberg, and under independence (more precisely, when the null <img src="https://latex.codecogs.com/png.latex?p">-values are <em>conditionally super-uniform</em>) it controls the FDR; Chen and Arias-Castro (2021) further show it is asymptotically as powerful as BH in a Gaussian model.</p>
<p>SAFFRON (Ramdas et al., 2018) makes LORD++ <em>adaptive</em>. It picks a threshold <img src="https://latex.codecogs.com/png.latex?%5Clambda"> and refuses to spend wealth on “candidate” <img src="https://latex.codecogs.com/png.latex?p">-values larger than <img src="https://latex.codecogs.com/png.latex?%5Clambda">—since a large <img src="https://latex.codecogs.com/png.latex?p">-value was never going to be rejected anyway, why pay to test it? By estimating the proportion of true nulls and conserving wealth accordingly, SAFFRON delivers more power than LORD++ whenever a meaningful fraction of hypotheses are non-null with strong signals.</p>
<p>ADDIS (Tian and Ramdas, 2019) adds <em>discarding</em> on top of adaptivity. It explicitly throws away the most conservative nulls—the largest <img src="https://latex.codecogs.com/png.latex?p">-values—before testing. Here is where the earlier observation pays off: always-valid <img src="https://latex.codecogs.com/png.latex?p">-values are <em>conservative under the null</em>. A procedure that exploits conservative nulls is therefore a natural partner for an inner process built on continuous monitoring. The two layers of the inner/outer framing don’t just compose—they reinforce each other.</p>
<hr>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>“Sequential” hides three ideas: classical sequential testing (one hypothesis, growing sample), always-valid <img src="https://latex.codecogs.com/png.latex?p">-values (rigorous optional stopping), and online multiple testing (error control across a stream).</li>
<li>The inner/outer framing composes them: an always-valid test <em>inside</em> each experiment, an online-FDR algorithm <em>across</em> them, and the guarantees stack.</li>
<li>Always-valid <img src="https://latex.codecogs.com/png.latex?p">-values and confidence sequences make continuous A/B-test monitoring legitimate — at the price of conservatism under the null.</li>
<li>For the stream, default to FDR, fall back to mFDR when no FDR proof exists, and use FDX when the FDP can swing far from its mean; avoid alpha-spending, whose power decays to zero.</li>
<li>Among algorithms: LORD++ is the safe default (online BH), SAFFRON adds adaptivity for power, and ADDIS adds discarding that pairs well with conservative <img src="https://latex.codecogs.com/png.latex?p">-values.</li>
</ul>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Aharoni, E., and Rosset, S. (2014). Generalized <img src="https://latex.codecogs.com/png.latex?%5Calpha">-investing: definitions, optimality results and application to public databases. <em>Journal of the Royal Statistical Society: Series B</em>, 76(4), 771–794.</p>
<p>Chen, S., and Arias-Castro, E. (2021). On the power of some sequential multiple testing procedures. <em>Annals of the Institute of Statistical Mathematics</em>, 73(2), 311–336.</p>
<p>Foster, D. P., and Stine, R. A. (2008). <img src="https://latex.codecogs.com/png.latex?%5Calpha">-investing: a procedure for sequential control of expected false discoveries. <em>Journal of the Royal Statistical Society: Series B</em>, 70(2), 429–444.</p>
<p>Howard, S. R., Ramdas, A., McAuliffe, J., and Sekhon, J. (2021). Time-uniform, nonparametric, nonasymptotic confidence sequences. <em>Annals of Statistics</em>, 49(2), 1055–1080.</p>
<p>Javanmard, A., and Montanari, A. (2018). Online rules for control of false discovery rate and false discovery exceedance. <em>Annals of Statistics</em>, 46(2), 526–554.</p>
<p>Johari, R., Koomen, P., Pekelis, L., and Walsh, D. (2021). Always valid inference: continuous monitoring of A/B tests. <em>Operations Research</em>, 70(3), 1806–1821.</p>
<p>Ramdas, A., Yang, F., Wainwright, M. J., and Jordan, M. I. (2017). Online control of the false discovery rate with decaying memory. <em>Advances in Neural Information Processing Systems</em>, 30.</p>
<p>Ramdas, A., Zrnic, T., Wainwright, M., and Jordan, M. (2018). SAFFRON: an adaptive algorithm for online control of the false discovery rate. <em>Proceedings of the 35th International Conference on Machine Learning</em>, 4286–4294.</p>
<p>Robertson, D. S., Wason, J. M. S., and Ramdas, A. (2023). Online multiple hypothesis testing. <em>Statistical Science</em>, 38(4), 557–575.</p>
<p>Tian, J., and Ramdas, A. (2019). ADDIS: an adaptive discarding algorithm for online FDR control with conservative nulls. <em>Advances in Neural Information Processing Systems</em>, 32.</p>


</section>

 ]]></description>
  <category>multiple testing</category>
  <category>hypothesis testing</category>
  <category>statistical inference</category>
  <guid>https://vyasenov.github.io/blog/online-multiple-testing.html</guid>
  <pubDate>Wed, 24 Jun 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>Linear Models and \(p &gt; n\): What Can You Do?</title>
  <link>https://vyasenov.github.io/blog/linear-models-p-over-n.html</link>
  <description><![CDATA[ 





<div class="reading-time">6 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>It seems intuitive that you cannot fit a regression with more predictors than observations. With <img src="https://latex.codecogs.com/png.latex?p"> parameters and only <img src="https://latex.codecogs.com/png.latex?n%20%3C%20p"> data points, the reasoning goes, you have more unknowns than equations, the system is underdetermined, and the whole enterprise collapses. Geneticists know this well.</p>
<p>This intuition is half right. It is true that when <img src="https://latex.codecogs.com/png.latex?p%20%3E%20n"> you cannot recover the coefficient vector <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> — not even in principle, not with infinite sample or computing power. But it does not follow that the model is useless. The thing you usually <em>care</em> about — the prediction <img src="https://latex.codecogs.com/png.latex?X%5Cbeta"> — can be perfectly well-defined even when <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> itself is hopelessly ambiguous. Coefficients that are individually unknowable can combine into a quantity that is pinned down exactly. I find this one of the more beautiful facts in linear-model theory, and it sits at the heart of a recent expository paper by Ronald Christensen (2026).</p>
<p>I will spend most of the post on <em>why</em> <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> is non-identifiable and what survives anyway, then briefly sketch the menu of estimators people actually reach for in this regime, and what “prediction” even means when half the parameter space is invisible to the data.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Start with the standard linear model</p>
<p><img src="https://latex.codecogs.com/png.latex?Y%20=%20X%5Cbeta%20+%20e,%20%5Cqquad%20%5Cmathbb%7BE%7D(e)%20=%200,%20%5Cqquad%20%5Ctext%7Bcov%7D(e)%20=%20%5Csigma%5E2%20I_n,"></p>
<p>where</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?Y"> is an <img src="https://latex.codecogs.com/png.latex?n">-vector of outcomes,</li>
<li><img src="https://latex.codecogs.com/png.latex?X"> is a known <img src="https://latex.codecogs.com/png.latex?n%20%5Ctimes%20p"> design matrix,</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Cbeta"> is the <img src="https://latex.codecogs.com/png.latex?p">-vector of unknown coefficients, and</li>
<li><img src="https://latex.codecogs.com/png.latex?e"> is mean-zero noise.</li>
</ul>
<p>The case of interest is <img src="https://latex.codecogs.com/png.latex?p%20%3E%20n">, which forces the rank of <img src="https://latex.codecogs.com/png.latex?X"> to satisfy <img src="https://latex.codecogs.com/png.latex?r(X)%20%5Cle%20n%20%3C%20p">. Two subspaces do all the work.</p>
<ul>
<li>The <em>column space</em> <img src="https://latex.codecogs.com/png.latex?C(X)%20%5Csubseteq%20%5Cmathbb%7BR%7D%5En"> is the set of all fitted-value vectors <img src="https://latex.codecogs.com/png.latex?X%5Cbeta"> the model can produce.</li>
<li>The <em>row space</em> <img src="https://latex.codecogs.com/png.latex?C(X')%20%5Csubseteq%20%5Cmathbb%7BR%7D%5Ep"> is the span of the rows of <img src="https://latex.codecogs.com/png.latex?X"> — the directions in coefficient space that the data actually “see.”</li>
</ul>
<p>Let <img src="https://latex.codecogs.com/png.latex?N"> denote the (orthogonal) projection onto the row space <img src="https://latex.codecogs.com/png.latex?C(X')">, so that any coefficient vector splits cleanly into</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbeta%20=%20%5Cunderbrace%7BN%5Cbeta%7D_%7B%5Ctext%7Bin%20the%20row%20space%7D%7D%20+%20%5Cunderbrace%7B(I%20-%20N)%5Cbeta%7D_%7B%5Ctext%7Borthogonal%20to%20it%7D%7D."></p>
<p>That decomposition is the whole story, so it is worth keeping in view.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="why-beta-cannot-be-identified" class="level3">
<h3 class="anchored" data-anchor-id="why-beta-cannot-be-identified">Why <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> cannot be identified</h3>
<p>Here is the crux. Every row of <img src="https://latex.codecogs.com/png.latex?X"> lives in <img src="https://latex.codecogs.com/png.latex?C(X')"> by definition, which means <img src="https://latex.codecogs.com/png.latex?X"> annihilates anything orthogonal to the row space: <img src="https://latex.codecogs.com/png.latex?X(I%20-%20N)%20=%200">. Multiply the model through and the consequence is immediate —</p>
<p><img src="https://latex.codecogs.com/png.latex?X%5Cbeta%20=%20X%5Cbig(N%5Cbeta%20+%20(I-N)%5Cbeta%5Cbig)%20=%20X%20N%5Cbeta."></p>
<p>The component <img src="https://latex.codecogs.com/png.latex?(I%20-%20N)%5Cbeta"> contributes <em>nothing</em> to <img src="https://latex.codecogs.com/png.latex?X%5Cbeta">, and therefore nothing to <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D(Y)">. The data are generated by <img src="https://latex.codecogs.com/png.latex?N%5Cbeta"> alone. Whatever value <img src="https://latex.codecogs.com/png.latex?(I-N)%5Cbeta"> takes — zero, enormous, anything — the distribution of <img src="https://latex.codecogs.com/png.latex?Y"> is exactly the same. No estimator can distinguish between two coefficient vectors that agree on their row-space part and differ off it, because they produce statistically identical data.</p>
<p>When <img src="https://latex.codecogs.com/png.latex?p%20%5Cle%20n"> and <img src="https://latex.codecogs.com/png.latex?X"> has full column rank, the row space is all of <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5Ep">, the projection <img src="https://latex.codecogs.com/png.latex?N"> is the identity, <img src="https://latex.codecogs.com/png.latex?(I-N)%5Cbeta"> vanishes, and this issue never arises — which is why we rarely think about it. But the moment <img src="https://latex.codecogs.com/png.latex?p%20%3E%20n">, the row space is a <em>proper</em> subspace of <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BR%7D%5Ep">, the orthogonal complement is non-trivial, and a whole <img src="https://latex.codecogs.com/png.latex?(p%20-%20r)">-dimensional flat of coefficient vectors fits the data equally well. That is non-identifiability, stated geometrically: <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> is unknowable precisely along the directions the design never probes.</p>
<hr>
</section>
<section id="non-unique-coefficients-unique-predictions" class="level3">
<h3 class="anchored" data-anchor-id="non-unique-coefficients-unique-predictions">Non-unique coefficients, unique predictions</h3>
<p>Now the payoff. The fitted-value vector is</p>
<p><img src="https://latex.codecogs.com/png.latex?X%5Chat%5Cbeta%20=%20X%20N%5Chat%5Cbeta,"></p>
<p>and this object is <strong>unique</strong> even though <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> is not. Geometrically, fitting projects <img src="https://latex.codecogs.com/png.latex?Y"> onto the column space <img src="https://latex.codecogs.com/png.latex?C(X)">; that projection is a single, well-defined point regardless of which of the infinitely many least-squares solutions you happened to compute. The same is true of the row-space part of the coefficients: <img src="https://latex.codecogs.com/png.latex?N%5Cbeta"> is identifiable and estimable, while <img src="https://latex.codecogs.com/png.latex?(I%20-%20N)%5Cbeta"> is not. So the situation is not “everything is lost,” but rather a clean partition — the row-space shadow of <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> is recoverable, its orthogonal complement is forever hidden, and <em>predictions live entirely in the recoverable part</em>.</p>
<p>This is why high-dimensional regression is not the doomed exercise the equation-counting heuristic suggests. The coefficients are a fiction the data cannot fully resolve, but the model’s predictions are perfectly real. It is also a useful corrective to a habit many of us have — reading individual coefficients as if they meant something. With <img src="https://latex.codecogs.com/png.latex?p%20%3E%20n">, an individual <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_j"> is whatever your estimator’s tie-breaking rule decided to make it; only its projection onto the row space carries information. (This tension between estimating coefficients and estimating predictions shows up even in well-posed problems; I have written about it in <a href="https://vyasenov.github.io/blog/diff-causal-predictive-models.html">the difference between causal and predictive models</a>.)</p>
<hr>
</section>
<section id="four-ways-to-pick-a-beta" class="level3">
<h3 class="anchored" data-anchor-id="four-ways-to-pick-a-beta">Four ways to pick a <img src="https://latex.codecogs.com/png.latex?%5Cbeta"></h3>
<p>If infinitely many coefficient vectors fit, every estimator is really a <em>rule for choosing one</em> — equivalently, a rule for deciding what to do off the row space, where the data are silent. Christensen lays out four that practitioners actually use, and the unifying thread is that they are all functions of the ordinary least-squares fit; they differ only in how they pin down the ambiguous directions.</p>
<ol type="1">
<li><p><strong>Minimum-norm least squares.</strong> Among all least-squares solutions, take the one with the smallest <img src="https://latex.codecogs.com/png.latex?%5C%7C%5Cbeta%5C%7C">. This is exactly <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta_m%20=%20N%5Chat%5Cbeta"> — the solution that sets the orthogonal component to zero and lives entirely in the row space <img src="https://latex.codecogs.com/png.latex?C(X')">. It is unique, it is what gradient descent from the origin converges to, and it is the natural reference point for the others.</p></li>
<li><p><strong>Penalized (regularized) least squares.</strong> Minimize <img src="https://latex.codecogs.com/png.latex?%5C%7CY%20-%20X%5Cbeta%5C%7C%5E2%20+%20%5Clambda%5C,%20%5Cmathcal%7BP%7D(%5Cbeta)"> for a penalty <img src="https://latex.codecogs.com/png.latex?%5Cmathcal%7BP%7D"> — ridge (<img src="https://latex.codecogs.com/png.latex?%5Cell_2">), <a href="https://vyasenov.github.io/blog/flavors-lasso.html">the LASSO</a> (<img src="https://latex.codecogs.com/png.latex?%5Cell_1">), elastic net, and so on. The penalty breaks the tie by preferring small or sparse coefficients, which generally makes the estimate unique.</p></li>
<li><p><strong>Spectral shrinkage.</strong> Working from the singular value decomposition of <img src="https://latex.codecogs.com/png.latex?X'X">, shrink the components of the fit associated with each eigen-direction by a chosen factor. Ridge regression is the canonical special case (it shrinks the direction with eigenvalue <img src="https://latex.codecogs.com/png.latex?s"> by <img src="https://latex.codecogs.com/png.latex?s/(s%20+%20%5Clambda)">), and as <img src="https://latex.codecogs.com/png.latex?%5Clambda%20%5Cto%200"> ridge converges to the minimum-norm solution.</p></li>
<li><p><strong>Principal component regression.</strong> Keep only the leading <a href="https://vyasenov.github.io/blog/flavors-pca.html">principal components</a> of <img src="https://latex.codecogs.com/png.latex?X"> and regress on those, discarding the low-variance directions entirely. This is a hard-thresholding cousin of spectral shrinkage — zero weight below the cutoff, full weight above.</p></li>
</ol>
<p>The differences among them are real but secondary to the shared structure: each one estimates the identifiable part <img src="https://latex.codecogs.com/png.latex?N%5Cbeta"> from the data and then imposes some discipline on the unidentifiable part. For the theory behind when these choices recover the truth, see my post on <a href="https://vyasenov.github.io/blog/lasso-theory-guarantees.html">the LASSO’s theoretical guarantees</a>.</p>
<hr>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>With <img src="https://latex.codecogs.com/png.latex?p%20%3E%20n">, the coefficient vector <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> is <em>not identifiable</em> — the design only sees its projection <img src="https://latex.codecogs.com/png.latex?N%5Cbeta"> onto the row space, and the orthogonal part <img src="https://latex.codecogs.com/png.latex?(I-N)%5Cbeta"> is invisible to the data and to any prior.</li>
<li>Yet the fitted values <img src="https://latex.codecogs.com/png.latex?X%5Chat%5Cbeta"> and the row-space part <img src="https://latex.codecogs.com/png.latex?N%5Cbeta"> are <em>unique and estimable</em>. Non-unique coefficients, unique predictions: that is the central fact, and it is what keeps high-dimensional regression alive.</li>
<li>Every estimator is a rule for choosing among the infinitely many fits, agreeing on <img src="https://latex.codecogs.com/png.latex?N%5Cbeta"> and differing only off the row space.</li>
</ul>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<ul>
<li><p>Christensen, R. (2026). Linear Model Estimation and Prediction for <img src="https://latex.codecogs.com/png.latex?p%20%3E%20n">. <em>The American Statistician</em>, 80(2), 232–240.</p></li>
<li><p>Hastie, T., Tibshirani, R., &amp; Friedman, J. (2009). <em>The Elements of Statistical Learning</em> (2nd ed.). New York: Springer.</p></li>
</ul>


</section>

 ]]></description>
  <category>parametric models</category>
  <category>statistical inference</category>
  <category>machine learning</category>
  <guid>https://vyasenov.github.io/blog/linear-models-p-over-n.html</guid>
  <pubDate>Mon, 22 Jun 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>A Simple Estimation Recipe for Targeted Learning</title>
  <link>https://vyasenov.github.io/blog/tmle-estimation-recipe.html</link>
  <description><![CDATA[ 





<div class="reading-time">6 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Targeted learning is extremely popular in public health and epidemiology, yet it has never really made its way into the economics and econometrics world. It was introduced and extended by Mark van der Laan and coauthors in a long series of papers and books.The targeted learning class of methods enjoys very attractive theoretical properties. It is doubly robust and, under the right conditions, semiparametrically efficient, and it is method-agnostic in that it can plug in a wide range of machine learning algorithms.</p>
<p>This note aims to demystify targeted learning for a broader audience. From a practical standpoint, I find the best way to do that is through the lens of <em>estimation</em>, since that is where practitioners actually spend their time with a method. It is also the easiest way to compare it against the causal inference tools you already know — be it <a href="https://vyasenov.github.io/blog/flavors-prop-score-methods.html">propensity score methods</a>, double machine learning, or <a href="https://vyasenov.github.io/blog/ml-based-adjustments.html">regression adjustment</a>.</p>
<p>My focus is on the how-to and less on theoretical derivations or guarantees, and the overview borrows heavily from Schuler and Rose (2017). I deliberately stay with the <em>basic</em> version of targeted learning — targeted maximum likelihood estimation (TMLE) for the average treatment effect in a cross-sectional observational study. The framework extends to many other estimands, longitudinal data, and beyond, but those are out of scope here.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Suppose we observe <img src="https://latex.codecogs.com/png.latex?n"> i.i.d. draws of <img src="https://latex.codecogs.com/png.latex?O%20=%20(X,%20A,%20Y)">, where:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?A%20%5Cin%20%5C%7B0,%201%5C%7D"> is a binary treatment (the “exposure”),</li>
<li><img src="https://latex.codecogs.com/png.latex?X"> is a vector of confounders, and</li>
<li><img src="https://latex.codecogs.com/png.latex?Y"> is a continuous outcome.</li>
</ul>
<p>Each unit has a pair of potential outcomes <img src="https://latex.codecogs.com/png.latex?Y(1)"> and <img src="https://latex.codecogs.com/png.latex?Y(0)">, and the target is the average treatment effect (ATE),</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cpsi%20=%20%5Cmathbb%7BE%7D%5Cbig%5BY(1)%20-%20Y(0)%5Cbig%5D."></p>
<p>Two nuisance functions do all the work. The <em>outcome regression</em> is the conditional mean of the outcome,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbar%7BQ%7D(A,%20X)%20=%20%5Cmathbb%7BE%7D%5BY%20%5Cmid%20A,%20X%5D,"></p>
<p>and the <em>propensity score</em> is the conditional probability of treatment,</p>
<p><img src="https://latex.codecogs.com/png.latex?g(X)%20=%20%5Cmathbb%7BP%7D(A%20=%201%20%5Cmid%20X)."></p>
<p>For <img src="https://latex.codecogs.com/png.latex?%5Cpsi"> to carry a causal interpretation we need the usual trio of assumptions — no unmeasured confounding, positivity (<img src="https://latex.codecogs.com/png.latex?0%20%3C%20g(X)%20%3C%201">), and SUTVA — which I will take as given since the focus here is estimation, not identification.</p>
<p>A concrete example to fix ideas, taken from the paper: <img src="https://latex.codecogs.com/png.latex?A"> is whether a person exercises regularly, <img src="https://latex.codecogs.com/png.latex?Y"> is a depression score, and <img src="https://latex.codecogs.com/png.latex?X"> collects sex, use of psychosocial therapy, and antidepressant use.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="two-nuisances-three-estimators" class="level3">
<h3 class="anchored" data-anchor-id="two-nuisances-three-estimators">Two Nuisances, Three Estimators</h3>
<p>The reason TMLE is easy to place on a mental map is that it shares its ingredients with methods you already use. <a href="https://vyasenov.github.io/blog/ml-based-adjustments.html">G-computation</a> (regression adjustment) models only the outcome regression <img src="https://latex.codecogs.com/png.latex?%5Cbar%7BQ%7D"> and then averages the predicted difference. Inverse probability weighting (IPW) models only the propensity score <img src="https://latex.codecogs.com/png.latex?g"> and reweights the observed outcomes. Each leans entirely on getting <em>one</em> of the two nuisances right.</p>
<p>TMLE uses <em>both</em>. It starts from an outcome-regression prediction and then nudges it using the propensity score, in a way designed specifically for the ATE. That extra step is what buys <em>double robustness</em>: the final estimate is consistent if <em>either</em> <img src="https://latex.codecogs.com/png.latex?%5Cbar%7BQ%7D"> or <img src="https://latex.codecogs.com/png.latex?g"> is correctly estimated, not necessarily both. If both are consistent, the estimator is also efficient. This is the practical payoff, and it is why the method is worth the extra bookkeeping.</p>
<hr>
</section>
<section id="the-recipe-four-steps" class="level3">
<h3 class="anchored" data-anchor-id="the-recipe-four-steps">The Recipe: Four Steps</h3>
<p>Here is the whole procedure for the ATE, stripped to its essentials. One technical preliminary: because the targeting step runs through a logistic regression, the continuous outcome <img src="https://latex.codecogs.com/png.latex?Y"> is first rescaled to the unit interval <img src="https://latex.codecogs.com/png.latex?(0,%201)">, and everything is undone at the end.</p>
<div class="callout callout-style-default callout-note callout-titled" title="Algorithm: TMLE for the ATE">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>Algorithm: TMLE for the ATE
</div>
</div>
<div class="callout-body-container callout-body">
<ol type="1">
<li><strong>Initial outcome model.</strong> Fit <img src="https://latex.codecogs.com/png.latex?%5Cbar%7BQ%7D(A,%20X)"> and use it to predict each unit’s pair of potential outcomes, <img src="https://latex.codecogs.com/png.latex?%5Cbar%7BQ%7D(1,%20X_i)"> and <img src="https://latex.codecogs.com/png.latex?%5Cbar%7BQ%7D(0,%20X_i)">.</li>
<li><strong>Propensity model.</strong> Fit <img src="https://latex.codecogs.com/png.latex?g(X)%20=%20%5Cmathbb%7BP%7D(A%20=%201%20%5Cmid%20X)">, giving <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Cpi%7D_1%20=%20%5Chat%20g(X_i)"> and <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Cpi%7D_0%20=%201%20-%20%5Chat%20g(X_i)">.</li>
<li><strong>Targeting step.</strong> Form the “clever covariate” <img src="https://latex.codecogs.com/png.latex?H(A,%20X)%20=%20%5Cfrac%7BA%7D%7B%5Chat%7B%5Cpi%7D_1%7D%20-%20%5Cfrac%7B1%20-%20A%7D%7B%5Chat%7B%5Cpi%7D_0%7D">, run a one-parameter logistic regression of <img src="https://latex.codecogs.com/png.latex?Y"> on <img src="https://latex.codecogs.com/png.latex?H"> using the initial <img src="https://latex.codecogs.com/png.latex?%5Cbar%7BQ%7D"> as an offset to estimate a fluctuation <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Cvarepsilon%7D">, and update the predicted potential outcomes on the logit scale.</li>
<li><strong>Plug-in estimate.</strong> Average the difference between the <em>updated</em> potential outcomes: <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Cpsi%7D%20=%20%5Cfrac%7B1%7D%7Bn%7D%5Csum_i%20%5Cbig%5B%5Cbar%7BQ%7D%5E*(1,%20X_i)%20-%20%5Cbar%7BQ%7D%5E*(0,%20X_i)%5Cbig%5D">.</li>
</ol>
</div>
</div>
<p>The only genuinely new object is the clever covariate <img src="https://latex.codecogs.com/png.latex?H">. Note that it looks a lot like an inverse-probability weight — and that is no accident — but here it enters as a <em>regressor</em> in the fluctuation rather than as a weight. Step 3 is the “targeting”: it tilts the initial fit just enough to remove first-order bias in the direction that matters for the ATE, while leaving the rest of the outcome model alone.</p>
<hr>
</section>
<section id="why-bother-with-the-targeting-step" class="level3">
<h3 class="anchored" data-anchor-id="why-bother-with-the-targeting-step">Why Bother With the Targeting Step?</h3>
<p>A fair question is why we do not simply stop after step 1 and report the average difference in predicted outcomes — that is exactly G-computation. The answer is robustness. A plain outcome-model plug-in is only as good as that one model; if it is misspecified, the estimate is biased, full stop. The targeting step injects information from the propensity score so that a mistake in <em>one</em> of the two models can be absorbed by the other. In the paper’s simulation, when either the outcome or the exposure model is deliberately misspecified, TMLE stays essentially unbiased, while G-computation and IPW pick up large bias from the same misspecification.</p>
<p>Two practical notes follow from this. First, TMLE is a <em>substitution</em> (plug-in) estimator — the ATE is computed by plugging fitted values into the target functional — which makes it more stable than estimating-equation methods like IPW when propensity scores get close to <img src="https://latex.codecogs.com/png.latex?0"> or <img src="https://latex.codecogs.com/png.latex?1">. Second, because the recipe never cares <em>how</em> <img src="https://latex.codecogs.com/png.latex?%5Cbar%7BQ%7D"> and <img src="https://latex.codecogs.com/png.latex?g"> are estimated, you should estimate them with flexible machine learning rather than hand-specified regressions. In practice this means an ensemble (the super learner), which lets the data choose among <a href="https://vyasenov.github.io/blog/flavors-ml-methods-ci.html">a library of ML methods</a> instead of betting on one functional form.</p>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>Targeted maximum likelihood estimation is a very popular class of methods in the public health and epidemiology communities, and underused elsewhere.</li>
<li>It is doubly robust — consistent if <em>either</em> the outcome regression or the propensity score is right — and semiparametrically efficient when both are.</li>
<li>It is flexible: the recipe is agnostic to how the two nuisance functions are estimated, so it accommodates a wide range of machine learning algorithms (ideally an ensemble).</li>
<li>In essence, TMLE is outcome-regression plus propensity-score modeling, with one extra step that removes bias from the outcome model through a clever use of the estimated propensity score.</li>
</ul>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<ul>
<li><p>Schuler, M. S., &amp; Rose, S. (2017). Targeted maximum likelihood estimation for causal inference in observational studies. <em>American Journal of Epidemiology</em>, 185(1), 65–73.</p></li>
<li><p>van der Laan, M. J., &amp; Rose, S. (2011). <em>Targeted Learning: Causal Inference for Observational and Experimental Data</em>. Springer.</p></li>
<li><p>van der Laan, M. J., &amp; Rubin, D. (2006). Targeted maximum likelihood learning. <em>The International Journal of Biostatistics</em>, 2(1), Article 11.</p></li>
</ul>


</section>

 ]]></description>
  <category>causal inference</category>
  <category>machine learning</category>
  <guid>https://vyasenov.github.io/blog/tmle-estimation-recipe.html</guid>
  <pubDate>Fri, 12 Jun 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>The Role of Instrumental Variables in Randomized Experiments</title>
  <link>https://vyasenov.github.io/blog/iv-randomized-experiments.html</link>
  <description><![CDATA[ 





<div class="reading-time">6 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Instrumental variables (IV) are econometricians’ pride. They underpin a great many scientific findings, and even the Nobel committee in Stockholm seems fond of them, judging by the laureates it picks. Yet their prominence outside academia is limited, and so I have not featured them on this blog as often as their importance warrants. Today I change that.</p>
<p>My goal here is to give an overview of how one can use instrumental variables <em>inside</em> randomized experiments. The material draws on the recent NEJM survey by Angrist, Gao, Hull, and Yeh (2025), which makes the case for IV methods in clinical trials. I keep the mathematical rigor to a minimum and shine the spotlight on the practical side of the ideas. A caveat worth stating up front: IVs are arguably even more powerful in the <em>absence</em> of randomization, where they rescue observational studies from confounding — but that is a separate topic for another day.</p>
<p>The setup that motivates everything below is simple and familiar to anyone who has run an experiment: randomized trials often fail to go according to plan. People assigned to treatment do not take it; people assigned to control find a way to get it anyway. IVs offer a principled way to recover causal effects when that happens.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Index participants by <img src="https://latex.codecogs.com/png.latex?i">. Let</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?Y_i"> be the outcome.</li>
<li><img src="https://latex.codecogs.com/png.latex?Z_i%20%5Cin%20%5C%7B0,%201%5C%7D"> denote random <em>assignment</em> to treatment, and</li>
<li><img src="https://latex.codecogs.com/png.latex?T_i%20%5Cin%20%5C%7B0,%201%5C%7D"> denote the treatment actually <em>received</em>.</li>
</ul>
<p>In a clean experiment these coincide, but with noncompliance they need not: a participant can have <img src="https://latex.codecogs.com/png.latex?Z_i%20=%201,%20T_i%20=%200"> (assigned but untreated) or <img src="https://latex.codecogs.com/png.latex?Z_i%20=%200,%20T_i%20=%201"> (a control who crossed over). The instrument is the randomized assignment <img src="https://latex.codecogs.com/png.latex?Z_i">; the endogenous variable is the received treatment <img src="https://latex.codecogs.com/png.latex?T_i">.</p>
<p>Following the potential-outcomes framework, write <img src="https://latex.codecogs.com/png.latex?Y_i(1)"> and <img src="https://latex.codecogs.com/png.latex?Y_i(0)"> for participant <img src="https://latex.codecogs.com/png.latex?i">’s outcome with and without treatment; the individual causal effect is</p>
<p><img src="https://latex.codecogs.com/png.latex?Y_i(1)%20-%20Y_i(0),"></p>
<p>forever unobservable since only one of the two is realized.</p>
<p>Likewise, let <img src="https://latex.codecogs.com/png.latex?T_i(z)"> be the treatment <img src="https://latex.codecogs.com/png.latex?i"> would take under assignment <img src="https://latex.codecogs.com/png.latex?z">. This last object lets us partition the population into four latent types:</p>
<ul>
<li><strong>Compliers</strong> take treatment when assigned and not otherwise: <img src="https://latex.codecogs.com/png.latex?T_i(1)%20=%201,%20T_i(0)%20=%200">.</li>
<li><strong>Always-takers</strong> take treatment regardless: <img src="https://latex.codecogs.com/png.latex?T_i(1)%20=%20T_i(0)%20=%201">.</li>
<li><strong>Never-takers</strong> refuse regardless: <img src="https://latex.codecogs.com/png.latex?T_i(1)%20=%20T_i(0)%20=%200">.</li>
<li><strong>Defiers</strong> do the opposite of their assignment — assumed away below.</li>
</ul>
<p>Three quantities organize the analysis.</p>
<ol type="1">
<li>The <strong>first stage</strong> is the effect of assignment (<img src="https://latex.codecogs.com/png.latex?Z">) on treatment (<img src="https://latex.codecogs.com/png.latex?T">) received, i.e.&nbsp;the difference in treatment rates between the assigned-treatment and assigned-control groups — also called <em>compliance</em>.</li>
<li>The <strong>reduced form</strong> (or intention-to-treat, ITT, effect) is the effect of assignment (<img src="https://latex.codecogs.com/png.latex?Z">) on the outcome (<img src="https://latex.codecogs.com/png.latex?Y">).</li>
<li>The <strong>local average treatment effect</strong> (LATE) is the average causal effect among compliers.</li>
</ol>
<p>The whole framework rests on four assumptions:</p>
<ol type="1">
<li>random assignment of <img src="https://latex.codecogs.com/png.latex?Z_i">;</li>
<li>a <em>first-stage</em> (relevance) condition — assignment must actually move treatment, so compliance is non-zero;</li>
<li><em>monotonicity</em> — assignment never pushes anyone <em>away</em> from treatment, which rules out defiers; and</li>
<li>the <em>exclusion restriction</em> — assignment affects the outcome only through treatment receipt, never directly.</li>
</ol>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="use-case-1-noncompliance" class="level3">
<h3 class="anchored" data-anchor-id="use-case-1-noncompliance">Use Case #1: Noncompliance</h3>
<p>In a trial where everyone complies, <img src="https://latex.codecogs.com/png.latex?T_i%20=%20Z_i">, and the difference in mean outcomes by assignment <em>is</em> the average treatment effect. Noncompliance breaks this.</p>
<p>Suppose treatment effects are constant and equal to <img src="https://latex.codecogs.com/png.latex?%5Cbeta">, so that</p>
<p><img src="https://latex.codecogs.com/png.latex?Y_i%20=%20Y_i(0)%20+%20%5Cbeta%20T_i."></p>
<p>Then a little algebra on the assignment-based comparison gives</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cunderbrace%7B%5Ctext%7BITT%20effect%7D%7D_%7B%5Ctext%7Breduced%20form%7D%7D%20=%20%5Cbeta%20%5Ctimes%20%5Cunderbrace%7B%5Ctext%7BCompliance%7D%7D_%7B%5Ctext%7Bfirst%20stage%7D%7D.%0A"></p>
<p>The intuition is that the ITT effect gets <em>diluted</em>: when only a fraction of those assigned actually take treatment, the assignment-versus-assignment comparison mixes in untreated people on the treatment side and crossovers on the control side, shrinking the apparent effect toward zero. If compliance is, say, <img src="https://latex.codecogs.com/png.latex?0.4">, the ITT understates the true effect by more than half.</p>
<p>The fix falls right out of the identity. Dividing the reduced form by the first stage recovers the effect:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cbeta%20=%20%5Cfrac%7B%5Ctext%7BITT%20effect%7D%7D%7B%5Ctext%7BCompliance%7D%7D%20=%20%5Cfrac%7B%5Ctext%7Breduced%20form%7D%7D%7B%5Ctext%7Bfirst%20stage%7D%7D.%0A"></p>
<p>This ratio of differences in means is the heart of IV analysis — the Wald estimator. When effects are heterogeneous, the LATE theorem (Imbens and Angrist, 1994) tells us this same ratio identifies not some universal <img src="https://latex.codecogs.com/png.latex?%5Cbeta"> but the average effect <em>for compliers</em>:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5Ctext%7BITT%20effect%7D%7D%7B%5Ctext%7BCompliance%7D%7D%20=%20%5Cmathbb%7BE%7D%5Cbig%5BY_i(1)%20-%20Y_i(0)%20%5Cmid%20%5Ctext%7Bcomplier%7D%5Cbig%5D.%0A"></p>
<hr>
</section>
<section id="use-case-2-selection-bias" class="level3">
<h3 class="anchored" data-anchor-id="use-case-2-selection-bias">Use Case #2: Selection Bias</h3>
<p>The second problem IVs solve is subtler, and it is where practitioners most often go wrong. Faced with noncompliance, the tempting move is a <em>per-protocol</em> or <em>as-treated</em> analysis: just compare people by the treatment they actually received, <img src="https://latex.codecogs.com/png.latex?T_i">. The trouble is that <img src="https://latex.codecogs.com/png.latex?T_i"> is not randomized. The people who comply, cross over, or refuse differ systematically, so comparing by treatment received reintroduces exactly the confounding that randomization was designed to eliminate.</p>
<p>The IV approach sidesteps this entirely by comparing groups defined by <em>randomized</em> assignment <img src="https://latex.codecogs.com/png.latex?Z_i">, not by <img src="https://latex.codecogs.com/png.latex?T_i">. The comparison is apples-to-apples — the complier subpopulation on the treated side is statistically identical to the complier subpopulation on the control side, differing only in the luck of the draw. The estimate is a per-protocol effect, but one purged of selection bias. As a bonus, although individual compliers cannot be identified, their average baseline characteristics <em>can</em> be computed, letting the analyst check how representative they are of the broader patient population.</p>
<hr>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>Instrumental variables are ubiquitous in academic econometrics and applied microeconomics; their footprint in industry remains comparatively small.</li>
<li>Randomized experiments do not always go according to plan — noncompliance and crossovers are common in pragmatic and clinical trials.</li>
<li>IVs come to the rescue for two distinct, thorny problems: noncompliance and selection bias.</li>
<li>The price is interpretational: IV identifies the LATE, an effect specific to the compliers induced by the instrument — not necessarily the average effect for the whole population. Whether that is the estimand you want is a question worth asking before you run the regression.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>The two foundational papers are Imbens and Angrist (1994), which introduced the LATE theorem, and Angrist, Imbens, and Rubin (1996), which recast IV estimation in the potential-outcomes language used throughout this note. For a complete and famously readable treatment, Angrist and Pischke’s <em>Mostly Harmless Econometrics</em> (2009) remains the standard reference. The clinical-trials framing here follows Angrist, Gao, Hull, and Yeh (2025), an accessible survey aimed at medical researchers that I recommend to anyone who wants to see these ideas applied end-to-end on a real trial.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<ul>
<li><p>Angrist, J. D., Gao, C., Hull, P., &amp; Yeh, R. W. (2025). Instrumental variables in randomized trials. <em>NEJM Evidence</em>, 4(4).</p></li>
<li><p>Angrist, J. D., Imbens, G. W., &amp; Rubin, D. B. (1996). Identification of causal effects using instrumental variables. <em>Journal of the American Statistical Association</em>, 91(434), 444–455.</p></li>
<li><p>Angrist, J. D., &amp; Pischke, J.-S. (2009). <em>Mostly Harmless Econometrics: An Empiricist’s Companion</em>. Princeton University Press.</p></li>
<li><p>Imbens, G. W., &amp; Angrist, J. D. (1994). Identification and estimation of local average treatment effects. <em>Econometrica</em>, 62(2), 467–475.</p></li>
</ul>


</section>

 ]]></description>
  <category>causal inference</category>
  <category>randomized experiments</category>
  <guid>https://vyasenov.github.io/blog/iv-randomized-experiments.html</guid>
  <pubDate>Thu, 11 Jun 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>Lasso and Its Theoretical Guarantees</title>
  <link>https://vyasenov.github.io/blog/lasso-theory-guarantees.html</link>
  <description><![CDATA[ 





<div class="reading-time">7 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Every data scientist has heard of the Lasso, and I have written plenty about it here as well — its <a href="https://vyasenov.github.io/blog/flavors-lasso.html">many flavors</a>, its <a href="https://vyasenov.github.io/blog/oracle-property.html">oracle property</a>, and its <a href="https://vyasenov.github.io/blog/lasso-heterogeneous-effects.html">use in estimating heterogeneous treatment effects</a>, among other things. It is appealing for several reasons: simplicity, cheap and fast computation, interpretability, and a solid theoretical foundation.</p>
<p>In this note I focus on that last item — what makes the Lasso attractive from a theoretical standpoint. The goal is to give a high-level overview of the kinds of guarantees the Lasso promises. The literature here is heavy and daunting, so I keep the mathematical rigor to a minimum. I am after intuition: what can the Lasso deliver and under what conditions?</p>
<p>The punchline, which I will return to repeatedly, is that these guarantees are not free. Each one rests on assumptions about the design matrix, the noise, and the true signal — and those assumptions get stronger as the promises get bolder.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Consider the usual linear model</p>
<p><img src="https://latex.codecogs.com/png.latex?Y%20=%20X%5Cbeta%5E*%20+%20%5Cvarepsilon,%20%5Cquad%20%5Cvarepsilon%20%5Csim%20(0,%20%5Csigma%5E2%20I_n),"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?Y%20%5Cin%20%5Cmathbb%7BR%7D%5En"> is the outcome, <img src="https://latex.codecogs.com/png.latex?X%20%5Cin%20%5Cmathbb%7BR%7D%5E%7Bn%20%5Ctimes%20p%7D"> is the design matrix, <img src="https://latex.codecogs.com/png.latex?%5Cbeta%5E*%20%5Cin%20%5Cmathbb%7BR%7D%5Ep"> is the true coefficient vector, and <img src="https://latex.codecogs.com/png.latex?%5Cvarepsilon"> is mean-zero noise with variance <img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2">. The interesting regime is high-dimensional, where <img src="https://latex.codecogs.com/png.latex?p"> can be comparable to or much larger than <img src="https://latex.codecogs.com/png.latex?n">.</p>
<p>The signal is assumed <em>sparse</em>: only a few coordinates of <img src="https://latex.codecogs.com/png.latex?%5Cbeta%5E*"> are non-zero. Let</p>
<p><img src="https://latex.codecogs.com/png.latex?S%20=%20%5C%7Bj%20:%20%5Cbeta%5E*_j%20%5Cneq%200%5C%7D,%20%5Cquad%20s%20=%20%7CS%7C"></p>
<p>denote the <em>support</em> and its size. Sparsity is what makes the problem tractable when <img src="https://latex.codecogs.com/png.latex?p%20%5Cgg%20n">.</p>
<p>The Lasso can be written in two equivalent ways. The penalized (Lagrangian) form is</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta%20=%20%5Carg%5Cmin_%7B%5Cbeta%7D%20%5Cleft(%20%5Cfrac%7B1%7D%7B2n%7D%20%5C%7C%20Y%20-%20X%5Cbeta%20%5C%7C_2%5E2%20+%20%5Clambda%20%5C%7C%5Cbeta%5C%7C_1%20%5Cright),"></p>
<p>and the constrained form is</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta%20=%20%5Carg%5Cmin_%7B%5Cbeta%7D%20%5Cfrac%7B1%7D%7B2n%7D%20%5C%7C%20Y%20-%20X%5Cbeta%20%5C%7C_2%5E2%20%5Cquad%20%5Ctext%7Bsubject%20to%7D%20%5Cquad%20%5C%7C%5Cbeta%5C%7C_1%20%5Cleq%20t."></p>
<p>For every <img src="https://latex.codecogs.com/png.latex?%5Clambda"> there is a <img src="https://latex.codecogs.com/png.latex?t"> that yields the same solution. The <img src="https://latex.codecogs.com/png.latex?%5Cell_1"> penalty <img src="https://latex.codecogs.com/png.latex?%5C%7C%5Cbeta%5C%7C_1%20=%20%5Csum_j%20%7C%5Cbeta_j%7C"> is what does the work: unlike the <img src="https://latex.codecogs.com/png.latex?%5Cell_2"> (ridge) penalty, it has corners that produce <em>exact</em> zeros, giving simultaneous shrinkage and selection. The tuning parameter <img src="https://latex.codecogs.com/png.latex?%5Clambda%20%5Cgeq%200"> controls the strength of regularization.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<p>I will examine three broad groups of theoretical results. Each comes with its own assumptions and works only under specific conditions — sparse true support, a particular growth rate for <img src="https://latex.codecogs.com/png.latex?n"> relative to <img src="https://latex.codecogs.com/png.latex?p">, a well-behaved design matrix, and so on. I have ordered the sections in roughly ascending order of how demanding those assumptions are. This ordering is the most important takeaway of the post: prediction is cheap, estimation costs more, and exact support recovery is expensive.</p>
<hr>
<section id="prediction-error" class="level3">
<h3 class="anchored" data-anchor-id="prediction-error">Prediction Error</h3>
<p>This is the most basic guarantee. It says the Lasso will predict “well enough” — the in-sample prediction error will not exceed a certain bound.</p>
<p>Formally, with the penalty chosen at the canonical rate <img src="https://latex.codecogs.com/png.latex?%5Clambda%20%5Casymp%20%5Csigma%5Csqrt%7B%5Ctfrac%7B%5Clog%20p%7D%7Bn%7D%7D">, one can show that with high probability</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B1%7D%7Bn%7D%20%5C%7C%20X(%5Chat%5Cbeta%20-%20%5Cbeta%5E*)%20%5C%7C_2%5E2%20%5C;%5Clesssim%5C;%20%5Clambda%20%5C,%20%5C%7C%5Cbeta%5E*%5C%7C_1%20%5C;%5Casymp%5C;%20%5Csigma%20%5C,%20%5C%7C%5Cbeta%5E*%5C%7C_1%20%5Csqrt%7B%5Cfrac%7B%5Clog%20p%7D%7Bn%7D%7D."></p>
<p>This is the so-called <em>slow rate</em>.</p>
<p>What is remarkable is how little it requires: essentially no conditions on the design matrix <img src="https://latex.codecogs.com/png.latex?X"> beyond standardizing the columns. All you need is for <img src="https://latex.codecogs.com/png.latex?%5Clambda"> to be large enough to dominate the noise — which is exactly what the <img src="https://latex.codecogs.com/png.latex?%5Csqrt%7B%5Clog%20p%20/%20n%7D"> scaling ensures. The <img src="https://latex.codecogs.com/png.latex?%5Clog%20p"> term is the price of searching over <img src="https://latex.codecogs.com/png.latex?p"> candidate predictors, and it enters only logarithmically, which is why the Lasso tolerates enormous <img src="https://latex.codecogs.com/png.latex?p">.</p>
<p>If you are willing to assume more about the design (see the next section), the bound sharpens to the <em>fast rate</em>,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cfrac%7B1%7D%7Bn%7D%20%5C%7C%20X(%5Chat%5Cbeta%20-%20%5Cbeta%5E*)%20%5C%7C_2%5E2%20%5C;%5Clesssim%5C;%20%5Cfrac%7Bs%5C,%20%5Csigma%5E2%20%5Clog%20p%7D%7Bn%7D,"></p>
<p>which scales with the number of true signals <img src="https://latex.codecogs.com/png.latex?s"> rather than with <img src="https://latex.codecogs.com/png.latex?%5C%7C%5Cbeta%5E*%5C%7C_1">.</p>
<hr>
</section>
<section id="estimation-error" class="level3">
<h3 class="anchored" data-anchor-id="estimation-error">Estimation Error</h3>
<p>Here the question shifts from predictions <img src="https://latex.codecogs.com/png.latex?X%5Chat%5Cbeta"> to the coefficients <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> themselves — how close is <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> to <img src="https://latex.codecogs.com/png.latex?%5Cbeta%5E*">? This is a harder problem, and it requires a condition on the design matrix.</p>
<p>The standard assumption is the <em>restricted eigenvalue</em> (RE) condition. Loosely, it requires that <img src="https://latex.codecogs.com/png.latex?%5Ctfrac%7B1%7D%7Bn%7D%20X%5E%5Ctop%20X"> behave like a well-conditioned matrix — bounded away from singularity — but only over the directions that matter, namely vectors that are approximately sparse. We cannot ask <img src="https://latex.codecogs.com/png.latex?X%5E%5Ctop%20X"> to be invertible outright, since <img src="https://latex.codecogs.com/png.latex?p%20%3E%20n"> makes that impossible; the restriction to a sparse cone is what rescues the argument.</p>
<p>Under the RE condition with constant <img src="https://latex.codecogs.com/png.latex?%5Ckappa%20%3E%200">, and again <img src="https://latex.codecogs.com/png.latex?%5Clambda%20%5Casymp%20%5Csigma%5Csqrt%7B%5Ctfrac%7B%5Clog%20p%7D%7Bn%7D%7D">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5C%7C%5Chat%5Cbeta%20-%20%5Cbeta%5E*%5C%7C_2%20%5C;%5Clesssim%5C;%20%5Cfrac%7B%5Csigma%7D%7B%5Ckappa%7D%20%5Csqrt%7B%5Cfrac%7Bs%20%5Clog%20p%7D%7Bn%7D%7D,%20%5Cqquad%20%5C%7C%5Chat%5Cbeta%20-%20%5Cbeta%5E*%5C%7C_1%20%5C;%5Clesssim%5C;%20%5Cfrac%7B%5Csigma%20s%7D%7B%5Ckappa%7D%20%5Csqrt%7B%5Cfrac%7B%5Clog%20p%7D%7Bn%7D%7D."></p>
<p>The intuition is that strong correlations among predictors flatten the objective function in certain directions, making the coefficients poorly identified even when predictions are fine. The RE condition rules out the worst of this. When it holds, the <img src="https://latex.codecogs.com/png.latex?%5Cell_2"> error decays at essentially the rate an oracle who knew <img src="https://latex.codecogs.com/png.latex?S"> would achieve, up to the <img src="https://latex.codecogs.com/png.latex?%5Clog%20p"> factor.</p>
<p>You know to never take the coefficients — or the implied <img src="https://latex.codecogs.com/png.latex?p">-values — from a Lasso fit too seriously without an extreme degree of caution. The shrinkage that makes the Lasso work also biases every non-zero coefficient toward zero, and standard inference ignores the selection step entirely. I have written about <a href="https://vyasenov.github.io/blog/hypothesis-testing-linear-ml.html">hypothesis testing in linear ML models</a> elsewhere on the blog; the estimation bounds above are about <em>rates</em>, not about valid confidence intervals.</p>
<hr>
</section>
<section id="support-recovery" class="level3">
<h3 class="anchored" data-anchor-id="support-recovery">Support Recovery</h3>
<p>This is the most intriguing guarantee and, fittingly, the most expensive. It is relevant for model selection rather than prediction: it asks whether the Lasso picks out exactly the right set of variables, <img src="https://latex.codecogs.com/png.latex?%5Chat%20S%20=%20S">, where <img src="https://latex.codecogs.com/png.latex?%5Chat%20S%20=%20%5C%7Bj%20:%20%5Chat%5Cbeta_j%20%5Cneq%200%5C%7D">.</p>
<p>The goal is <em>selection consistency</em>,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BP%7D(%5Chat%20S%20=%20S)%20%5Cto%201."></p>
<p>Two strong conditions are typically needed. The first is the <em>irrepresentable condition</em>, which limits how strongly the irrelevant predictors (<img src="https://latex.codecogs.com/png.latex?X_%7BS%5Ec%7D">) can be correlated with the relevant ones (<img src="https://latex.codecogs.com/png.latex?X_S">):</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cbig%5C%7C%20X_%7BS%5Ec%7D%5E%5Ctop%20X_S%20(X_S%5E%5Ctop%20X_S)%5E%7B-1%7D%20%5Coperatorname%7Bsign%7D(%5Cbeta%5E*_S)%20%5Cbig%5C%7C_%5Cinfty%20%5Cleq%201%20-%20%5Ceta"></p>
<p>for some <img src="https://latex.codecogs.com/png.latex?%5Ceta%20%3E%200">. This is close to necessary, not merely sufficient — if it fails, the Lasso tends to bring spurious variables into the model. The second is a <em>beta-min</em> condition: the smallest non-zero coefficient must be detectably large, <img src="https://latex.codecogs.com/png.latex?%5Cmin_%7Bj%20%5Cin%20S%7D%20%7C%5Cbeta%5E*_j%7C%20%5Cgtrsim%20%5Csqrt%7B%5Ctfrac%7B%5Clog%20p%7D%7Bn%7D%7D">. Signals weaker than the noise floor simply cannot be distinguished from zero.</p>
<p>The practical implication is sobering. Exact support recovery is fragile: it demands that the truly important variables be only mildly correlated with the unimportant ones, and that no real signal be too small. Both are easy to violate with observational data. This is also why I treated this topic separately in my post on the <a href="https://vyasenov.github.io/blog/oracle-property.html">oracle property</a> — standard Lasso generally does <em>not</em> achieve oracle-style selection, and the fixes (adaptive Lasso, nonconvex penalties like SCAD and MCP) exist precisely to relax the irrepresentable condition.</p>
<hr>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>The Lasso is among the most popular machine learning methods, and a good part of its appeal comes from a strong theoretical foundation.</li>
<li>Under suitable conditions, one can show that the Lasso performs well across three distinct tasks — prediction, coefficient estimation, and exact support recovery..</li>
<li>Prediction error is nearly free; estimation error needs a restricted-eigenvalue-type condition on the design; support recovery additionally needs an irrepresentable condition and a minimum-signal-strength condition.</li>
<li>Not all of these guarantees will hold on any given dataset. The researcher must evaluate the regularity conditions carefully for each claim she makes.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>For a focused, modern treatment, “Statistical Learning with Sparsity” by Hastie, Tibshirani, and Wainwright (2015) is the natural starting point, with “The Elements of Statistical Learning” (2009) as gentler background. For the theory nerds, Bühlmann and van de Geer’s “Statistics for High-Dimensional Data” (2011) and Wainwright’s “High-Dimensional Statistics” (2019) are the standard references, though both are too dense for most mortals.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<ul>
<li><p>Belloni, A., Chernozhukov, V., &amp; Wang, L. (2011). Square-root lasso: Pivotal recovery of sparse signals via conic programming. <em>Biometrika</em>, 98(4), 791–806.</p></li>
<li><p>Bickel, P. J., Ritov, Y., &amp; Tsybakov, A. B. (2009). Simultaneous analysis of Lasso and Dantzig selector. <em>The Annals of Statistics</em>, 37(4), 1705–1732.</p></li>
<li><p>Bühlmann, P., &amp; van de Geer, S. (2011). <em>Statistics for High-Dimensional Data: Methods, Theory and Applications</em>. Springer.</p></li>
<li><p>Hastie, T., Tibshirani, R., &amp; Friedman, J. (2009). <em>The Elements of Statistical Learning: Data Mining, Inference, and Prediction</em> (2nd ed.). Springer.</p></li>
<li><p>Hastie, T., Tibshirani, R., &amp; Wainwright, M. (2015). <em>Statistical Learning with Sparsity: The Lasso and Generalizations</em>. CRC Press.</p></li>
<li><p>Raskutti, G., Wainwright, M. J., &amp; Yu, B. (2011). Minimax rates of estimation for high-dimensional linear regression over <img src="https://latex.codecogs.com/png.latex?%5Cell_q">-balls. <em>IEEE Transactions on Information Theory</em>, 57(10), 6976–6994.</p></li>
<li><p>Tibshirani, R. (1996). Regression shrinkage and selection via the lasso. <em>Journal of the Royal Statistical Society: Series B (Methodological)</em>, 58(1), 267–288.</p></li>
<li><p>van de Geer, S., Bühlmann, P., Ritov, Y., &amp; Dezeure, R. (2014). On asymptotically optimal confidence regions and tests for high-dimensional models. <em>The Annals of Statistics</em>, 42(3), 1166–1202.</p></li>
<li><p>Wainwright, M. J. (2009). Sharp thresholds for high-dimensional and noisy sparsity recovery using <img src="https://latex.codecogs.com/png.latex?%5Cell_1">-constrained quadratic programming (Lasso). <em>IEEE Transactions on Information Theory</em>, 55(5), 2183–2202.</p></li>
<li><p>Wainwright, M. J. (2019). <em>High-Dimensional Statistics: A Non-Asymptotic Viewpoint</em>. Cambridge University Press.</p></li>
<li><p>Zhao, P., &amp; Yu, B. (2006). On model selection consistency of Lasso. <em>Journal of Machine Learning Research</em>, 7, 2541–2563.</p></li>
</ul>


</section>

 ]]></description>
  <category>machine learning</category>
  <category>variable selection</category>
  <category>statistical inference</category>
  <guid>https://vyasenov.github.io/blog/lasso-theory-guarantees.html</guid>
  <pubDate>Thu, 11 Jun 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>Second-Generation \(p\)-Values: A Worthy Idea That Did Not Catch On</title>
  <link>https://vyasenov.github.io/blog/second-gen-pvalues.html</link>
  <description><![CDATA[ 





<div class="reading-time">7 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Hardly a data science interview goes by without the person in power bringing up the definition of the infamous <img src="https://latex.codecogs.com/png.latex?p">-value. Normally, chaos ensues. For good or ill, <img src="https://latex.codecogs.com/png.latex?p">-values are omnipresent in a data scientist’s world. A grad school professor of mine once described them as summaries of an entire dataset into a single number — or even, I would add, into a single yes/no decision.</p>
<p>The downsides of <img src="https://latex.codecogs.com/png.latex?p">-values have been well understood and widely publicized for decades. They conflate effect size and precision, they are routinely misinterpreted, and they say nothing about scientific relevance or practical importance. Famously, the American Statistical Association issued a formal statement on their use and misuse (Wasserstein and Lazar, 2016). Predictably, there has been no shortage of proposed alternatives — <img src="https://latex.codecogs.com/png.latex?e">-values, Bayes factors, posterior probabilities, and more.</p>
<p>In this note I describe one such alternative: the second-generation <img src="https://latex.codecogs.com/png.latex?p">-value (SGPV) of Blume et al.&nbsp;(2019). The point is to broaden how we think about using data to test scientific claims, and to get acquainted with a genuinely different approach. I keep the mathematical rigor to a minimum and focus on the intellectual idea behind the proposal.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Suppose we are interested in some parameter <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> — a difference in means, a log odds ratio, a regression coefficient, whatever the scientific question demands. Classical testing pits a <em>simple</em> (point) null hypothesis against everything else:</p>
<p><img src="https://latex.codecogs.com/png.latex?H_0:%20%5Ctheta%20=%20%5Ctheta_0%20%5Cquad%20%5Ctext%7Bversus%7D%20%5Cquad%20H_1:%20%5Ctheta%20%5Cneq%20%5Ctheta_0."></p>
<p>A simple hypothesis pins <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> to a single value; a <em>composite</em> hypothesis allows a whole set of values. The key move in what follows is to replace the point null with a composite one.</p>
<p>Let <img src="https://latex.codecogs.com/png.latex?I%20=%20%5B%5Ctheta_%5Cell,%20%5Ctheta_u%5D"> denote an interval estimate of <img src="https://latex.codecogs.com/png.latex?%5Ctheta"> — for concreteness, a 95% confidence interval — with length <img src="https://latex.codecogs.com/png.latex?%7CI%7C%20=%20%5Ctheta_u%20-%20%5Ctheta_%5Cell">.</p>
<p>Also, let <img src="https://latex.codecogs.com/png.latex?H_0%20=%20%5B%5Ctheta_%5Cell%5E0,%20%5Ctheta_u%5E0%5D"></p>
<p>denote an <em>interval null hypothesis</em>: the range of effect sizes that are too small to matter scientifically, with length <img src="https://latex.codecogs.com/png.latex?%7CH_0%7C">. This interval includes the exact null <img src="https://latex.codecogs.com/png.latex?%5Ctheta_0"> but widens it to absorb effects that are technically non-zero yet practically trivial. Choosing its width is a scientific judgment, made <em>before</em> seeing the data.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="the-first-generation-p-value" class="level3">
<h3 class="anchored" data-anchor-id="the-first-generation-p-value">The First-Generation P-Value</h3>
<p>Start with the object everyone already knows. We observe a dataset, and the <img src="https://latex.codecogs.com/png.latex?p">-value is the probability of seeing data at least as extreme — weirder, loosely speaking — than what we actually observed, <em>if the null hypothesis were true</em>.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap%20=%20P(%5Ctext%7Bdata%20at%20least%20as%20extreme%20as%20%7D%20%5Ctext%7Bobserved%7D%20%7C%20H_0)%0A"></p>
<p>A large <img src="https://latex.codecogs.com/png.latex?p">-value means the data are unsurprising under the null and therefore offer no evidence against it. Famously, this is <em>not</em> the probability that the null is true; getting at that requires a Bayesian apparatus and a prior. This single number has carried an enormous load for nearly a century, and that is precisely the source of trouble.</p>
<hr>
</section>
<section id="the-problem" class="level3">
<h3 class="anchored" data-anchor-id="the-problem">The Problem</h3>
<p>The classical <img src="https://latex.codecogs.com/png.latex?p">-value conflates two things a practitioner usually wants to keep separate: the <em>size</em> of an effect and the <em>precision</em> with which it is estimated. A tiny, scientifically meaningless effect will produce an arbitrarily small <img src="https://latex.codecogs.com/png.latex?p">-value once the sample is large enough, because precision alone drives significance. In the era of big data this is not a hypothetical — it is the default failure mode.</p>
<p>The deeper issue is the point null itself. The hypothesis <img src="https://latex.codecogs.com/png.latex?%5Ctheta%20=%20%5Ctheta_0"> <em>exactly</em> is almost never true and rarely even interesting. Two treatments are essentially never identical to infinite precision; the relevant question is whether they differ by an amount that matters. Statistical significance, as classically defined, simply does not speak to that question.</p>
<hr>
</section>
<section id="the-main-idea" class="level3">
<h3 class="anchored" data-anchor-id="the-main-idea">The Main Idea</h3>
<p>The SGPV, which I will denote <img src="https://latex.codecogs.com/png.latex?p_%5Cdelta">, replaces the point null with the interval null <img src="https://latex.codecogs.com/png.latex?H_0"> and then measures how much the interval estimate <img src="https://latex.codecogs.com/png.latex?I"> overlaps it. It is a <em>proportion</em>, not a tail-area probability:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ap_%5Cdelta%20=%20%5Cfrac%7B%7CI%20%5Ccap%20H_0%7C%7D%7B%7CI%7C%7D%20%5Ctimes%20%5Cmax%5Cleft%5C%7B%20%5Cfrac%7B%7CI%7C%7D%7B2%7CH_0%7C%7D,%5C,%201%20%5Cright%5C%7D,%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?%7CI%20%5Ccap%20H_0%7C"> is the length of the overlap between the two intervals. When the interval estimate is reasonably precise (specifically, <img src="https://latex.codecogs.com/png.latex?%7CI%7C%20%5Cleq%202%7CH_0%7C">), the correction term is <img src="https://latex.codecogs.com/png.latex?1"> and the formula reduces to the clean fraction <img src="https://latex.codecogs.com/png.latex?p_%5Cdelta%20=%20%7CI%20%5Ccap%20H_0%7C%20/%20%7CI%7C"> — the share of the interval estimate that falls inside the null zone. The correction factor only kicks in when <img src="https://latex.codecogs.com/png.latex?I"> is very wide relative to the null, capping the statistic to reflect that the data are simply too imprecise to say much.</p>
<p>The interpretation is direct:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?p_%5Cdelta%20=%200">: the interval estimate does not overlap the null at all. The data are incompatible with a trivial effect and support a scientifically meaningful one.</li>
<li><img src="https://latex.codecogs.com/png.latex?p_%5Cdelta%20=%201">: the interval estimate lies entirely inside the null. The data support <em>only</em> the null premise — something a classical <img src="https://latex.codecogs.com/png.latex?p">-value can never tell you.</li>
<li><img src="https://latex.codecogs.com/png.latex?0%20%3C%20p_%5Cdelta%20%3C%201">: the data are inconclusive, with <img src="https://latex.codecogs.com/png.latex?p_%5Cdelta%20%5Capprox%201/2"> being the maximally inconclusive case.</li>
</ul>
</section>
<section id="quick-example" class="level3">
<h3 class="anchored" data-anchor-id="quick-example">Quick Example</h3>
<p>A quick worked example from the paper makes it concrete. In a study of 100 smokers and 100 non-smokers, suppose 65 smokers and 50 non-smokers develop lung cancer. The odds ratio is <img src="https://latex.codecogs.com/png.latex?1.86"> with a 95% confidence interval of <img src="https://latex.codecogs.com/png.latex?%5B1.03,%203.36%5D">. Take the interval null to be odds ratios between <img src="https://latex.codecogs.com/png.latex?0.9"> and <img src="https://latex.codecogs.com/png.latex?1.1"> — associations too weak to care about. The interval estimate overlaps the null only slightly, and the SGPV works out to <img src="https://latex.codecogs.com/png.latex?p_%5Cdelta%20=%200.175">: suggestive, but not conclusive. Bump the smokers’ cancer count from 65 to 70 and the odds ratio rises to <img src="https://latex.codecogs.com/png.latex?2.33"> with interval <img src="https://latex.codecogs.com/png.latex?%5B1.27,%204.27%5D">, which no longer touches the null. Now <img src="https://latex.codecogs.com/png.latex?p_%5Cdelta%20=%200">, and we would report a scientifically meaningful association.</p>
<hr>
</section>
<section id="pros-and-cons" class="level3">
<h3 class="anchored" data-anchor-id="pros-and-cons">Pros and Cons</h3>
<p>The appeal is that the SGPV bakes scientific relevance into the inference itself, rather than leaving it as an afterthought to be eyeballed from a confidence interval. By construction it can support the null, it indicates when the data are inconclusive instead of forcing a verdict, and — a genuinely attractive frequency property — its Type I error rate shrinks toward zero as the sample grows, instead of hovering at <img src="https://latex.codecogs.com/png.latex?%5Calpha"> forever. That directly attacks the big-data significance problem and tends to yield lower false discovery rates.</p>
<p>The interval null must be specified in advance, and pinning down the width of “scientifically trivial” is a real judgment call that invites disagreement and can feel arbitrary. The statistic is a proportion rather than a probability, which makes it unfamiliar and harder to slot into existing reporting conventions. And it competes in a crowded field: practitioners who care about false discoveries already reach for <a href="https://vyasenov.github.io/blog/recent-dev-fdr.html">false discovery rate (FDR)</a> or <a href="https://vyasenov.github.io/blog/flavors-multiple-testing.html">family-wise error rate (FWER)</a> procedures.</p>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?P">-values are among the most widely used and most widely misused tools in applied statistics; their core flaw is conflating effect size with precision.</li>
<li>The second-generation <img src="https://latex.codecogs.com/png.latex?p">-value is an alternative worth knowing when false discovery is a concern.</li>
<li>Its main idea is simple: measure the overlap between an interval estimate and an interval null that absorbs both the exact null and all scientifically trivial effects.</li>
<li>Despite its elegance, the SGPV never gained traction. FDR/FWER control and equivalence testing remain the dominant ways practitioners guard against spurious findings.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>See the papers referenced below and look around my blog for more details on multiple testing and false discovery rate control.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<ul>
<li><p>Benjamini, Y., &amp; Hochberg, Y. (1995). Controlling the false discovery rate: A practical and powerful approach to multiple testing. <em>Journal of the Royal Statistical Society: Series B (Methodological)</em>, 57(1), 289–300.</p></li>
<li><p>Blume, J. D., D’Agostino McGowan, L., Dupont, W. D., &amp; Greevy, R. A. (2018). Second-generation p-values: Improved rigor, reproducibility, and transparency in statistical analyses. <em>PLOS ONE</em>, 13(3), e0188299.</p></li>
<li><p>Blume, J. D., Greevy, R. A., Welty, V. F., Smith, J. R., &amp; Dupont, W. D. (2019). An introduction to second-generation p-values. <em>The American Statistician</em>, 73(sup1), 157–167.</p></li>
<li><p>Wasserstein, R. L., &amp; Lazar, N. A. (2016). The ASA statement on p-values: Context, process, and purpose. <em>The American Statistician</em>, 70(2), 129–133.</p></li>
<li><p>Wasserstein, R. L., Schirm, A. L., &amp; Lazar, N. A. (2019). Moving to a world beyond “p &lt; 0.05”. <em>The American Statistician</em>, 73(sup1), 1–19.</p></li>
</ul>


</section>

 ]]></description>
  <category>hypothesis testing</category>
  <category>statistical inference</category>
  <guid>https://vyasenov.github.io/blog/second-gen-pvalues.html</guid>
  <pubDate>Thu, 11 Jun 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>6 Underrated Plot Types</title>
  <link>https://vyasenov.github.io/blog/six-plots-you-should-know.html</link>
  <description><![CDATA[ 





<div class="reading-time">7 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Most data science workflows rely on a familiar trio of plots: histograms, scatterplots, and boxplots. They are useful, but they leave a lot of structure hidden in the data.</p>
<p>There are several plots that statisticians use regularly but that rarely show up in typical data science notebooks. Many of these are extremely informative for diagnostics, distribution comparison, or exploring high-dimensional relationships.</p>
<p>In this post I’ll look at six of them. To keep things simple I will use the same dataset throughout: the classic <code>iris</code> dataset. The goal is not mathematical rigor but practical intuition and code you can reuse. All examples below are shown in <code>R</code> and <code>Python</code>.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<p>Let’s start by loading the data.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ggplot2)</span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(ggridges)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># install.packages("ggridges")</span></span>
<span id="cb1-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(hexbin)    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># install.packages("hexbin")</span></span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(corrplot)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># install.packages("corrplot")</span></span>
<span id="cb1-5"></span>
<span id="cb1-6"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">data</span>(iris)</span></code></pre></div></div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb2-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb2-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> seaborn <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> sns</span>
<span id="cb2-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> scipy.stats <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> stats</span>
<span id="cb2-5"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> load_iris</span>
<span id="cb2-6"></span>
<span id="cb2-7">iris_bunch <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> load_iris(as_frame<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>)</span>
<span id="cb2-8">iris <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> iris_bunch.frame.copy()</span>
<span id="cb2-9">iris[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"species"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> iris[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"target"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">map</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">dict</span>(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">enumerate</span>(iris_bunch.target_names)))</span>
<span id="cb2-10">iris <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> iris.rename(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>{</span>
<span id="cb2-11">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal length (cm)"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal_length"</span>,</span>
<span id="cb2-12">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal width (cm)"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal_width"</span>,</span>
<span id="cb2-13">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"petal length (cm)"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"petal_length"</span>,</span>
<span id="cb2-14">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"petal width (cm)"</span>: <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"petal_width"</span>,</span>
<span id="cb2-15">})</span></code></pre></div></div>
</div>
</div>
</div>
<section id="q-q-plot" class="level3">
<h3 class="anchored" data-anchor-id="q-q-plot">Q-Q Plot</h3>
<p>A Q-Q plot compares sample quantiles to theoretical quantiles from a reference distribution. In practice that reference is usually the normal distribution, which makes the plot a fast diagnostic for residual checks and distributional shape. If the points line up, the sample is broadly consistent with the reference. If they bend away from the line, that tells you where the mismatch lives: skewness shows up as asymmetric curvature, while heavy tails pull the extremes away from the line. One can also use Q-Q plots to compare two empirical distributions, but I’d argue there are better ways to do that.</p>
<p>What I like about Q-Q plots is that they force you to think about <em>where</em> a distribution departs from a model, not just whether a normality test rejects. The downside is that they are easy to overread in small samples and less useful if you do not have a meaningful reference distribution in mind. Unlike traditional statistical tests, Q-Q plots do not spit out a <img src="https://latex.codecogs.com/png.latex?p">-value, so you have to interpret the plot yourself.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="../files/qq-plot.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1"><img src="https://vyasenov.github.io/files/qq-plot.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:85.0%" alt="Q-Q plot of iris sepal length"></a></p>
</figure>
</div>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-2-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-1" aria-controls="tabset-2-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-2-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-2" aria-controls="tabset-2-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-2-1" class="tab-pane active" aria-labelledby="tabset-2-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(iris, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sample =</span> Sepal.Length)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stat_qq</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"#66c2a5"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stat_qq_line</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb3-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb3-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Q-Q Plot of Sepal Length"</span>,</span>
<span id="cb3-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Theoretical Quantiles"</span>,</span>
<span id="cb3-8">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sample Quantiles"</span></span>
<span id="cb3-9">  )</span></code></pre></div></div>
</div>
<div id="tabset-2-2" class="tab-pane" aria-labelledby="tabset-2-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1">stats.probplot(iris[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal_length"</span>], dist<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"norm"</span>, plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>plt)</span>
<span id="cb4-2">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Q-Q Plot of Sepal Length"</span>)</span>
<span id="cb4-3">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Theoretical Quantiles"</span>)</span>
<span id="cb4-4">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sample Quantiles"</span>)</span>
<span id="cb4-5">plt.show()</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="violin-plot" class="level3">
<h3 class="anchored" data-anchor-id="violin-plot">Violin Plot</h3>
<p>A violin plot combines a boxplot with a smoothed (symmetric) density estimate. That makes it useful when a plain boxplot feels too compressed. Two groups can have similar medians and quartiles but very different shapes, and a violin plot makes that visible immediately. In the <code>iris</code> data, it is a quick way to see that species differ not only in central tendency but in how concentrated or dispersed their sepal lengths are.</p>
<p>The main drawback is that the density is smoothed, so small samples can look more structured than they really are. It can also be sensitive to the smoothing parameters (bandwidth more than kernel type). Violins also become noisy if you cram in too many categories. Still, when I want a compact distribution comparison across a handful of groups, violin plots are often a strict upgrade over boxplots.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="../files/violin-plot.png" class="lightbox" data-gallery="quarto-lightbox-gallery-2"><img src="https://vyasenov.github.io/files/violin-plot.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:85.0%" alt="Violin plot of iris sepal length by species"></a></p>
</figure>
</div>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-3-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-1" aria-controls="tabset-3-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-3-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-2" aria-controls="tabset-3-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-3-1" class="tab-pane active" aria-labelledby="tabset-3-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(iris, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> Species, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> Sepal.Length, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> Species)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_violin</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">trim =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">FALSE</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_boxplot</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">width =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">outlier.shape =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb5-5">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Violin Plot of Sepal Length by Species"</span>)</span></code></pre></div></div>
</div>
<div id="tabset-3-2" class="tab-pane" aria-labelledby="tabset-3-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1">sns.violinplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>iris, x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"species"</span>, y<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal_length"</span>, inner<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"box"</span>)</span>
<span id="cb6-2">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Violin Plot of Sepal Length by Species"</span>)</span>
<span id="cb6-3">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span>)</span>
<span id="cb6-4">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal Length"</span>)</span>
<span id="cb6-5">plt.show()</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="ecdf-plot" class="level3">
<h3 class="anchored" data-anchor-id="ecdf-plot">ECDF Plot</h3>
<p>The empirical cumulative distribution function shows the share of observations less than or equal to a given value. That sounds modest, but it is one of the cleanest ways to compare distributions because it avoids arbitrary bin choices and displays the full sample directly. When one ECDF sits to the right of another, you can read that as a first-order stochastic dominance story, at least visually.</p>
<p>The ECDF is defined as</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7BF%7D_n(x)%20=%20%5Cfrac%7B1%7D%7Bn%7D%20%5Csum_%7Bi=1%7D%5En%201(X_i%20%5Cle%20x).%0A"></p>
<p>Do you remember that the PDF is the derivative of the CDF? Yes, CDF is really central to probability theory and understanding any variable at hand. In microeconomic theory classes, ECDFs are used to establish stochastic dominance relationships. I like ECDFs because they are honest. They show every observation’s contribution to the distribution without smoothing it away. The tradeoff is that they are less familiar to many audiences and can look busy when too many groups are overlaid. For side-by-side distribution comparison, though, they are hard to beat.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="../files/ecdf-plot.png" class="lightbox" data-gallery="quarto-lightbox-gallery-3"><img src="https://vyasenov.github.io/files/ecdf-plot.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:85.0%" alt="ECDF plot of iris sepal length by species"></a></p>
</figure>
</div>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-4-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-4-1" aria-controls="tabset-4-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-4-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-4-2" aria-controls="tabset-4-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-4-1" class="tab-pane active" aria-labelledby="tabset-4-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(iris, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(Sepal.Length, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> Species)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">stat_ecdf</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">linewidth =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb7-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb7-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ECDF of Sepal Length by Species"</span>,</span>
<span id="cb7-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal Length"</span>,</span>
<span id="cb7-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Empirical CDF"</span></span>
<span id="cb7-8">  )</span></code></pre></div></div>
</div>
<div id="tabset-4-2" class="tab-pane" aria-labelledby="tabset-4-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1">sns.ecdfplot(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>iris, x<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal_length"</span>, hue<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"species"</span>)</span>
<span id="cb8-2">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ECDF of Sepal Length by Species"</span>)</span>
<span id="cb8-3">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal Length"</span>)</span>
<span id="cb8-4">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Empirical CDF"</span>)</span>
<span id="cb8-5">plt.show()</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="ridgeline-plot" class="level3">
<h3 class="anchored" data-anchor-id="ridgeline-plot">Ridgeline Plot</h3>
<p>Ridgeline plots stack several density curves vertically, which makes them especially useful when you want to compare many related distributions at once. The variables, however, need to be on more-or-less the same scale for the plot to make sense. They are common in cohort analysis and time-based comparisons, but they also work well for grouped exploratory analysis like the species differences in <code>iris</code>.</p>
<p>Their advantage is compactness: you can compare several distributions without the visual clutter of heavy overlap. Their weakness is that they are still density plots, so the same caution about smoothing applies. I use ridgelines when I want a plot that is more expressive than small multiples but less chaotic than overlaying five or six densities in one panel.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="../files/ridgeline-plot.png" class="lightbox" data-gallery="quarto-lightbox-gallery-4"><img src="https://vyasenov.github.io/files/ridgeline-plot.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:85.0%" alt="Ridgeline plot of iris sepal length by species"></a></p>
</figure>
</div>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-5-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-5-1" aria-controls="tabset-5-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-5-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-5-2" aria-controls="tabset-5-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-5-1" class="tab-pane active" aria-labelledby="tabset-5-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(iris, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> Sepal.Length, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> Species, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">fill =</span> Species)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_density_ridges</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">color =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"white"</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_ridges</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb9-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb9-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ridgeline Plot of Sepal Length by Species"</span>,</span>
<span id="cb9-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal Length"</span>,</span>
<span id="cb9-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NULL</span></span>
<span id="cb9-8">  )</span></code></pre></div></div>
</div>
<div id="tabset-5-2" class="tab-pane" aria-labelledby="tabset-5-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1">species_order <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"setosa"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"versicolor"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"virginica"</span>]</span>
<span id="cb10-2">x_grid <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linspace(iris[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal_length"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>,</span>
<span id="cb10-3">                     iris[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal_length"</span>].<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span>)</span>
<span id="cb10-4">offsets <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>]</span>
<span id="cb10-5"></span>
<span id="cb10-6">fig, ax <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> plt.subplots(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb10-7"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> offset, species <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">zip</span>(offsets, species_order):</span>
<span id="cb10-8">    subset <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> iris.loc[iris[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"species"</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> species, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal_length"</span>]</span>
<span id="cb10-9">    kde <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> stats.gaussian_kde(subset)</span>
<span id="cb10-10">    density <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> kde(x_grid)</span>
<span id="cb10-11">    density <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> density <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> density.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">max</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span></span>
<span id="cb10-12">    ax.fill_between(x_grid, offset, offset <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> density, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb10-13">    ax.plot(x_grid, offset <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> density, color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span>
<span id="cb10-14">    ax.text(x_grid.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">min</span>() <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.02</span>, offset <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.12</span>, species, ha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"right"</span>)</span>
<span id="cb10-15"></span>
<span id="cb10-16">ax.set_title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Ridgeline Plot of Sepal Length by Species"</span>)</span>
<span id="cb10-17">ax.set_xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal Length"</span>)</span>
<span id="cb10-18">ax.set_yticks([])</span>
<span id="cb10-19">plt.show()</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="hexbin-plot" class="level3">
<h3 class="anchored" data-anchor-id="hexbin-plot">Hexbin Plot</h3>
<p>Scatterplots are great until they are not. Have you tried a scatterplot with a million points? It’s slow and it’s hard to see anything. Once the sample gets large enough, overplotting hides the very structure you want to see. Hexbin plots solve that by aggregating points into small hexagonal cells and coloring those cells by count. You give up the exact point cloud, but in return you get a much clearer view of where the data are concentrated.</p>
<p>The <code>iris</code> data are too small to truly need a hexbin, which is worth saying out loud. But the plot still illustrates the logic well. On genuinely large datasets, this is often the right substitute for a scatterplot, as is the <a href="https://vyasenov.github.io/blog/binscatter.html">binscatter</a> I have written about elsewhere. The cost is that rare points and local outliers become less visible, so it is better for density structure than for point-level inspection.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="../files/hexbin-plot.png" class="lightbox" data-gallery="quarto-lightbox-gallery-5"><img src="https://vyasenov.github.io/files/hexbin-plot.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:85.0%" alt="Hexbin plot of iris sepal length and petal length"></a></p>
</figure>
</div>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-6-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-6-1" aria-controls="tabset-6-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-6-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-6-2" aria-controls="tabset-6-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-6-1" class="tab-pane active" aria-labelledby="tabset-6-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ggplot</span>(iris, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">aes</span>(Sepal.Length, Petal.Length)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-2">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">geom_hex</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">theme_minimal</span>() <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span></span>
<span id="cb11-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">labs</span>(</span>
<span id="cb11-5">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">title =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Hexbin Plot of Sepal vs Petal Length"</span>,</span>
<span id="cb11-6">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal Length"</span>,</span>
<span id="cb11-7">    <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">y =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Petal Length"</span></span>
<span id="cb11-8">  )</span></code></pre></div></div>
</div>
<div id="tabset-6-2" class="tab-pane" aria-labelledby="tabset-6-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1">plt.hexbin(</span>
<span id="cb12-2">    iris[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"sepal_length"</span>],</span>
<span id="cb12-3">    iris[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"petal_length"</span>],</span>
<span id="cb12-4">    gridsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">14</span>,</span>
<span id="cb12-5">    cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"YlOrRd"</span></span>
<span id="cb12-6">)</span>
<span id="cb12-7">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sepal Length"</span>)</span>
<span id="cb12-8">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Petal Length"</span>)</span>
<span id="cb12-9">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Hexbin Plot of Sepal vs Petal Length"</span>)</span>
<span id="cb12-10">plt.colorbar(label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Count"</span>)</span>
<span id="cb12-11">plt.show()</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="corrgram" class="level3">
<h3 class="anchored" data-anchor-id="corrgram">Corrgram</h3>
<p>A corrgram turns a correlation matrix into something you can actually read. Before fitting a regression, building a clustering pipeline, or running PCA, I almost always want to know which variables are moving together and which are largely independent. A corrgram gives that answer in a single glance.</p>
<p>The upside is speed: strong blocks, redundancies, and likely multicollinearity jump out immediately. The downside is that (Pearson) correlation is a blunt summary. It only captures linear association, ignores conditional relationships, and can be badly distorted by outliers. Presumably, one can move away from Pearson correlation and do the same plot with other correlation measures. Corrgrams also don’t work well with too many variables. So I treat corrgrams as a screening device, not as evidence of mechanism. Used that way, they are extremely effective.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="../files/corrgram.png" class="lightbox" data-gallery="quarto-lightbox-gallery-6"><img src="https://vyasenov.github.io/files/corrgram.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:80.0%" alt="Corrgram of iris measurements"></a></p>
</figure>
</div>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-7-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-7-1" aria-controls="tabset-7-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-7-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-7-2" aria-controls="tabset-7-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-7-1" class="tab-pane active" aria-labelledby="tabset-7-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1">corr_matrix <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cor</span>(iris[, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>])</span>
<span id="cb13-2"></span>
<span id="cb13-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">corrplot</span>(</span>
<span id="cb13-4">  corr_matrix,</span>
<span id="cb13-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"color"</span>,</span>
<span id="cb13-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"upper"</span>,</span>
<span id="cb13-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tl.col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"black"</span>,</span>
<span id="cb13-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">tl.srt =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">45</span></span>
<span id="cb13-9">)</span></code></pre></div></div>
</div>
<div id="tabset-7-2" class="tab-pane" aria-labelledby="tabset-7-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1">corr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> iris.drop(columns<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>[<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"species"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"target"</span>]).corr()</span>
<span id="cb14-2"></span>
<span id="cb14-3">sns.heatmap(corr, annot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"RdBu_r"</span>, center<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb14-4">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Correlation Matrix (Corrgram)"</span>)</span>
<span id="cb14-5">plt.show()</span></code></pre></div></div>
</div>
</div>
</div>
<p>In the <code>iris</code> data, the corrgram immediately tells you that petal length and petal width are carrying very similar information. That is exactly the kind of thing you want to know before moving on to feature engineering, PCA, or a predictive model.</p>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>Q-Q plots are among the fastest ways to diagnose whether a distributional assumption is wrong and where it fails.</li>
<li>Violin plots and ECDFs are often better than boxplots and histograms when the goal is comparing full distributions across groups.</li>
<li>Ridgeline plots are excellent for compact multi-group distribution comparisons, especially when overlaid densities start to look messy.</li>
<li>Hexbin plots are the right replacement for scatterplots once overplotting becomes a real problem.</li>
<li>Corrgrams are simple but high-value screening tools before modeling, especially when redundancy and multicollinearity are on the table.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>Wilke’s <em>Fundamentals of Data Visualization</em> is what I have in my bookshelf, but I admit I don’t reach for it very often. Novice data scientists will surely benefit from it, though.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Wilke, C. O. (2019). <em>Fundamentals of Data Visualization</em>. O’Reilly Media.</p>


</section>

 ]]></description>
  <category>correlation</category>
  <category>statistical inference</category>
  <guid>https://vyasenov.github.io/blog/six-plots-you-should-know.html</guid>
  <pubDate>Mon, 06 Apr 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>The Many Flavors of Principal Component Analysis</title>
  <link>https://vyasenov.github.io/blog/flavors-pca.html</link>
  <description><![CDATA[ 





<div class="reading-time">7 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Principal component analysis (PCA) is one of those methods that everyone learns early and then quietly keeps using for years. The appeal is obvious: take a high-dimensional data matrix, rotate it into orthogonal directions of maximum variance, and keep only the first few directions. That gives you compression, visualization, denoising, and sometimes a useful preprocessing step for downstream models.</p>
<p>The common misconception is that PCA is a generic tool for finding the “most important” variables or the “true latent factors” in the data. It is neither. Classical PCA finds directions of high variance. That is often useful, but it is not the same thing as finding predictive features, interpretable components, or nonlinear structure. Once you keep that distinction straight, the many PCA variants make much more sense: each flavor modifies classical PCA to target a different practical goal.</p>
<p>In this post I will use the standard PCA formulation as the baseline and then focus on four variants that I think matter most in applied work. The goal is to get a broad sense of some of the most popular ways PCA has evolved over the years.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Let <img src="https://latex.codecogs.com/png.latex?X%20%5Cin%20%5Cmathbb%7BR%7D%5E%7Bn%20%5Ctimes%20p%7D"> be a data matrix with rows as observations and columns as variables. Assume the columns have been centered so that</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi=1%7D%5En%20X_%7Bij%7D=0%20%5Cqquad%20%5Ctext%7Bfor%20%7D%20j=1,%5Cdots,p.%0A"></p>
<p>When variables are on very different scales, it is often better to standardize them as well and work with the correlation matrix rather than the covariance matrix. I will write the empirical covariance matrix as</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AS%20=%20%5Cfrac%7B1%7D%7Bn%7DX'X.%0A"></p>
<p>The first principal component loading vector <img src="https://latex.codecogs.com/png.latex?v_1%20%5Cin%20%5Cmathbb%7BR%7D%5Ep"> solves</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Av_1%20=%20%5Carg%5Cmax_%7B%5C%7Cv%5C%7C_2=1%7D%20v'Sv.%0A"></p>
<p>Subsequent components solve the same problem subject to orthogonality constraints. If <img src="https://latex.codecogs.com/png.latex?V_k%20=%20%5Bv_1,%5Cdots,v_k%5D">, the corresponding score matrix is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AZ_k%20=%20XV_k.%0A"></p>
<p>Equivalently, if <img src="https://latex.codecogs.com/png.latex?X%20=%20UDV'"> is the singular value decomposition, the columns of <img src="https://latex.codecogs.com/png.latex?V"> are the loading vectors and the diagonal entries of <img src="https://latex.codecogs.com/png.latex?D%5E2/n"> are the explained variances.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="classical-pca" class="level3">
<h3 class="anchored" data-anchor-id="classical-pca">Classical PCA</h3>
<p>Classical PCA is the benchmark because its optimization problem is clean and its geometry is transparent. The first component is the unit vector that captures the most sample variance; the second is the best such vector orthogonal to the first; and so on. If the singular values of <img src="https://latex.codecogs.com/png.latex?X"> are <img src="https://latex.codecogs.com/png.latex?d_1%20%5Cge%20%5Ccdots%20%5Cge%20d_r">, then the proportion of variance explained by the first <img src="https://latex.codecogs.com/png.latex?k"> components is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cfrac%7B%5Csum_%7Bj=1%7D%5Ek%20d_j%5E2%7D%7B%5Csum_%7Bj=1%7D%5Er%20d_j%5E2%7D.%0A"></p>
<p>In practice, two issues matter more than the derivation. First, PCA is extremely sensitive to scaling. If one variable is measured in dollars and another in percentages, the dollar variable may dominate the first component unless the data are standardized. Second, variance is not the same thing as signal. A noisy feature with large variance can easily drive the first component. I treat classical PCA as a compression tool, not as an automatic discovery engine.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(stats)</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb1-4">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span></span>
<span id="cb1-5">p <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span></span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulate a low-rank signal with two latent factors</span></span>
<span id="cb1-8">latent_factors <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb1-9">loadings_true <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(</span>
<span id="cb1-10">  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>,</span>
<span id="cb1-11">  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>,</span>
<span id="cb1-12">  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>,</span>
<span id="cb1-13">  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>,</span>
<span id="cb1-14">  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>,</span>
<span id="cb1-15">  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>,</span>
<span id="cb1-16"> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>,</span>
<span id="cb1-17">  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb1-18">), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nrow =</span> p, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">byrow =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb1-19"></span>
<span id="cb1-20">X <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> latent_factors <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">t</span>(loadings_true) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sd =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>), n, p)</span>
<span id="cb1-21"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">colnames</span>(X) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">paste0</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"feature_"</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span>p)</span>
<span id="cb1-22"></span>
<span id="cb1-23"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Standardize before PCA because variables may be on different scales</span></span>
<span id="cb1-24">pca_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prcomp</span>(X, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">center =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale. =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb1-25"></span>
<span id="cb1-26"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Explained variance ratio</span></span>
<span id="cb1-27">explained_var <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> pca_fit<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>sdev<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(pca_fit<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>sdev<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb1-28"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(explained_var[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span>
<span id="cb1-29"></span>
<span id="cb1-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># First two loading vectors</span></span>
<span id="cb1-31"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(pca_fit<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>rotation[, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span></code></pre></div></div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb2-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.decomposition <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PCA</span>
<span id="cb2-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StandardScaler</span>
<span id="cb2-4"></span>
<span id="cb2-5">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb2-6">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span></span>
<span id="cb2-7">p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span></span>
<span id="cb2-8"></span>
<span id="cb2-9">latent_factors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb2-10">loadings_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([</span>
<span id="cb2-11">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>],</span>
<span id="cb2-12">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>],</span>
<span id="cb2-13">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>],</span>
<span id="cb2-14">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>],</span>
<span id="cb2-15">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.0</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>],</span>
<span id="cb2-16">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>],</span>
<span id="cb2-17">    [<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span>],</span>
<span id="cb2-18">    [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>,  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>],</span>
<span id="cb2-19">])</span>
<span id="cb2-20"></span>
<span id="cb2-21">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> latent_factors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> loadings_true.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n, p) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span></span>
<span id="cb2-22"></span>
<span id="cb2-23">scaler <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler()</span>
<span id="cb2-24">X_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> scaler.fit_transform(X)</span>
<span id="cb2-25"></span>
<span id="cb2-26">pca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb2-27">pca.fit(X_std)</span>
<span id="cb2-28"></span>
<span id="cb2-29"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Explained variance ratio:"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca.explained_variance_ratio_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span>
<span id="cb2-30"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"First two loading vectors:</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca.components_[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>].T, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="sparse-pca" class="level3">
<h3 class="anchored" data-anchor-id="sparse-pca">Sparse PCA</h3>
<p>Sparse PCA modifies the loading vectors so that many coordinates are exactly zero. A convenient way to write the idea is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmax_%7B%5C%7Cv%5C%7C_2=1%7D%20v'Sv%0A%5Cqquad%0A%5Ctext%7Bsubject%20to%20%7D%20%5C%7Cv%5C%7C_1%20%5Cle%20c,%0A"></p>
<p>or, equivalently, with an <img src="https://latex.codecogs.com/png.latex?%5Cell_1"> penalty on the loadings. The point is not to improve the mathematics of PCA. The point is to make the components readable.</p>
<p>This matters when <img src="https://latex.codecogs.com/png.latex?p"> is large and the classical loading vectors spread small weight across almost every variable. In genomics, marketing, or text applications, that is often useless from a substantive perspective. Sparse PCA forces each component to be built from a smaller set of variables. The tradeoff is that you lose some variance explained, orthogonality becomes less clean, and the components can be more sensitive to tuning choices. In practice, I reach for Sparse PCA when interpretation matters at least as much as compression.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-2-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-1" aria-controls="tabset-2-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-2-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-2" aria-controls="tabset-2-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-2-1" class="tab-pane active" aria-labelledby="tabset-2-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># install.packages("elasticnet")</span></span>
<span id="cb3-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(elasticnet)</span>
<span id="cb3-3"></span>
<span id="cb3-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb3-5">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span></span>
<span id="cb3-6">p <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span></span>
<span id="cb3-7"></span>
<span id="cb3-8">latent_factor <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n)</span>
<span id="cb3-9">X <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(</span>
<span id="cb3-10">  latent_factor <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sd =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>),</span>
<span id="cb3-11">  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> latent_factor <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sd =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>),</span>
<span id="cb3-12">  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> latent_factor <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sd =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>),</span>
<span id="cb3-13">  <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> latent_factor <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sd =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>),</span>
<span id="cb3-14">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> (p <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)), n, p <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb3-15">)</span>
<span id="cb3-16"></span>
<span id="cb3-17">X <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scale</span>(X)</span>
<span id="cb3-18"></span>
<span id="cb3-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Ask for two sparse components with at most 4 nonzero loadings each</span></span>
<span id="cb3-20">spca_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">spca</span>(X, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">K =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"predictor"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sparse =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"varnum"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">para =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb3-21"></span>
<span id="cb3-22"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">round</span>(spca_fit<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>loadings[, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>)</span></code></pre></div></div>
</div>
<div id="tabset-2-2" class="tab-pane" aria-labelledby="tabset-2-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb4-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.decomposition <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> SparsePCA</span>
<span id="cb4-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StandardScaler</span>
<span id="cb4-4"></span>
<span id="cb4-5">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb4-6">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span></span>
<span id="cb4-7">p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span></span>
<span id="cb4-8"></span>
<span id="cb4-9">latent_factor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(n)</span>
<span id="cb4-10">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([</span>
<span id="cb4-11">    latent_factor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>,</span>
<span id="cb4-12">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.9</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> latent_factor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>,</span>
<span id="cb4-13">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> latent_factor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>,</span>
<span id="cb4-14">    <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> latent_factor <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>,</span>
<span id="cb4-15">    np.random.randn(n, p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>)</span>
<span id="cb4-16">])</span>
<span id="cb4-17"></span>
<span id="cb4-18">X_std <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler().fit_transform(X)</span>
<span id="cb4-19"></span>
<span id="cb4-20">spca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> SparsePCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb4-21">spca.fit(X_std)</span>
<span id="cb4-22"></span>
<span id="cb4-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Sparse loadings:</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(spca.components_.T, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="kernel-pca" class="level3">
<h3 class="anchored" data-anchor-id="kernel-pca">Kernel PCA</h3>
<p>Kernel PCA keeps the variance-maximization logic but applies it in a nonlinear feature space. Instead of diagonalizing the covariance matrix of <img src="https://latex.codecogs.com/png.latex?X">, we diagonalize a centered kernel matrix</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AK_%7Bij%7D%20=%20k(x_i,%20x_j),%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?k(%5Ccdot,%5Ccdot)"> might be a radial basis function kernel or a polynomial kernel. PCA is then performed on the centered version of <img src="https://latex.codecogs.com/png.latex?K"> rather than on the original variables.</p>
<p>This is useful when the data lie on a curved manifold rather than near a linear subspace. The classic example is concentric circles: ordinary PCA sees almost no useful low-dimensional linear structure, while Kernel PCA can often unfold the geometry. The price is interpretability. Classical PCA gives loading vectors in the original variables; Kernel PCA gives components in an implicit feature space. In practice, that makes it more of a nonlinear embedding method than a variable-summary tool. It is also sensitive to kernel choice and scale, so I do not treat it as a push-button replacement for standard PCA.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-3-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-1" aria-controls="tabset-3-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-3-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-2" aria-controls="tabset-3-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-3-1" class="tab-pane active" aria-labelledby="tabset-3-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># install.packages("kernlab")</span></span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(kernlab)</span>
<span id="cb5-3"></span>
<span id="cb5-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb5-5">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span></span>
<span id="cb5-6">angles <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runif</span>(n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> pi)</span>
<span id="cb5-7">radius <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">each =</span> n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sd =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span>)</span>
<span id="cb5-8"></span>
<span id="cb5-9">X_circle <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(</span>
<span id="cb5-10">  radius <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cos</span>(angles),</span>
<span id="cb5-11">  radius <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sin</span>(angles)</span>
<span id="cb5-12">)</span>
<span id="cb5-13"></span>
<span id="cb5-14">kpca_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">kpca</span>(</span>
<span id="cb5-15">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">x =</span> X_circle,</span>
<span id="cb5-16">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">kernel =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rbfdot"</span>,</span>
<span id="cb5-17">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">kpar =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">list</span>(<span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sigma =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>),</span>
<span id="cb5-18">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">features =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span></span>
<span id="cb5-19">)</span>
<span id="cb5-20"></span>
<span id="cb5-21"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rotated</span>(kpca_fit))</span></code></pre></div></div>
</div>
<div id="tabset-3-2" class="tab-pane" aria-labelledby="tabset-3-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb6-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.decomposition <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> KernelPCA</span>
<span id="cb6-3"></span>
<span id="cb6-4">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb6-5">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">300</span></span>
<span id="cb6-6">angles <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.uniform(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.pi, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb6-7">radius <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.repeat([<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.0</span>], repeats<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">//</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.05</span></span>
<span id="cb6-8"></span>
<span id="cb6-9">X_circle <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.column_stack([</span>
<span id="cb6-10">    radius <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.cos(angles),</span>
<span id="cb6-11">    radius <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> np.sin(angles),</span>
<span id="cb6-12">])</span>
<span id="cb6-13"></span>
<span id="cb6-14">kpca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> KernelPCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, kernel<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"rbf"</span>, gamma<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb6-15">X_embedded <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> kpca.fit_transform(X_circle)</span>
<span id="cb6-16"></span>
<span id="cb6-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(X_embedded[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="probabilistic-pca" class="level3">
<h3 class="anchored" data-anchor-id="probabilistic-pca">Probabilistic PCA</h3>
<p>Probabilistic PCA (PPCA) replaces the deterministic projection view with a latent variable model:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Ax_i%20=%20%5Cmu%20+%20W%20z_i%20+%20%5Cvarepsilon_i,%0A%5Cqquad%0Az_i%20%5Csim%20N(0,%20I_q),%0A%5Cqquad%0A%5Cvarepsilon_i%20%5Csim%20N(0,%20%5Csigma%5E2%20I_p).%0A"></p>
<p>Here <img src="https://latex.codecogs.com/png.latex?z_i"> is a <img src="https://latex.codecogs.com/png.latex?q">-dimensional latent factor and <img src="https://latex.codecogs.com/png.latex?%5Cvarepsilon_i"> is isotropic Gaussian noise. Under maximum likelihood, the estimated subspace coincides with classical PCA in a particular limit, but the formulation buys you something important: a likelihood, uncertainty quantification, and a principled way to deal with missing values.</p>
<p>That makes PPCA attractive when PCA is part of a generative modeling workflow rather than just a preprocessing step. I especially like it when the data matrix has moderate missingness and I do not want to impute first and hope for the best. The main caveat is the isotropic-noise assumption. If feature-specific noise levels differ substantially, PPCA can be too restrictive and factor analysis may be the better model.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-4-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-4-1" aria-controls="tabset-4-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-4-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-4-2" aria-controls="tabset-4-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-4-1" class="tab-pane active" aria-labelledby="tabset-4-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># install.packages("pcaMethods")</span></span>
<span id="cb7-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(pcaMethods)</span>
<span id="cb7-3"></span>
<span id="cb7-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb7-5">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">150</span></span>
<span id="cb7-6">p <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span></span>
<span id="cb7-7"></span>
<span id="cb7-8">latent_factors <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-9">loadings_true <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(p <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), p, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb7-10">X <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> latent_factors <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">t</span>(loadings_true) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sd =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span>), n, p)</span>
<span id="cb7-11"></span>
<span id="cb7-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Introduce missing values</span></span>
<span id="cb7-13">missing_index <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(X), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">size =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(X))</span>
<span id="cb7-14">X[missing_index] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">NA</span></span>
<span id="cb7-15"></span>
<span id="cb7-16">ppca_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pca</span>(X, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">method =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ppca"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">nPcs =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">seed =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb7-17"></span>
<span id="cb7-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Completed data and estimated scores</span></span>
<span id="cb7-19">X_completed <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">completeObs</span>(ppca_fit)</span>
<span id="cb7-20"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scores</span>(ppca_fit)</span></code></pre></div></div>
</div>
<div id="tabset-4-2" class="tab-pane" aria-labelledby="tabset-4-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># pip install ppca-py</span></span>
<span id="cb8-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb8-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> ppca <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PPCA</span>
<span id="cb8-4"></span>
<span id="cb8-5">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb8-6">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">150</span></span>
<span id="cb8-7">p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span></span>
<span id="cb8-8"></span>
<span id="cb8-9">latent_factors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb8-10">loadings_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(p, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb8-11">X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> latent_factors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> loadings_true.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n, p) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.2</span></span>
<span id="cb8-12"></span>
<span id="cb8-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Introduce missing values</span></span>
<span id="cb8-14">missing_mask <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.rand(n, p) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.10</span></span>
<span id="cb8-15">X[missing_mask] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.nan</span>
<span id="cb8-16"></span>
<span id="cb8-17">ppca <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PPCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb8-18">ppca.fit(X)</span>
<span id="cb8-19"></span>
<span id="cb8-20">scores, score_cov <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ppca.posterior_latent(X)</span>
<span id="cb8-21">X_imputed <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ppca.sample_missing(X, n_draws<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb8-22"></span>
<span id="cb8-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Estimated noise variance:"</span>, <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(ppca.noise_variance_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>))</span>
<span id="cb8-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"First five latent scores:</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(scores[:<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>], <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="truncated-pca" class="level3">
<h3 class="anchored" data-anchor-id="truncated-pca">Truncated PCA</h3>
<p>This last flavor is a little different. Truncated PCA does not change the statistical target. It changes the computation. Instead of computing the full singular value decomposition, we directly approximate the top <img src="https://latex.codecogs.com/png.latex?k"> singular vectors:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AX%20%5Capprox%20U_k%20D_k%20V_k'.%0A"></p>
<p>When <img src="https://latex.codecogs.com/png.latex?n"> and <img src="https://latex.codecogs.com/png.latex?p"> are large, or when <img src="https://latex.codecogs.com/png.latex?X"> is sparse, that distinction matters a lot. If all you want are the first few components, computing the full decomposition is wasted effort.</p>
<p>For practitioners, this is often the most useful PCA variant of all because it makes the classical method scale. The catch is conceptual rather than mathematical: randomized or truncated PCA is not discovering a different notion of component. It is approximating the same principal subspace more cheaply. If the approximation error is small, great. If not, you have a computational shortcut, not a new estimator.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-5-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-5-1" aria-controls="tabset-5-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-5-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-5-2" aria-controls="tabset-5-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-5-1" class="tab-pane active" aria-labelledby="tabset-5-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># install.packages("irlba")</span></span>
<span id="cb9-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(irlba)</span>
<span id="cb9-3"></span>
<span id="cb9-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb9-5">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span></span>
<span id="cb9-6">p <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span></span>
<span id="cb9-7"></span>
<span id="cb9-8">latent_factors <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>), n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb9-9">loadings_true <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(p <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>), p, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb9-10">X_large <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> latent_factors <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">t</span>(loadings_true) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sd =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>), n, p)</span>
<span id="cb9-11"></span>
<span id="cb9-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fast approximation to the first 5 principal components</span></span>
<span id="cb9-13">pca_fast <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">prcomp_irlba</span>(X_large, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">n =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">center =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">scale. =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb9-14"></span>
<span id="cb9-15">pca_fast<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>sdev<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(pca_fast<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>sdev<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span></code></pre></div></div>
</div>
<div id="tabset-5-2" class="tab-pane" aria-labelledby="tabset-5-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb10-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.decomposition <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> PCA</span>
<span id="cb10-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.preprocessing <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> StandardScaler</span>
<span id="cb10-4"></span>
<span id="cb10-5">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb10-6">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1000</span></span>
<span id="cb10-7">p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span></span>
<span id="cb10-8"></span>
<span id="cb10-9">latent_factors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb10-10">loadings_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(p, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb10-11">X_large <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> latent_factors <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> loadings_true.T <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n, p) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb10-12"></span>
<span id="cb10-13">X_large <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> StandardScaler().fit_transform(X_large)</span>
<span id="cb10-14"></span>
<span id="cb10-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Randomized SVD computes an approximate leading subspace</span></span>
<span id="cb10-16">pca_fast <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> PCA(n_components<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, svd_solver<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"randomized"</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb10-17">pca_fast.fit(X_large)</span>
<span id="cb10-18"></span>
<span id="cb10-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">round</span>(pca_fast.explained_variance_ratio_, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))</span></code></pre></div></div>
</div>
</div>
</div>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>Classical PCA is a variance-maximizing compression tool, not a generic device for finding the “most important” variables or latent causes.</li>
<li>Sparse PCA is the right upgrade when interpretability matters and dense loading vectors are getting in the way.</li>
<li>Kernel PCA is useful for nonlinear geometry, but you give up the clean loading-vector interpretation that makes ordinary PCA attractive.</li>
<li>Probabilistic PCA is worth using when likelihood, uncertainty, or missing data matter; otherwise classical PCA is usually simpler.</li>
<li>Truncated PCA is often the most practical choice on large matrices because it targets the same principal subspace at a much lower computational cost.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>For the classical theory, Jolliffe’s <em>Principal Component Analysis</em> is still the standard reference and Jolliffe and Cadima (2016) is a concise modern review. Zou, Hastie, and Tibshirani (2006) is the canonical sparse PCA paper. Schölkopf, Smola, and Müller (1998) remains the core reference for Kernel PCA, while Tipping and Bishop (1999) is the paper to read for the probabilistic view. If your main concern is computation at scale, Halko, Martinsson, and Tropp (2011) is the right randomized linear algebra entry point.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Halko, N., Martinsson, P. G., &amp; Tropp, J. A. (2011). Finding structure with randomness: Probabilistic algorithms for constructing approximate matrix decompositions. <em>SIAM Review</em>, 53(2), 217-288.</p>
<p>Jolliffe, I. T., &amp; Cadima, J. (2016). Principal component analysis: A review and recent developments. <em>Philosophical Transactions of the Royal Society A</em>, 374(2065), 20150202.</p>
<p>Schölkopf, B., Smola, A., &amp; Müller, K.-R. (1998). Nonlinear component analysis as a kernel eigenvalue problem. <em>Neural Computation</em>, 10(5), 1299-1319.</p>
<p>Tipping, M. E., &amp; Bishop, C. M. (1999). Probabilistic principal component analysis. <em>Journal of the Royal Statistical Society: Series B</em>, 61(3), 611-622.</p>
<p>Zou, H., Hastie, T., &amp; Tibshirani, R. (2006). Sparse principal component analysis. <em>Journal of Computational and Graphical Statistics</em>, 15(2), 265-286.</p>


</section>

 ]]></description>
  <category>machine learning</category>
  <category>flavors</category>
  <guid>https://vyasenov.github.io/blog/flavors-pca.html</guid>
  <pubDate>Sun, 05 Apr 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>Brief Overview of Treatment Effect Bounds</title>
  <link>https://vyasenov.github.io/blog/treatment-effects-bounds.html</link>
  <description><![CDATA[ 





<div class="reading-time">7 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>In applied causal work, the real problem is often not estimation but identification. Attrition, imperfect take-up, endogenous selection, and missing outcomes can all make the average treatment effect impossible to point-identify from the data at hand. In those settings, a precise estimate is not a sign of rigor. It is usually a sign that strong assumptions have been smuggled in.</p>
<p>Bounding methods take a more honest route. Rather than asking for the exact value of a treatment effect, they ask which values remain consistent with the observed data and a stated set of assumptions. The answer is an interval, not a point. That interval may be wide, but its width is itself informative: it tells you how much the design really buys you before additional structure is imposed.</p>
<p>This is why I think treatment effect bounds are worth knowing even for practitioners who usually work with point estimators. They are useful both as primary estimands and as a diagnostic. If weak-assumption bounds are already tight, your design is doing real work. If they are wide, that is a warning against overconfident causal claims.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>For each unit <img src="https://latex.codecogs.com/png.latex?i">, let <img src="https://latex.codecogs.com/png.latex?Y_i(1)"> and <img src="https://latex.codecogs.com/png.latex?Y_i(0)"> denote the potential outcomes under treatment and control, and let <img src="https://latex.codecogs.com/png.latex?D_i%20%5Cin%20%5C%7B0,1%5C%7D"> be the treatment indicator. When needed, I use <img src="https://latex.codecogs.com/png.latex?Z"> for an ordered instrument or covariate. The observed outcome is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AY_i%20=%20D_i%20Y_i(1)%20+%20(1-D_i)Y_i(0).%0A"></p>
<p>The target parameter is the average treatment effect</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctau%20=%20%5Cmathbb%7BE%7D%5BY(1)-Y(0)%5D.%0A"></p>
<p>When <img src="https://latex.codecogs.com/png.latex?%5Ctau"> is not point-identified, the object of interest becomes an identified set</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctau%20%5Cin%20%5B%5Cunderline%7B%5Ctau%7D,%20%5Coverline%7B%5Ctau%7D%5D,%0A"></p>
<p>where the endpoints depend on the observed distribution and the maintained assumptions. A bound is <em>sharp</em> if every value in that interval is attainable under some data-generating process consistent with those assumptions. Sharp is always good!</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="manski-bounds" class="level3">
<h3 class="anchored" data-anchor-id="manski-bounds">Manski Bounds</h3>
<p>Manski (1990) is the natural starting point because it assumes almost nothing beyond bounded outcomes. Suppose <img src="https://latex.codecogs.com/png.latex?Y%20%5Cin%20%5By_%7B%5Cmin%7D,%20y_%7B%5Cmax%7D%5D">, let <img src="https://latex.codecogs.com/png.latex?p%20=%20%5Cmathbb%7BP%7D(D=1)">, and define</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmu_1%20=%20%5Cmathbb%7BE%7D(Y%20%5Cmid%20D=1),%20%5Cqquad%20%5Cmu_0%20=%20%5Cmathbb%7BE%7D(Y%20%5Cmid%20D=0).%0A"></p>
<p>Then the missing counterfactual means satisfy</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathbb%7BE%7D%5BY(1)%5D%20%5Cin%20%5Cleft%5Bp%5Cmu_1%20+%20(1-p)y_%7B%5Cmin%7D,%20%5C;%20p%5Cmu_1%20+%20(1-p)y_%7B%5Cmax%7D%5Cright%5D%0A"></p>
<p>and</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathbb%7BE%7D%5BY(0)%5D%20%5Cin%20%5Cleft%5B(1-p)%5Cmu_0%20+%20py_%7B%5Cmin%7D,%20%5C;%20(1-p)%5Cmu_0%20+%20py_%7B%5Cmax%7D%5Cright%5D.%0A"></p>
<p>Combining them gives sharp bounds on the ATE:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctau%20%5Cin%20%5Cleft%5B%0A%5Cunderline%7B%5Ctau%7D,%20%5Coverline%7B%5Ctau%7D%0A%5Cright%5D.%0A"></p>
<p>where</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cunderline%7B%5Ctau%7D%20=%20p%5Cmu_1%20-%20(1-p)%5Cmu_0%20+%20(1-p)y_%7B%5Cmin%7D%20-%20py_%7B%5Cmax%7D%0A"></p>
<p>and</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Coverline%7B%5Ctau%7D%20=%20p%5Cmu_1%20-%20(1-p)%5Cmu_0%20+%20(1-p)y_%7B%5Cmax%7D%20-%20py_%7B%5Cmin%7D.%0A"></p>
<p>These bounds are usually wide, and that is exactly the point. Manski bounds tell you what the data alone can support before you add structure. In practice, I treat them as the baseline honesty check.</p>
</section>
<section id="tightening-manski-mtr-mts-and-miv" class="level3">
<h3 class="anchored" data-anchor-id="tightening-manski-mtr-mts-and-miv">Tightening Manski: MTR, MTS, and MIV</h3>
<p>The usual next step is to ask whether credible qualitative restrictions can narrow the interval. Manski and Pepper (2000) study three of the most useful ones. My first job market paper as a PhD candidate employed these restrictions to tighten the Manski bounds in the context of the labor market impact of immigration.</p>
<p>First, under <em>Monotone Treatment Response (MTR)</em>, treatment weakly helps everyone: <img src="https://latex.codecogs.com/png.latex?Y(1)%20%5Cge%20Y(0)%20%5Ctext%7B%20for%20every%20unit%20%7D."></p>
<p>MTR tightens the bounds by ruling out any configuration in which treatment hurts some units, so the lower bound rises and negative treatment effects become harder or impossible to sustain. For example, under MTR, <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D%5BY(1)%5Cmid%20D=0%5D"> cannot be below <img src="https://latex.codecogs.com/png.latex?%5Cmu_0"> (each control’s missing <img src="https://latex.codecogs.com/png.latex?Y(1)"> is at least that unit’s observed <img src="https://latex.codecogs.com/png.latex?Y(0)">), not merely <img src="https://latex.codecogs.com/png.latex?y_%7B%5Cmin%7D">; and <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D%5BY(0)%5Cmid%20D=1%5D"> cannot exceed <img src="https://latex.codecogs.com/png.latex?%5Cmu_1">.</p>
<p>Second, under <em>Monotone Treatment Selection (MTS)</em>, treated units are systematically stronger than untreated units in terms of their potential outcomes. MTS tightens the bounds by imposing an ordering on who selects into treatment, so the observed outcomes in one group become informative about the missing potential outcomes in the other. For example, under MTS, <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D%5BY(0)%5Cmid%20D=1%5D"> is bounded below by <img src="https://latex.codecogs.com/png.latex?%5Cmu_0">, not merely <img src="https://latex.codecogs.com/png.latex?y_%7B%5Cmin%7D">.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathbb%7BE%7D%5BY(d)%5Cmid%20D=1%5D%20%5Cge%20%5Cmathbb%7BE%7D%5BY(d)%5Cmid%20D=0%5D,%20%5Cqquad%20d%20%5Cin%20%5C%7B0,1%5C%7D.%0A"></p>
<p>Third, under a <em>Monotone Instrumental Variable (MIV)</em> assumption, an ordered variable <img src="https://latex.codecogs.com/png.latex?Z"> shifts potential outcomes in a known direction:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmathbb%7BE%7D%5BY(d)%5Cmid%20Z=z_1%5D%20%5Cle%20%5Cmathbb%7BE%7D%5BY(d)%5Cmid%20Z=z_2%5D%20%5Cquad%20%5Ctext%7Bfor%20%7D%20z_1%20%5Cle%20z_2,%5C%20d%20%5Cin%20%5C%7B0,1%5C%7D.%0A"></p>
<p>In words, MIV lets us use the ordering in <img src="https://latex.codecogs.com/png.latex?Z"> to intersect bounds across instrument values, which can noticeably shrink the identified set. These assumptions get more powerful as the data scientist combines them together. In some cases, the resulting interval can be informative.</p>
</section>
<section id="balke-pearl-bounds-for-noncompliance" class="level3">
<h3 class="anchored" data-anchor-id="balke-pearl-bounds-for-noncompliance">Balke-Pearl Bounds for Noncompliance</h3>
<p>Balke and Pearl (1997) address randomized assignment with imperfect compliance. Instead of jumping directly to <a href="https://vyasenov.github.io/blog/iv-randomized-experiments.html">LATE under exclusion and monotonicity</a>, they ask a broader question: what does the observed joint distribution of <img src="https://latex.codecogs.com/png.latex?(Y,D,Z)"> imply about the population treatment effect under weaker assumptions?</p>
<p>The answer is a sharp nonparametric bound obtained by optimizing over all latent compliance-response types consistent with the observed data:</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cmin_%7Bq%20%5Cin%20%5Cmathcal%7BQ%7D(P_%7BYDZ%7D)%7D%20%5Cmathbb%7BE%7D_q%5BY(1)-Y(0)%5D%0A%5C;%5Cle%5C;%0A%5Ctau%0A%5C;%5Cle%5C;%0A%5Cmax_%7Bq%20%5Cin%20%5Cmathcal%7BQ%7D(P_%7BYDZ%7D)%7D%20%5Cmathbb%7BE%7D_q%5BY(1)-Y(0)%5D.%0A"></p>
<p>This is best viewed as a separation between what the experiment identifies and what extra assumptions identify. Balke-Pearl bounds are often much wider than a LATE estimate, but they answer a different question. LATE is a point-identified effect for compliers under stronger structure. Balke-Pearl bounds are partial-identification statements about broader causal quantities. When the policy question is about the full eligible population rather than compliers, that distinction matters.</p>
</section>
<section id="lee-bounds-for-sample-selection" class="level3">
<h3 class="anchored" data-anchor-id="lee-bounds-for-sample-selection">Lee Bounds for Sample Selection</h3>
<p>Lee (2009) is the method I see most often in practice because the intuition is so transparent. Suppose treatment is randomized, but outcomes are only observed for selected units. Wages observed only for employed workers is the canonical example. If treatment changes employment, comparing observed wages across treatment arms is contaminated by selection.</p>
<p>Lee’s key assumption is <em>monotone selection</em>: treatment can move selection in only one direction for every unit. If treatment raises the probability of observation, then the treated group contains some “extra” observed units relative to control. Those units must be trimmed away from one tail or the other of the treated outcome distribution.</p>
<p>Let <img src="https://latex.codecogs.com/png.latex?S"> indicate whether the outcome is observed and suppose <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BP%7D(S=1%20%5Cmid%20D=1)%20%3E%20%5Cmathbb%7BP%7D(S=1%20%5Cmid%20D=0)">. The excess selected share in the treated group is</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Cpi%20=%20%5Cfrac%7B%5Cmathbb%7BP%7D(S=1%20%5Cmid%20D=1)%20-%20%5Cmathbb%7BP%7D(S=1%20%5Cmid%20D=0)%7D%7B%5Cmathbb%7BP%7D(S=1%20%5Cmid%20D=1)%7D.%0A"></p>
<p>Trimming a fraction <img src="https://latex.codecogs.com/png.latex?%5Cpi"> from the upper tail gives one bound; trimming it from the lower tail gives the other.</p>
<div class="callout callout-style-default callout-note callout-titled" title="Algorithm:">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>Algorithm:
</div>
</div>
<div class="callout-body-container callout-body">
<ol type="1">
<li>Compute the selection rate in each treatment arm.</li>
<li>Identify the arm with the higher selection rate.</li>
<li>Trim the excess share from one tail and then the other of that arm’s observed outcome distribution.</li>
<li>Compare the trimmed means to the mean outcome in the arm with the lower selection rate.</li>
</ol>
</div>
</div>
<p>I like Lee bounds because they are easy to explain and easy to audit. The practical warning is equally simple: if treatment plausibly pushes some units into the sample and others out, the monotone-selection logic breaks. <!-- 
### MTE-Based Extrapolation

Kowalski (2016) is slightly different in spirit. She presented this paper while I was in graduate school, so the idea stuck with me. The goal is not just to bound treatment effects under weak assumptions, but to say more about populations beyond compliers by adding structure through the marginal treatment effect framework. If $u$ indexes resistance to treatment take-up and $p(z)=\mathbb{P}(D=1\mid Z=z)$, then

$$
\text{ATE} = \int_0^1 \text{MTE}(u)\,du,
\qquad
\text{LATE}(z,z') = \frac{1}{p(z)-p(z')} \int_{p(z')}^{p(z)} \text{MTE}(u)\,du.
$$

The intuition is that standard IV identifies an average treatment effect only over the slice of the selection margin moved by the instrument. With additional structure, you can extrapolate beyond that slice. This can be useful when the policy question is about always-takers, never-takers, or external validity more broadly. I would not treat this as a first-line bounding strategy, but it is a useful next step once the limits of LATE become the real issue.
--> ## Bottom Line</p>
<ul>
<li>Bounds are not a consolation prize. They are the right estimand when the data do not support point identification.</li>
<li>Manski bounds are the benchmark because they show what your design identifies before assumptions start doing the heavy lifting.</li>
<li>Monotonicity restrictions, Lee trimming, and Balke-Pearl bounds can be very informative, but only when their substantive assumptions are defensible.</li>
<li>Wide bounds are often the most important empirical result in the paper because they reveal how little the design alone can rule out.</li>
</ul>
</section>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>For a broad introduction, I would start with Manski’s <em>Partial Identification of Probability Distributions</em>, which remains the cleanest entry point into the logic of identification regions. Manski and Pepper (2000) is the canonical reference for monotone restrictions such as MTR and MIV. Balke and Pearl (1997) is still the core paper for noncompliance bounds, while Lee (2009) is the practical workhorse for attrition and sample selection. <!-- Kowalski (2016) is useful once the conversation shifts from partial identification toward extrapolating beyond compliers. --></p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Balke, A., &amp; Pearl, J. (1997). Bounds on treatment effects from studies with imperfect compliance. <em>Journal of the American Statistical Association</em>, 92(439), 1171-1176.</p>
<p>Kowalski, A. E. (2016). Doing more when you’re running LATE: Applying marginal treatment effect methods to examine treatment effect heterogeneity in experiments. <em>American Economic Journal: Applied Economics</em>, 8(2), 1-17.</p>
<p>Lee, D. S. (2009). Training, wages, and sample selection: Estimating sharp bounds on treatment effects. <em>Review of Economic Studies</em>, 76(3), 1071-1102.</p>
<p>Manski, C. F. (1990). Nonparametric bounds on treatment effects. <em>American Economic Review</em>, 80(2), 319-323.</p>
<p>Manski, C. F. (2003). <em>Partial Identification of Probability Distributions</em>. Springer.</p>
<p>Manski, C. F., &amp; Pepper, J. V. (2000). Monotone instrumental variables: With an application to the returns to schooling. <em>Econometrica</em>, 68(4), 997-1010.</p>


</section>

 ]]></description>
  <category>causal inference</category>
  <guid>https://vyasenov.github.io/blog/treatment-effects-bounds.html</guid>
  <pubDate>Thu, 02 Apr 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>What OLS Estimates in Causal Inference</title>
  <link>https://vyasenov.github.io/blog/interpret-OLS-causal-inference.html</link>
  <description><![CDATA[ 





<div class="reading-time">7 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>OLS is still the default causal estimator in a surprising amount of applied work. That is often understandable. Regression is simple, transparent, and often a reasonable first pass. The problem is interpretation. Once we move beyond randomized experiments with additive constant effects, the coefficient on treatment is not automatically the average treatment effect (ATE), or even an average treatment effect for a population we care about.</p>
<p>What makes this topic tricky is that there are really two separate questions. First, what population quantity does the OLS coefficient target? Second, under what assumptions can that quantity be interpreted causally? OLS itself does not assume a potential outcomes framework. It solves a least-squares projection problem. Potential outcomes enter only when we try to map that projection coefficient to objects like the ATE, ATT, or ATU.</p>
<p>Several somewhat related papers sharpen this distinction. This note provides a brief overview of some of the key developments in our understanding of OLS in causal inference. Taken together, these results explain both why OLS can be useful and why its causal interpretation is often more delicate than practitioners realize.</p>
<!-- Aronow and Samii (2016) show that regression adjustment can be understood as targeting a weighted causal estimand, but their characterization is asymptotic. Chattopadhyay and Zubizarreta (2023) derive exact finite-sample implied weights. Słoczyński (2022) shows that with heterogeneous treatment effects the OLS coefficient becomes a weighted average of group-specific effects, often interpretable as effects for treated and untreated units, with the smaller group receiving more weight. 
-->
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Let <img src="https://latex.codecogs.com/png.latex?Y_i"> be the observed outcome, <img src="https://latex.codecogs.com/png.latex?D_i%20%5Cin%20%5C%7B0,1%5C%7D"> a treatment indicator, and <img src="https://latex.codecogs.com/png.latex?X_i"> a vector of covariates. Potential outcomes are <img src="https://latex.codecogs.com/png.latex?Y_i(1)"> and <img src="https://latex.codecogs.com/png.latex?Y_i(0)">, so</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AY_i%20=%20D_iY_i(1)%20+%20(1-D_i)Y_i(0).%0A"></p>
<p>Define the conditional mean functions</p>
<p><img src="https://latex.codecogs.com/png.latex?%0Am_d(x)=%5Cmathbb%7BE%7D%5BY(d)%5Cmid%20X=x%5D,%20%5Cqquad%20%5Ctau(x)=m_1(x)-m_0(x),%0A"></p>
<p>and the usual causal targets</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BATE%7D%20=%20%5Cmathbb%7BE%7D%5B%5Ctau(X)%5D,%20%5Cqquad%20%5Ctext%7BATT%7D%20=%20%5Cmathbb%7BE%7D%5B%5Ctau(X)%5Cmid%20D=1%5D,%20%5Cqquad%20%5Ctext%7BATU%7D%20=%20%5Cmathbb%7BE%7D%5B%5Ctau(X)%5Cmid%20D=0%5D.%0A"></p>
<p>Now consider the linear regression</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AY_i%20=%20%5Calpha%20+%20%5Ctau_%7B%5Ctext%7BOLS%7D%7D%20D_i%20+%20X_i'%5Cbeta%20+%20u_i.%0A"></p>
<p>The coefficient <img src="https://latex.codecogs.com/png.latex?%5Ctau_%7B%5Ctext%7BOLS%7D%7D"> is the population linear projection coefficient on <img src="https://latex.codecogs.com/png.latex?D">. By <a href="https://vyasenov.github.io/blog/ci-residualized-reg.html">Frisch-Waugh-Lovell</a>,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Ctau_%7B%5Ctext%7BOLS%7D%7D%20=%20%5Cfrac%7B%5Cmathbb%7BE%7D%5BV_iY_i%5D%7D%7B%5Cmathbb%7BE%7D%5BV_iD_i%5D%7D,%0A%5Cqquad%0AV_i%20=%20D_i%20-%20%5Cmathbb%7BL%7D(D_i%5Cmid%20X_i),%0A"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BL%7D(D_i%5Cmid%20X_i)"> is the best linear predictor of <img src="https://latex.codecogs.com/png.latex?D_i"> using <img src="https://latex.codecogs.com/png.latex?X_i">. This expression is purely statistical.</p>
<p>The causal question is whether <img src="https://latex.codecogs.com/png.latex?%5Ctau_%7B%5Ctext%7BOLS%7D%7D"> coincides with a treatment effect parameter under additional assumptions.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="regression-is-a-projection-not-a-causal-model" class="level3">
<h3 class="anchored" data-anchor-id="regression-is-a-projection-not-a-causal-model">Regression Is a Projection, Not a Causal Model</h3>
<p>This is the first point I would emphasize in practice. Writing down</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AY_i%20=%20%5Calpha%20+%20%5Ctau%20D_i%20+%20X_i'%5Cbeta%20+%20u_i%0A"></p>
<p>does not, by itself, assume homogeneous treatment effects or even invoke potential outcomes. It simply defines the best linear predictor of <img src="https://latex.codecogs.com/png.latex?Y"> given <img src="https://latex.codecogs.com/png.latex?D"> and <img src="https://latex.codecogs.com/png.latex?X">. If the goal is prediction, that is the end of the story. (For a related distinction about what randomness this projection is defined over, see my note on <a href="https://vyasenov.github.io/blog/ols-fixed-random-x.html">OLS with fixed versus random <img src="https://latex.codecogs.com/png.latex?X"></a>.)</p>
<p>For causal interpretation, however, we need more. Under random assignment or selection on observables, plus enough structure on how outcomes vary with <img src="https://latex.codecogs.com/png.latex?X">, the projection coefficient may line up with a causal estimand. Under constant treatment effects and correct linear adjustment, that estimand is often the ATE. Once treatment effects vary with <img src="https://latex.codecogs.com/png.latex?X">, the coefficient generally becomes a weighted average of heterogeneous effects rather than the plain sample average.</p>
</section>
<section id="aronow-and-samii-asymptotic-view" class="level3">
<h3 class="anchored" data-anchor-id="aronow-and-samii-asymptotic-view">Aronow and Samii: Asymptotic View</h3>
<p>Aronow and Samii (2016) show that regression-adjusted estimators need not be representative of the sample as a whole. In large samples, the estimand targeted by regression can be written as a weighted average of conditional treatment effects, where the weights depend on how treatment assignment varies with covariates and on the linear adjustment built into the regression.</p>
<p>The key practical point is that OLS does not weight covariate strata equally. These weights are proportional to residualized treatment variation (via FWL), not to the precision of outcome estimates. In particular, they do not correspond to inverse-variance weights in general. So even under ignorability, the regression coefficient need not correspond to the ATE for the empirical covariate distribution. It is often better understood as an ATE for an implicit reweighted population. That is a subtle point, but it matters whenever overlap is uneven or the linear model fits some regions of the covariate space much better than others.</p>
</section>
<section id="chattopadhyay-and-zubizarreta-finite-sample-view" class="level3">
<h3 class="anchored" data-anchor-id="chattopadhyay-and-zubizarreta-finite-sample-view">Chattopadhyay and Zubizarreta: Finite-Sample View</h3>
<p>One limitation of the Aronow-Samii perspective is that it is asymptotic. Chattopadhyay and Zubizarreta (2023) go further by showing that common linear regression estimators admit exact finite-sample weighting representations. For a regression-adjusted ATE estimator,</p>
<p><img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7B%5Ctau%7D_%7B%5Ctext%7BOLS%7D%7D%20=%20%5Csum_%7Bi:D_i=1%7D%20w_i%5E%7B(1)%7DY_i%20-%20%5Csum_%7Bi:D_i=0%7D%20w_i%5E%7B(0)%7DY_i,%0A"></p>
<p>where the weights are functions of only <img src="https://latex.codecogs.com/png.latex?D"> and <img src="https://latex.codecogs.com/png.latex?X">, not the realized outcomes.</p>
<p>This is useful for two reasons. First, it makes regression adjustment look less mysterious: OLS is <a href="https://vyasenov.github.io/blog/two-types-weights-causality.html">implicitly constructing a weighted comparison</a> between treated and control outcomes. Second, the implied weights can be inspected directly. In their framework, the weights clarify when regression adjustment achieves exact balance on included covariates, how dispersed the weights are, and whether the regression is targeting a population that still looks like the observed sample. That is a much more practical diagnostic than simply reporting a coefficient table.</p>
</section>
<section id="słoczyński-heterogeneous-effects-view" class="level3">
<h3 class="anchored" data-anchor-id="słoczyński-heterogeneous-effects-view">Słoczyński: Heterogeneous Effects View</h3>
<p>Słoczyński (2022) asks what the OLS coefficient means when treatment effects are heterogeneous. His central result is that the coefficient on treatment is generally not the ATE. Instead, it is a convex combination of two group-specific effect parameters that, under additional conditions, can be interpreted as the ATT and the ATU. The striking part is the weighting: the smaller treatment arm gets the larger implicit weight.</p>
<p>So if treated units are rare, OLS tends to lean toward effects for treated units. If treated units are common, it leans toward effects for untreated units. The exact formula depends on the specification and on how treatment assignment varies with covariates, but the qualitative message is robust: heterogeneity changes the target, and OLS can overweight the effect for the smaller group.</p>
<p>This is one of those results that sounds surprising at first and obvious in hindsight. Regression learns treatment effects from residual variation in treatment status. When one group is small, comparisons involving that group carry disproportionate identifying content. The practical implication is straightforward: if you care specifically about the ATE or ATT, you should not assume OLS is giving it to you just because the regression includes controls.</p>
</section>
<section id="angrist-and-pischke-saturated-model-view" class="level3">
<h3 class="anchored" data-anchor-id="angrist-and-pischke-saturated-model-view">Angrist and Pischke: Saturated Model View</h3>
<p>The cleanest interpretation of regression comes from saturated models with discrete covariates, an approach emphasized by Angrist and coauthors. If <img src="https://latex.codecogs.com/png.latex?X"> takes only a small number of values and the regression fully saturates those cells, then OLS is just averaging within-cell treatment-control differences. In that case, regression is a dressed-up version of exact matching.</p>
<p>That perspective is helpful because it shows where the causal content comes from. The coefficient is credible when comparisons are being made within genuinely comparable covariate cells. But it also shows the limitation immediately: with continuous or high-dimensional covariates, literal saturation is impossible and the argument breaks down. At that point, OLS is no longer exact within-cell adjustment. It is a parametric approximation that extrapolates across covariate values. That is often reasonable, but it is no longer harmless.</p>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>OLS does not inherently estimate a causal effect. It estimates a linear projection coefficient that becomes causal only under additional assumptions.</li>
<li>Aronow and Samii show that regression adjustment targets a weighted causal estimand in large samples rather than automatically targeting the sample ATE.</li>
<li>Chattopadhyay and Zubizarreta make this weighting interpretation exact in finite samples and turn it into a useful diagnostic tool.</li>
<li>With heterogeneous treatment effects, Słoczyński shows that OLS becomes a weighted average of group-specific effects, often interpretable as ATT- and ATU-type objects, and the smaller treatment arm gets more weight.</li>
<li>Saturated regressions with discrete covariates are the clean benchmark. With continuous <img src="https://latex.codecogs.com/png.latex?X">, standard OLS necessarily relies on approximation and implicit weighting.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>Aronow and Samii (2016) is the right place to start if you want the representativeness argument behind regression adjustment. Chattopadhyay and Zubizarreta (2023) is the most useful paper for understanding exact implied weights in finite samples. Słoczyński (2022) is now the canonical reference on how heterogeneous treatment effects distort the interpretation of the OLS coefficient. For the saturated-regression perspective, I would still point readers to Angrist and Pischke (2009), which makes clear why exact matching logic breaks down once covariates become continuous.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Angrist, J. D., &amp; Pischke, J. S. (2009). Mostly harmless econometrics: An empiricist’s companion. <em>Princeton university press</em>.</p>
<p>Aronow, P. M., &amp; Samii, C. (2016). Does regression produce representative estimates of causal effects? <em>American Journal of Political Science</em>, 60(1), 250-267.</p>
<p>Chattopadhyay, A., &amp; Zubizarreta, J. R. (2023). On the implied weights of linear regression for causal inference. <em>Biometrika</em>, 110(3), 615-629.</p>
<p>Słoczyński, T. (2022). Interpreting OLS estimands when treatment effects are heterogeneous: Smaller groups get larger weights. <em>Review of Economics and Statistics</em>, 104(3), 501-509.</p>


</section>

 ]]></description>
  <category>causal inference</category>
  <category>parametric models</category>
  <guid>https://vyasenov.github.io/blog/interpret-OLS-causal-inference.html</guid>
  <pubDate>Wed, 01 Apr 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>The Many Flavors of Lasso</title>
  <link>https://vyasenov.github.io/blog/flavors-lasso.html</link>
  <description><![CDATA[ 





<div class="reading-time">9 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>The Lasso (Least Absolute Shrinkage and Selection Operator), introduced by Tibshirani in 1996, has become one of the go-to tools for <a href="https://vyasenov.github.io/blog/flavors-var-selection.html">variable selection</a> and shrinkage in regression problems. But the classic Lasso is just the starting point. Over the years, researchers have developed many variants of Lasso, each designed to address specific limitations or tailor the method to different kinds of data structures.</p>
<p>This article provides a tour of the most popular flavors of Lasso — from standard <img src="https://latex.codecogs.com/png.latex?%5Cell_1">-penalized regression to modern adaptations like Adaptive Lasso, Elastic Net, Square-root Lasso, and more. For each version, I’ll lay out the objective function, describe when it’s applicable, and summarize its key characteristics.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Before diving into the variants, let’s revisit what makes Lasso special. In a standard linear regression setup, we model <img src="https://latex.codecogs.com/png.latex?y%20=%20X%5Cbeta%20+%20%5Cepsilon,"></p>
<p>where:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?y"> is the outcome,</li>
<li><img src="https://latex.codecogs.com/png.latex?X"> is our design matrix,</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Cbeta"> are the coefficients, and</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Cepsilon"> is the error term.</li>
</ul>
<p>Traditional ordinary least squares (OLS) minimizes the sum of squared residuals without any constraint on the coefficients.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="standard-lasso" class="level3">
<h3 class="anchored" data-anchor-id="standard-lasso">Standard Lasso</h3>
<p>The standard Lasso solves the following optimization problem: <img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7B%5Cbeta%7D%20=%20%5Carg%20%5Cmin_%7B%5Cbeta%7D%20%5Cleft(%20%5Cfrac%7B1%7D%7B2n%7D%20%5C%7C%20y%20-%20X%20%5Cbeta%20%5C%7C_2%5E2%20+%20%5Clambda%20%5C%7C%20%5Cbeta%20%5C%7C_1%20%5Cright)%0A"></p>
<p>The appeal of Lasso is straightforward: it trades a convex penalty for exact zeros in the solution. In moderately high dimensions, this often works surprisingly well as a first pass.</p>
<p>The main issue shows up when predictors are correlated. Lasso will typically pick one variable from a correlated group and ignore the rest, and which one it picks can be unstable across folds or small perturbations of the data. At the same time, all coefficients are <a href="https://vyasenov.github.io/blog/paradox-stein.html">shrunk</a>, including the large ones, which introduces bias that doesn’t go away even with large samples.</p>
<p>In practice, I treat standard Lasso as a baseline rather than a final model. If it’s stable and predictive, great. If not, it’s usually pointing to a structural issue in the design.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(glmnet)</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulate data</span></span>
<span id="cb1-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb1-5">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb1-6">p <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span></span>
<span id="cb1-7">X <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p), n, p)</span>
<span id="cb1-8">beta_true <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, p <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>))  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Only 3 non-zero coefficients</span></span>
<span id="cb1-9">y <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> X <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> beta_true <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n)</span>
<span id="cb1-10"></span>
<span id="cb1-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit standard Lasso</span></span>
<span id="cb1-12">lasso_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glmnet</span>(X, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># alpha = 1 for Lasso</span></span>
<span id="cb1-13"></span>
<span id="cb1-14"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Cross-validation to select lambda</span></span>
<span id="cb1-15">cv_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cv.glmnet</span>(X, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-16">lambda_opt <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> cv_fit<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>lambda.min</span>
<span id="cb1-17"></span>
<span id="cb1-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Get coefficients at optimal lambda</span></span>
<span id="cb1-19"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(cv_fit, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">s =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda.min"</span>)</span></code></pre></div></div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Lasso, LassoCV</span>
<span id="cb2-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.datasets <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> make_regression</span>
<span id="cb2-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb2-4"></span>
<span id="cb2-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulate data</span></span>
<span id="cb2-6">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb2-7">X, y, coef_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> make_regression(n_samples<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, n_features<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>, </span>
<span id="cb2-8">                                   n_informative<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, coef<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, </span>
<span id="cb2-9">                                   noise<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb2-10"></span>
<span id="cb2-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit Lasso with cross-validation</span></span>
<span id="cb2-12">lasso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LassoCV(cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, random_state<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb2-13">lasso.fit(X, y)</span>
<span id="cb2-14"></span>
<span id="cb2-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Display results</span></span>
<span id="cb2-16"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Optimal lambda: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>lasso<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>alpha_<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb2-17"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Number of non-zero coefficients: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(lasso.coef_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb2-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Selected coefficients:</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>lasso<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>coef_[lasso.coef_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="adaptive-lasso" class="level3">
<h3 class="anchored" data-anchor-id="adaptive-lasso">Adaptive Lasso</h3>
<p>Adaptive Lasso extends the standard Lasso by using data-driven weights for each coefficient: <img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7B%5Cbeta%7D%20=%20%5Carg%20%5Cmin_%7B%5Cbeta%7D%20%5Cleft(%20%5Cfrac%7B1%7D%7B2n%7D%20%5C%7C%20y%20-%20X%20%5Cbeta%20%5C%7C_2%5E2%20+%20%5Clambda%20%5Csum_%7Bj=1%7D%5Ep%20w_j%20%7C%20%5Cbeta_j%20%7C%20%5Cright)%0A"> where <img src="https://latex.codecogs.com/png.latex?w_j%20=%201%20/%20%7C%5Chat%7B%5Cbeta%7D_j%5E%7B%5Ctext%7Binit%7D%7D%7C%5E%5Cgamma"> and <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Cbeta%7D_j%5E%7B%5Ctext%7Binit%7D%7D"> comes from an initial estimator like OLS or Ridge.</p>
<p>The idea here is to penalize coefficients unevenly. Variables that look important in a first-stage model get penalized less, while weaker ones get pushed harder toward zero. This reduces the bias on large coefficients and improves variable selection consistency under certain conditions—one of the ingredients of the <a href="https://vyasenov.github.io/blog/oracle-property.html">oracle property</a>.</p>
<p>In practice, Adaptive Lasso is less about prediction and more about recovering a meaningful support. If you care about which variables are selected—not just the predictive accuracy—it’s often worth the extra step.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-2-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-1" aria-controls="tabset-2-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-2-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-2-2" aria-controls="tabset-2-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-2-1" class="tab-pane active" aria-labelledby="tabset-2-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Continue from previous example</span></span>
<span id="cb3-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(glmnet)</span>
<span id="cb3-3"></span>
<span id="cb3-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Step 1: Get initial estimates using Ridge</span></span>
<span id="cb3-5">ridge_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glmnet</span>(X, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># alpha = 0 for Ridge</span></span>
<span id="cb3-6">cv_ridge <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cv.glmnet</span>(X, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb3-7">beta_init <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">as.vector</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(cv_ridge, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">s =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda.min"</span>))[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Remove intercept</span></span>
<span id="cb3-8"></span>
<span id="cb3-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Step 2: Compute adaptive weights</span></span>
<span id="cb3-10">gamma <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Common choice</span></span>
<span id="cb3-11">weights <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abs</span>(beta_init) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-8</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">^</span>gamma  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add small constant to avoid division by zero</span></span>
<span id="cb3-12"></span>
<span id="cb3-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Step 3: Fit Adaptive Lasso</span></span>
<span id="cb3-14">adaptive_lasso <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glmnet</span>(X, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">penalty.factor =</span> weights)</span>
<span id="cb3-15">cv_adaptive <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cv.glmnet</span>(X, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">penalty.factor =</span> weights)</span>
<span id="cb3-16"></span>
<span id="cb3-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compare coefficients</span></span>
<span id="cb3-18"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Standard Lasso non-zero:"</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(cv_fit, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">s =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda.min"</span>)[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb3-19"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Adaptive Lasso non-zero:"</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(cv_adaptive, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">s =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda.min"</span>)[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
</div>
<div id="tabset-2-2" class="tab-pane" aria-labelledby="tabset-2-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Ridge, Lasso</span>
<span id="cb4-2"></span>
<span id="cb4-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Step 1: Get initial estimates using Ridge</span></span>
<span id="cb4-4">ridge <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Ridge(alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>)</span>
<span id="cb4-5">ridge.fit(X, y)</span>
<span id="cb4-6">beta_init <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ridge.coef_</span>
<span id="cb4-7"></span>
<span id="cb4-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Step 2: Compute adaptive weights</span></span>
<span id="cb4-9">gamma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb4-10">weights <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> (np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(beta_init) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-8</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span>gamma</span>
<span id="cb4-11"></span>
<span id="cb4-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Step 3: Fit Adaptive Lasso (manual implementation via weighted penalty)</span></span>
<span id="cb4-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Scale features by weights</span></span>
<span id="cb4-14">X_weighted <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> weights</span>
<span id="cb4-15"></span>
<span id="cb4-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit Lasso on weighted features</span></span>
<span id="cb4-17">adaptive_lasso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Lasso(alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb4-18">adaptive_lasso.fit(X_weighted, y)</span>
<span id="cb4-19"></span>
<span id="cb4-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Transform back to original scale</span></span>
<span id="cb4-21">adaptive_coef <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> adaptive_lasso.coef_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> weights</span>
<span id="cb4-22"></span>
<span id="cb4-23"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Standard Lasso non-zero: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(lasso.coef_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb4-24"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Adaptive Lasso non-zero: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(adaptive_coef <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="relaxed-lasso" class="level3">
<h3 class="anchored" data-anchor-id="relaxed-lasso">Relaxed Lasso</h3>
<p>Relaxed Lasso separates selection from estimation. First, run Lasso to pick variables; then refit on that subset, either with OLS or partial shrinkage via a parameter <img src="https://latex.codecogs.com/png.latex?%5Cphi%20%5Cin%20%5B0,1%5D">. At <img src="https://latex.codecogs.com/png.latex?%5Cphi=0"> you recover Lasso, and at <img src="https://latex.codecogs.com/png.latex?%5Cphi=1"> you get post-selection OLS.</p>
<p>The point is to reduce shrinkage bias. Lasso is good at finding the support but tends to underestimate large coefficients. Relaxing the penalty after selection keeps sparsity while improving estimates.</p>
<p>In practice, this works well when you trust the selected variables but want better coefficient accuracy. The main risk is overfitting if too many variables are selected, so it’s worth tuning both <img src="https://latex.codecogs.com/png.latex?%5Clambda"> and <img src="https://latex.codecogs.com/png.latex?%5Cphi">.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-3-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-1" aria-controls="tabset-3-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-3-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-3-2" aria-controls="tabset-3-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-3-1" class="tab-pane active" aria-labelledby="tabset-3-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(glmnet)</span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(relaxnet)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># For relaxed Lasso</span></span>
<span id="cb5-3"></span>
<span id="cb5-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit relaxed Lasso using glmnet (has built-in support)</span></span>
<span id="cb5-5">relaxed_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glmnet</span>(X, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">relax =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb5-6">cv_relaxed <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cv.glmnet</span>(X, y, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">relax =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)</span>
<span id="cb5-7"></span>
<span id="cb5-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Manual two-stage approach</span></span>
<span id="cb5-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Stage 1: Standard Lasso selection</span></span>
<span id="cb5-10">lasso_coef <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(cv_fit, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">s =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda.min"</span>)[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb5-11">selected <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">which</span>(lasso_coef <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb5-12"></span>
<span id="cb5-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Stage 2: OLS on selected variables</span></span>
<span id="cb5-14"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(selected) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) {</span>
<span id="cb5-15">  X_selected <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> X[, selected]</span>
<span id="cb5-16">  ols_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lm</span>(y <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> X_selected)</span>
<span id="cb5-17">  </span>
<span id="cb5-18">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compare coefficients</span></span>
<span id="cb5-19">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lasso coefficients (selected):</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-20">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(lasso_coef[selected])</span>
<span id="cb5-21">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">Relaxed (OLS) coefficients:</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb5-22">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(ols_fit)[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb5-23">}</span></code></pre></div></div>
</div>
<div id="tabset-3-2" class="tab-pane" aria-labelledby="tabset-3-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Manual two-stage relaxed Lasso</span></span>
<span id="cb6-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LinearRegression</span>
<span id="cb6-3"></span>
<span id="cb6-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Stage 1: Lasso selection</span></span>
<span id="cb6-5">lasso_coef <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> lasso.coef_</span>
<span id="cb6-6">selected <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.where(lasso_coef <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb6-7"></span>
<span id="cb6-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Lasso selected </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(selected)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> variables"</span>)</span>
<span id="cb6-9"></span>
<span id="cb6-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Stage 2: OLS on selected variables</span></span>
<span id="cb6-11"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(selected) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>:</span>
<span id="cb6-12">    X_selected <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X[:, selected]</span>
<span id="cb6-13">    ols <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LinearRegression()</span>
<span id="cb6-14">    ols.fit(X_selected, y)</span>
<span id="cb6-15">    </span>
<span id="cb6-16">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compare coefficient magnitudes</span></span>
<span id="cb6-17">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">Lasso coefficients (mean abs): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(lasso_coef[selected])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb6-18">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Relaxed coefficients (mean abs): </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(ols.coef_)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>mean()<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.4f}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb6-19">    </span>
<span id="cb6-20">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Often relaxed coefficients are larger in magnitude</span></span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="square-root-lasso" class="level3">
<h3 class="anchored" data-anchor-id="square-root-lasso">Square-root Lasso</h3>
<p>Square-root Lasso, also known as Scaled Lasso, modifies the objective function to: <img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7B%5Cbeta%7D%20=%20%5Carg%20%5Cmin_%7B%5Cbeta%7D%20%5Cleft(%20%5Cfrac%7B1%7D%7B%5Csqrt%7Bn%7D%7D%20%5C%7C%20y%20-%20X%20%5Cbeta%20%5C%7C_2%20+%20%5Clambda%20%5C%7C%20%5Cbeta%20%5C%7C_1%20%5Cright)%0A"></p>
<p>The crucial difference from standard Lasso is using the <img src="https://latex.codecogs.com/png.latex?%5Cell_2"> norm directly (without squaring) in the loss term. This seemingly small change has important consequences: the estimator becomes scale-invariant, meaning you don’t need to estimate or know the error variance <img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2"> to set the penalty parameter <img src="https://latex.codecogs.com/png.latex?%5Clambda"> appropriately. In standard Lasso, the optimal choice of <img src="https://latex.codecogs.com/png.latex?%5Clambda"> depends on the unknown noise level, but square-root Lasso eliminates this dependence.</p>
<p>This variant is particularly valuable when you have unknown or heteroskedastic error variance, making it robust to variance misspecification. The scale-invariance also simplifies tuning: you can use theoretically-motivated choices for <img src="https://latex.codecogs.com/png.latex?%5Clambda"> without prior knowledge of the noise level. In practice, this often translates to more stable selection across different datasets and makes the method especially appealing in settings where variance estimation is challenging or the homoskedasticity assumption is questionable.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-4-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-4-1" aria-controls="tabset-4-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-4-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-4-2" aria-controls="tabset-4-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-4-1" class="tab-pane active" aria-labelledby="tabset-4-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(scalreg)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># For square-root Lasso</span></span>
<span id="cb7-2"></span>
<span id="cb7-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit square-root Lasso</span></span>
<span id="cb7-4">sqrt_lasso <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">scalreg</span>(X, y)</span>
<span id="cb7-5"></span>
<span id="cb7-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compare with standard Lasso</span></span>
<span id="cb7-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Standard Lasso selected:"</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(cv_fit, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">s =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda.min"</span>)[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"variables</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb7-8"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Square-root Lasso selected:"</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(sqrt_lasso<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>coefficients <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"variables</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
</div>
<div id="tabset-4-2" class="tab-pane" aria-labelledby="tabset-4-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Square-root Lasso is not in sklearn, but we can implement a simple version</span></span>
<span id="cb8-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> LassoLars</span>
<span id="cb8-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> scipy.optimize <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> minimize</span>
<span id="cb8-4"></span>
<span id="cb8-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Manual implementation using CVXPY (if available)</span></span>
<span id="cb8-6"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">try</span>:</span>
<span id="cb8-7">    <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> cvxpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> cp</span>
<span id="cb8-8">    </span>
<span id="cb8-9">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define variables</span></span>
<span id="cb8-10">    beta <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cp.Variable(X.shape[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb8-11">    </span>
<span id="cb8-12">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define objective: ||y - X*beta||_2 + lambda * ||beta||_1</span></span>
<span id="cb8-13">    lambda_sqrt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span></span>
<span id="cb8-14">    objective <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cp.Minimize(cp.norm(y <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> X <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> beta, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> lambda_sqrt <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> cp.norm(beta, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>))</span>
<span id="cb8-15">    </span>
<span id="cb8-16">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Solve</span></span>
<span id="cb8-17">    prob <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> cp.Problem(objective)</span>
<span id="cb8-18">    prob.solve()</span>
<span id="cb8-19">    </span>
<span id="cb8-20">    sqrt_lasso_coef <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> beta.value</span>
<span id="cb8-21">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Square-root Lasso selected </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(sqrt_lasso_coef) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1e-6</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> variables"</span>)</span>
<span id="cb8-22">    </span>
<span id="cb8-23"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">except</span> <span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">ImportError</span>:</span>
<span id="cb8-24">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Square-root Lasso requires cvxpy package"</span>)</span>
<span id="cb8-25">    <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Install with: pip install cvxpy"</span>)</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="elastic-net" class="level3">
<h3 class="anchored" data-anchor-id="elastic-net">Elastic Net</h3>
<p>Elastic Net blends <img src="https://latex.codecogs.com/png.latex?%5Cell_1"> and <img src="https://latex.codecogs.com/png.latex?%5Cell_2"> regularization by minimizing: <img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7B%5Cbeta%7D%20=%20%5Carg%20%5Cmin_%7B%5Cbeta%7D%20%5Cleft(%20%5Cfrac%7B1%7D%7B2n%7D%20%5C%7C%20y%20-%20X%20%5Cbeta%20%5C%7C_2%5E2%20+%20%5Clambda_1%20%5C%7C%20%5Cbeta%20%5C%7C_1%20+%20%5Clambda_2%20%5C%7C%20%5Cbeta%20%5C%7C_2%5E2%20%5Cright)%0A"></p>
<p>This is often reparametrized as <img src="https://latex.codecogs.com/png.latex?%5Clambda%20%5Cleft%5B%20%5Calpha%20%5C%7C%20%5Cbeta%20%5C%7C_1%20+%20(1-%5Calpha)%20%5C%7C%20%5Cbeta%20%5C%7C_2%5E2%20%5Cright%5D"> where <img src="https://latex.codecogs.com/png.latex?%5Calpha%20%5Cin%20%5B0,1%5D"> controls the mixing between <img src="https://latex.codecogs.com/png.latex?%5Cell_1"> and <img src="https://latex.codecogs.com/png.latex?%5Cell_2"> penalties.</p>
<p>Elastic Net fixes a key issue with Lasso: when predictors are highly correlated, Lasso tends to pick one arbitrarily and ignore the rest. Adding an <img src="https://latex.codecogs.com/png.latex?%5Cell_2"> penalty induces a grouping effect, so correlated variables enter or leave together, while the <img src="https://latex.codecogs.com/png.latex?%5Cell_1"> term still enforces sparsity.</p>
<p>This makes it a better default in settings with multicollinearity—common in practice. The mixing parameter <img src="https://latex.codecogs.com/png.latex?%5Calpha"> controls the trade-off: closer to 1 behaves like Lasso, closer to <img src="https://latex.codecogs.com/png.latex?0"> like Ridge. In practice, moderate values (e.g.&nbsp;<img src="https://latex.codecogs.com/png.latex?0.5">) work well, with cross-validation refining the choice.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-5-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-5-1" aria-controls="tabset-5-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-5-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-5-2" aria-controls="tabset-5-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-5-1" class="tab-pane active" aria-labelledby="tabset-5-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(glmnet)</span>
<span id="cb9-2"></span>
<span id="cb9-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create correlated predictors to demonstrate Elastic Net advantage</span></span>
<span id="cb9-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb9-5">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb9-6">X_base <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>), n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb9-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add correlated predictors</span></span>
<span id="cb9-8">X_corr <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(X_base, X_base[, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">sd =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>), n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span>
<span id="cb9-9">beta_true <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.2</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.3</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># True coefficients for correlated pairs</span></span>
<span id="cb9-10">y_corr <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> X_corr <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> beta_true <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n)</span>
<span id="cb9-11"></span>
<span id="cb9-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit Elastic Net with alpha = 0.5 (equal mix of $\ell_1$ and $\ell_2$)</span></span>
<span id="cb9-13">elastic_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cv.glmnet</span>(X_corr, y_corr, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>)</span>
<span id="cb9-14"></span>
<span id="cb9-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compare with pure Lasso (alpha = 1)</span></span>
<span id="cb9-16">lasso_corr <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cv.glmnet</span>(X_corr, y_corr, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">alpha =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb9-17"></span>
<span id="cb9-18"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Elastic Net coefficients:</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb9-19"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(elastic_fit, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">s =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda.min"</span>))</span>
<span id="cb9-20"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">Lasso coefficients:</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb9-21"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(lasso_corr, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">s =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda.min"</span>))</span></code></pre></div></div>
</div>
<div id="tabset-5-2" class="tab-pane" aria-labelledby="tabset-5-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> ElasticNet, ElasticNetCV</span>
<span id="cb10-2"></span>
<span id="cb10-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create correlated predictors</span></span>
<span id="cb10-4">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb10-5">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb10-6">X_base <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb10-7">X_corr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.hstack([X_base, X_base[:, :<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>])</span>
<span id="cb10-8">beta_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.2</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.3</span>])</span>
<span id="cb10-9">y_corr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_corr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> beta_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n)</span>
<span id="cb10-10"></span>
<span id="cb10-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit Elastic Net with l1_ratio = 0.5 (equal mix)</span></span>
<span id="cb10-12">elastic <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ElasticNetCV(l1_ratio<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb10-13">elastic.fit(X_corr, y_corr)</span>
<span id="cb10-14"></span>
<span id="cb10-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compare with Lasso</span></span>
<span id="cb10-16">lasso_corr <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> LassoCV(cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb10-17">lasso_corr.fit(X_corr, y_corr)</span>
<span id="cb10-18"></span>
<span id="cb10-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Elastic Net coefficients:"</span>)</span>
<span id="cb10-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(elastic.coef_)</span>
<span id="cb10-21"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">Elastic Net selected </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(elastic.coef_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> variables"</span>)</span>
<span id="cb10-22"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Lasso selected </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(lasso_corr.coef_ <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;"> variables"</span>)</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="group-lasso" class="level3">
<h3 class="anchored" data-anchor-id="group-lasso">Group Lasso</h3>
<p>Group Lasso extends the <img src="https://latex.codecogs.com/png.latex?%5Cell_1"> penalty to operate on predefined groups of variables: <img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7B%5Cbeta%7D%20=%20%5Carg%20%5Cmin_%7B%5Cbeta%7D%20%5Cleft(%20%5Cfrac%7B1%7D%7B2n%7D%20%5C%7C%20y%20-%20X%20%5Cbeta%20%5C%7C_2%5E2%20+%20%5Clambda%20%5Csum_%7Bg=1%7D%5EG%20%5C%7C%20%5Cbeta%5E%7B(g)%7D%20%5C%7C_2%20%5Cright)%0A"> where <img src="https://latex.codecogs.com/png.latex?%5Cbeta%5E%7B(g)%7D"> represents the coefficients belonging to group <img src="https://latex.codecogs.com/png.latex?g">, and <img src="https://latex.codecogs.com/png.latex?%5C%7C%20%5Ccdot%20%5C%7C_2"> is the <img src="https://latex.codecogs.com/png.latex?%5Cell_2"> norm applied within each group.</p>
<p>The key insight is that the <img src="https://latex.codecogs.com/png.latex?%5Cell_2"> norm within groups combined with summation across groups creates a sparsity-inducing penalty at the group level. Either all coefficients in a group are set to zero, or all are kept (though possibly shrunk). This “all or nothing” behavior respects the natural grouping structure in your data.</p>
<p>Group Lasso is useful when variables come in meaningful groups. A common example is categorical features encoded as dummies—you usually want to include or exclude the whole variable, not individual levels. Similar structure appears in multi-task settings or grouped scientific measurements.</p>
<p>Instead of sparsity at the coefficient level, Group Lasso selects entire groups while allowing dense coefficients within them. This makes the model align better with how features are constructed.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-6-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-6-1" aria-controls="tabset-6-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-6-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-6-2" aria-controls="tabset-6-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-6-1" class="tab-pane active" aria-labelledby="tabset-6-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb11-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(grpreg)</span>
<span id="cb11-2"></span>
<span id="cb11-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create data with natural groups</span></span>
<span id="cb11-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Suppose we have 3 categorical variables with 3, 4, and 5 levels</span></span>
<span id="cb11-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb11-6">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb11-7">X1 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">model.matrix</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb11-8">X2 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">model.matrix</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb11-9">X3 <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">model.matrix</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">factor</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb11-10">X_grouped <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cbind</span>(X1, X2, X3)</span>
<span id="cb11-11"></span>
<span id="cb11-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Define groups (which columns belong to which group)</span></span>
<span id="cb11-13">groups <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb11-14"></span>
<span id="cb11-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># True model: only group 1 and 3 are relevant</span></span>
<span id="cb11-16">beta_true <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>), <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb11-17">y_grouped <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> X_grouped <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> beta_true <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n)</span>
<span id="cb11-18"></span>
<span id="cb11-19"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit Group Lasso</span></span>
<span id="cb11-20">group_lasso <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cv.grpreg</span>(X_grouped, y_grouped, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">group =</span> groups, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">penalty =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"grLasso"</span>)</span>
<span id="cb11-21"></span>
<span id="cb11-22"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Group Lasso coefficients by group:</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span>
<span id="cb11-23">coefs <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(group_lasso, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">s =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"lambda.min"</span>)[<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb11-24"><span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> (g <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unique</span>(groups)) {</span>
<span id="cb11-25">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cat</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sprintf</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Group %d: %d non-zero out of %d</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>, </span>
<span id="cb11-26">              g, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(coefs[groups <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> g] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sum</span>(groups <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> g)))</span>
<span id="cb11-27">}</span></code></pre></div></div>
</div>
<div id="tabset-6-2" class="tab-pane" aria-labelledby="tabset-6-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> MultiTaskLasso</span>
<span id="cb12-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Note: True group Lasso requires specialized packages</span></span>
<span id="cb12-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># We'll demonstrate with a simplified example</span></span>
<span id="cb12-4"></span>
<span id="cb12-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulate grouped structure</span></span>
<span id="cb12-6">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb12-7">n <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb12-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create 3 groups with 3, 4, 5 features each</span></span>
<span id="cb12-9">X_grouped <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(n, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span>)</span>
<span id="cb12-10">groups <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>])</span>
<span id="cb12-11"></span>
<span id="cb12-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># True coefficients (group 1 and 3 active, group 2 zero)</span></span>
<span id="cb12-13">beta_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.array([<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.2</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>])</span>
<span id="cb12-14">y_grouped <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_grouped <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> beta_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n)</span>
<span id="cb12-15"></span>
<span id="cb12-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># For true Group Lasso, would need package like 'group-lasso' or 'celer'</span></span>
<span id="cb12-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Here we show conceptual grouping with manual implementation</span></span>
<span id="cb12-18"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"For Python Group Lasso, install specialized packages:"</span>)</span>
<span id="cb12-19"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  pip install group-lasso"</span>)</span>
<span id="cb12-20"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  pip install celer"</span>)</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="fused-lasso" class="level3">
<h3 class="anchored" data-anchor-id="fused-lasso">Fused Lasso</h3>
<p>Fused Lasso adds a penalty on differences between adjacent coefficients: <img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7B%5Cbeta%7D%20=%20%5Carg%20%5Cmin_%7B%5Cbeta%7D%20%5Cleft(%20%5Cfrac%7B1%7D%7B2n%7D%20%5C%7C%20y%20-%20X%20%5Cbeta%20%5C%7C_2%5E2%20+%20%5Clambda_1%20%5C%7C%20%5Cbeta%20%5C%7C_1%20+%20%5Clambda_2%20%5Csum_%7Bj=2%7D%5Ep%20%7C%20%5Cbeta_j%20-%20%5Cbeta_%7Bj-1%7D%20%7C%20%5Cright)%0A"></p>
<p>This method introduces two types of penalties: the standard <img src="https://latex.codecogs.com/png.latex?%5Cell_1"> penalty <img src="https://latex.codecogs.com/png.latex?%5Clambda_1%20%5C%7C%20%5Cbeta%20%5C%7C_1"> encourages overall sparsity (setting coefficients to zero), while the fusion penalty <img src="https://latex.codecogs.com/png.latex?%5Clambda_2%20%5Csum_%7Bj=2%7D%5Ep%20%7C%20%5Cbeta_j%20-%20%5Cbeta_%7Bj-1%7D%20%7C"> encourages adjacent coefficients to be equal. The fusion penalty means that nearby coefficients in the ordering are pulled toward each other, creating piecewise-constant patterns in the coefficient profile.</p>
<p>Fused Lasso is useful when features have a natural ordering and coefficients are expected to vary smoothly or in blocks. Instead of treating coefficients independently, it encourages both sparsity and similarity between neighbors, leading to piecewise-constant patterns.</p>
<p>This shows up in time series, spatial data, or ordered genomic features. The two penalties control the trade-off: <img src="https://latex.codecogs.com/png.latex?%5Clambda_1"> drives sparsity, while <img src="https://latex.codecogs.com/png.latex?%5Clambda_2"> controls how strongly adjacent coefficients are fused.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-7-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-7-1" aria-controls="tabset-7-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-7-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-7-2" aria-controls="tabset-7-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-7-1" class="tab-pane active" aria-labelledby="tabset-7-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(genlasso)</span>
<span id="cb13-2"></span>
<span id="cb13-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulate data with ordered features (e.g., time series or spatial)</span></span>
<span id="cb13-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb13-5">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb13-6">p <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span></span>
<span id="cb13-7"></span>
<span id="cb13-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create design matrix with ordered features</span></span>
<span id="cb13-9">X_ordered <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> p), n, p)</span>
<span id="cb13-10"></span>
<span id="cb13-11"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># True coefficients with piecewise constant structure</span></span>
<span id="cb13-12">beta_true <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>), <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb13-13">y_ordered <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> X_ordered <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">%*%</span> beta_true <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rnorm</span>(n)</span>
<span id="cb13-14"></span>
<span id="cb13-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit Fused Lasso</span></span>
<span id="cb13-16">fused_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fusedlasso</span>(y_ordered, X_ordered)</span>
<span id="cb13-17"></span>
<span id="cb13-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Get coefficients at a specific lambda</span></span>
<span id="cb13-19">lambda_idx <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Example index</span></span>
<span id="cb13-20">coefs_fused <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">coef</span>(fused_fit, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lambda =</span> fused_fit<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>lambda[lambda_idx])<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>beta</span>
<span id="cb13-21"></span>
<span id="cb13-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Visualize coefficient profile</span></span>
<span id="cb13-23"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(coefs_fused, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">type =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"s"</span>, </span>
<span id="cb13-24">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">main =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Fused Lasso Coefficient Profile"</span>,</span>
<span id="cb13-25">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">xlab =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Feature Index"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">ylab =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Coefficient"</span>,</span>
<span id="cb13-26">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"blue"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lwd =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb13-27"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">lines</span>(beta_true, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"red"</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lty =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lwd =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb13-28"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">legend</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"topright"</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Estimated"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"True"</span>), </span>
<span id="cb13-29">       <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">col =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"blue"</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"red"</span>), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">lty =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>))</span></code></pre></div></div>
</div>
<div id="tabset-7-2" class="tab-pane" aria-labelledby="tabset-7-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fused Lasso implementation using sklearn and custom penalty</span></span>
<span id="cb14-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.linear_model <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> Lasso</span>
<span id="cb14-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb14-4"></span>
<span id="cb14-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulate ordered features</span></span>
<span id="cb14-6">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb14-7">n, p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span></span>
<span id="cb14-8">X_ordered <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.randn(n, p)</span>
<span id="cb14-9"></span>
<span id="cb14-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Piecewise constant true coefficients</span></span>
<span id="cb14-11">beta_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.concatenate([</span>
<span id="cb14-12">    np.zeros(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>), np.full(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">15</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>), np.zeros(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>), </span>
<span id="cb14-13">    np.full(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.5</span>), np.zeros(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb14-14">])</span>
<span id="cb14-15">y_ordered <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> X_ordered <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">@</span> beta_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> np.random.randn(n)</span>
<span id="cb14-16"></span>
<span id="cb14-17"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Standard Lasso (for comparison)</span></span>
<span id="cb14-18">lasso_ordered <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Lasso(alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)</span>
<span id="cb14-19">lasso_ordered.fit(X_ordered, y_ordered)</span>
<span id="cb14-20"></span>
<span id="cb14-21"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># For true Fused Lasso, specialized packages needed</span></span>
<span id="cb14-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Conceptual visualization</span></span>
<span id="cb14-23">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb14-24">plt.plot(beta_true, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'r--'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'True'</span>, linewidth<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb14-25">plt.plot(lasso_ordered.coef_, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'b-'</span>, label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Standard Lasso'</span>, alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.7</span>)</span>
<span id="cb14-26">plt.xlabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Feature Index'</span>)</span>
<span id="cb14-27">plt.ylabel(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Coefficient Value'</span>)</span>
<span id="cb14-28">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Coefficient Profile: Fused Lasso Encourages Piecewise Constant Structure'</span>)</span>
<span id="cb14-29">plt.legend()</span>
<span id="cb14-30">plt.grid(alpha<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span>)</span>
<span id="cb14-31">plt.show()</span>
<span id="cb14-32"></span>
<span id="cb14-33"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"For true Fused Lasso in Python, consider packages:"</span>)</span>
<span id="cb14-34"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  skfda (functional data analysis)"</span>)</span>
<span id="cb14-35"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"  or implement using cvxpy with fusion penalty"</span>)</span></code></pre></div></div>
</div>
</div>
</div>
</section>
<section id="graphical-lasso" class="level3">
<h3 class="anchored" data-anchor-id="graphical-lasso">Graphical Lasso</h3>
<p>Graphical Lasso applies <img src="https://latex.codecogs.com/png.latex?%5Cell_1"> penalization to the estimation of precision matrices (inverse covariance matrices): <img src="https://latex.codecogs.com/png.latex?%0A%5Chat%7B%5CTheta%7D%20=%20%5Carg%20%5Cmin_%7B%5CTheta%20%5Csucc%200%7D%20%5Cleft(%20-%5Clog%20%5Cdet%20%5CTheta%20+%20%5Ctext%7Btrace%7D(S%20%5CTheta)%20+%20%5Clambda%20%5C%7C%20%5CTheta%20%5C%7C_1%20%5Cright)%0A"> where <img src="https://latex.codecogs.com/png.latex?%5CTheta"> is the precision matrix, <img src="https://latex.codecogs.com/png.latex?S"> is the sample covariance matrix, and <img src="https://latex.codecogs.com/png.latex?%5CTheta%20%5Csucc%200"> ensures positive definiteness.</p>
<p>Graphical Lasso shifts the focus from regression to covariance structure, estimating a sparse precision matrix. A zero entry <img src="https://latex.codecogs.com/png.latex?%5CTheta_%7Bij%7D%20=%200"> means variables <img src="https://latex.codecogs.com/png.latex?i"> and <img src="https://latex.codecogs.com/png.latex?j"> are conditionally independent given the rest, so the model directly encodes a network of relationships.</p>
<p>This is useful when the goal is to recover dependency structure rather than predict an outcome—common in genomics, finance, or neuroscience. The <img src="https://latex.codecogs.com/png.latex?%5Cell_1"> penalty enforces sparsity, leading to interpretable graphs where most connections are absent. In practice, the main challenge is tuning <img src="https://latex.codecogs.com/png.latex?%5Clambda"> to balance fit and sparsity.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-8-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-8-1" aria-controls="tabset-8-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-8-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-8-2" aria-controls="tabset-8-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-8-1" class="tab-pane active" aria-labelledby="tabset-8-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb15-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(glasso)</span>
<span id="cb15-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">library</span>(igraph)</span>
<span id="cb15-3"></span>
<span id="cb15-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulate multivariate data</span></span>
<span id="cb15-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb15-6">n <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span></span>
<span id="cb15-7">p <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span></span>
<span id="cb15-8"></span>
<span id="cb15-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create a sparse precision matrix (true network structure)</span></span>
<span id="cb15-10">Theta_true <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">matrix</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, p, p)</span>
<span id="cb15-11"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">diag</span>(Theta_true) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb15-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Add some conditional dependencies</span></span>
<span id="cb15-13">Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb15-14">Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span></span>
<span id="cb15-15">Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span></span>
<span id="cb15-16">Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">8</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>] <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span></span>
<span id="cb15-17"></span>
<span id="cb15-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generate data from this precision matrix</span></span>
<span id="cb15-19">Sigma <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">solve</span>(Theta_true)</span>
<span id="cb15-20">X_network <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> MASS<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mvrnorm</span>(n, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mu =</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rep</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, p), <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">Sigma =</span> Sigma)</span>
<span id="cb15-21"></span>
<span id="cb15-22"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Compute sample covariance</span></span>
<span id="cb15-23">S <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cov</span>(X_network)</span>
<span id="cb15-24"></span>
<span id="cb15-25"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit Graphical Lasso</span></span>
<span id="cb15-26">glasso_fit <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">glasso</span>(S, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rho =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.1</span>)  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># rho is the penalty parameter</span></span>
<span id="cb15-27"></span>
<span id="cb15-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Extract estimated precision matrix</span></span>
<span id="cb15-29">Theta_est <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> glasso_fit<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span>wi</span>
<span id="cb15-30"></span>
<span id="cb15-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Visualize network</span></span>
<span id="cb15-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create adjacency matrix (thresholded)</span></span>
<span id="cb15-33">adj_matrix <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> (<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">abs</span>(Theta_est) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb15-34"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">diag</span>(adj_matrix) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span></span>
<span id="cb15-35"></span>
<span id="cb15-36"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot network</span></span>
<span id="cb15-37">graph_obj <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">graph_from_adjacency_matrix</span>(adj_matrix, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">mode =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"undirected"</span>)</span>
<span id="cb15-38"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>(graph_obj, </span>
<span id="cb15-39">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">main =</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Estimated Conditional Dependence Network"</span>,</span>
<span id="cb15-40">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">vertex.size =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">20</span>,</span>
<span id="cb15-41">     <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">vertex.label.cex =</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.8</span>)</span></code></pre></div></div>
</div>
<div id="tabset-8-2" class="tab-pane" aria-labelledby="tabset-8-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">from</span> sklearn.covariance <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> GraphicalLassoCV</span>
<span id="cb16-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> networkx <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> nx</span>
<span id="cb16-3"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> matplotlib.pyplot <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> plt</span>
<span id="cb16-4"></span>
<span id="cb16-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Simulate multivariate data</span></span>
<span id="cb16-6">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb16-7">n, p <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span></span>
<span id="cb16-8"></span>
<span id="cb16-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># True sparse precision matrix</span></span>
<span id="cb16-10">Theta_true <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.eye(p)</span>
<span id="cb16-11">Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.5</span></span>
<span id="cb16-12">Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.4</span></span>
<span id="cb16-13">Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">3</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.6</span></span>
<span id="cb16-14">Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> Theta_true[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">6</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.3</span></span>
<span id="cb16-15"></span>
<span id="cb16-16"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generate data</span></span>
<span id="cb16-17">Sigma <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.linalg.inv(Theta_true)</span>
<span id="cb16-18">X_network <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.multivariate_normal(np.zeros(p), Sigma, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>n)</span>
<span id="cb16-19"></span>
<span id="cb16-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Fit Graphical Lasso with cross-validation</span></span>
<span id="cb16-21">glasso <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> GraphicalLassoCV(cv<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>)</span>
<span id="cb16-22">glasso.fit(X_network)</span>
<span id="cb16-23"></span>
<span id="cb16-24"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Get estimated precision matrix</span></span>
<span id="cb16-25">Theta_est <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> glasso.precision_</span>
<span id="cb16-26"></span>
<span id="cb16-27"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Visualize network</span></span>
<span id="cb16-28">plt.figure(figsize<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span>))</span>
<span id="cb16-29"></span>
<span id="cb16-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Create adjacency matrix (thresholded)</span></span>
<span id="cb16-31">adj_matrix <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> (np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(Theta_est) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>).astype(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">int</span>)</span>
<span id="cb16-32">np.fill_diagonal(adj_matrix, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>)</span>
<span id="cb16-33"></span>
<span id="cb16-34"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Plot using networkx</span></span>
<span id="cb16-35">G <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nx.from_numpy_array(adj_matrix)</span>
<span id="cb16-36">pos <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> nx.spring_layout(G, seed<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">123</span>)</span>
<span id="cb16-37"></span>
<span id="cb16-38">plt.subplot(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb16-39">nx.draw(G, pos, with_labels<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>, node_color<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'lightblue'</span>, </span>
<span id="cb16-40">        node_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">500</span>, font_size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>, font_weight<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'bold'</span>)</span>
<span id="cb16-41">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Estimated Network Structure'</span>)</span>
<span id="cb16-42"></span>
<span id="cb16-43"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Show precision matrix heatmap</span></span>
<span id="cb16-44">plt.subplot(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>, <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>)</span>
<span id="cb16-45">plt.imshow(Theta_est, cmap<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'RdBu_r'</span>, vmin<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>, vmax<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb16-46">plt.colorbar(label<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Precision Matrix Entry'</span>)</span>
<span id="cb16-47">plt.title(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Estimated Precision Matrix'</span>)</span>
<span id="cb16-48">plt.tight_layout()</span>
<span id="cb16-49">plt.show()</span>
<span id="cb16-50"></span>
<span id="cb16-51"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(<span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">f"Sparsity: </span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span>np<span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">sum</span>(np.<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">abs</span>(Theta_est) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.01</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> p<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">**</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:.2%}</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span>)</span></code></pre></div></div>
</div>
</div>
</div>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>The Lasso family has expanded to include specialized methods (e.g., Adaptive, Elastic Net, Group Lasso) that address unique challenges like bias reduction, feature correlation, grouping structures, and network discovery.</li>
<li>Selection depends on data characteristics—correlated predictors (Elastic Net), grouped features (Group Lasso), ordered data (Fused Lasso), or bias concerns (Adaptive/Relaxed Lasso)—while all share a core principle of sparsity-promoting penalization.</li>
<li>Despite their differences, all variants rely on penalized optimization to achieve simplicity, offering tailored solutions for different modeling needs.</li>
<li>Modern tools (R: <code>glmnet</code>, <code>grpreg</code>; Python: <code>scikit-learn</code>, <code>group-lasso</code>) make these methods widely available.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>For a comprehensive treatment of penalized regression methods, see “The Elements of Statistical Learning” by Hastie, Tibshirani, and Friedman (2009), which covers Lasso and many variants in detail. “Statistical Learning with Sparsity” by Hastie, Tibshirani, and Wainwright (2015) provides a more recent and focused treatment. For theoretical properties and high-dimensional asymptotics, Bühlmann and van de Geer’s “Statistics for High-Dimensional Data” (2011) is excellent, but too technical and dense for most readers.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<ul>
<li><p>Belloni, A., Chernozhukov, V., &amp; Wang, L. (2011). Square-root lasso: Pivotal recovery of sparse signals via conic programming. <em>Biometrika</em>, 98(4), 791–806.</p></li>
<li><p>Bühlmann, P., &amp; van de Geer, S. (2011). <em>Statistics for High-Dimensional Data: Methods, Theory and Applications</em>. Springer.</p></li>
<li><p>Friedman, J., Hastie, T., &amp; Tibshirani, R. (2008). Sparse inverse covariance estimation with the graphical lasso. <em>Biostatistics</em>, 9(3), 432–441.</p></li>
<li><p>Hastie, T., Tibshirani, R., &amp; Friedman, J. (2009). <em>The Elements of Statistical Learning: Data Mining, Inference, and Prediction</em> (2nd ed.). Springer.</p></li>
<li><p>Hastie, T., Tibshirani, R., &amp; Wainwright, M. (2015). <em>Statistical Learning with Sparsity: The Lasso and Generalizations</em>. CRC Press.</p></li>
<li><p>Meinshausen, N. (2007). Relaxed lasso. <em>Computational Statistics &amp; Data Analysis</em>, 52(1), 374–393.</p></li>
<li><p>Tibshirani, R. (1996). Regression shrinkage and selection via the lasso. <em>Journal of the Royal Statistical Society: Series B (Methodological)</em>, 58(1), 267–288.</p></li>
<li><p>Tibshirani, R., Saunders, M., Rosset, S., Zhu, J., &amp; Knight, K. (2005). Sparsity and smoothness via the fused lasso. <em>Journal of the Royal Statistical Society: Series B (Statistical Methodology)</em>, 67(1), 91–108.</p></li>
<li><p>Yuan, M., &amp; Lin, Y. (2006). Model selection and estimation in regression with grouped variables. <em>Journal of the Royal Statistical Society: Series B (Statistical Methodology)</em>, 68(1), 49–67.</p></li>
<li><p>Zou, H., &amp; Hastie, T. (2005). Regularization and variable selection via the elastic net. <em>Journal of the Royal Statistical Society: Series B (Statistical Methodology)</em>, 67(2), 301–320.</p></li>
<li><p>Zou, H. (2006). The adaptive lasso and its oracle properties. <em>Journal of the American Statistical Association</em>, 101(476), 1418–1429.</p></li>
</ul>


</section>

 ]]></description>
  <category>machine learning</category>
  <category>flavors</category>
  <guid>https://vyasenov.github.io/blog/flavors-lasso.html</guid>
  <pubDate>Sat, 14 Mar 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>The Oracle Property: What It Promises (and What It Doesn’t)</title>
  <link>https://vyasenov.github.io/blog/oracle-property.html</link>
  <description><![CDATA[ 





<div class="reading-time">4 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>In high-dimensional regression, we sometimes hear that a <a href="https://vyasenov.github.io/blog/flavors-var-selection.html">variable selection</a> method possesses the oracle property. The phrase sounds impressive: it suggests that an estimator behaves as if the true sparsity pattern were known in advance—hence the name, as though an oracle had revealed the true support beforehand.</p>
<p>This note explains what the oracle property actually means, why it is considered desirable, and where its practical relevance is limited. The goal is to distinguish asymptotic guarantees from practical performance. As usual, I introduce some notation so that the discussion rests on a clear mathematical foundation and a shared framework.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Consider the linear model</p>
<p><img src="https://latex.codecogs.com/png.latex?Y%20=%20X%5Cbeta%20+%20%5Cvarepsilon,%20%5Cquad%20%5Cvarepsilon%20%5Csim%20(0,%20%5Csigma%5E2%20I_n),"></p>
<p>with <img src="https://latex.codecogs.com/png.latex?X%20%5Cin%20%5Cmathbb%7BR%7D%5E%7Bn%20%5Ctimes%20p%7D"> and <img src="https://latex.codecogs.com/png.latex?p"> potentially large. Let the true parameter vector be sparse:</p>
<p><img src="https://latex.codecogs.com/png.latex?S%20=%20%5C%7Bj%20:%20%5Cbeta_j%20%5Cneq%200%5C%7D,%20%5Cquad%20s%20=%20%7CS%7C."></p>
<p>Put simply, <img src="https://latex.codecogs.com/png.latex?S"> is the set of variables that are non-zero in the true parameter vector <img src="https://latex.codecogs.com/png.latex?%5Cbeta">, and <img src="https://latex.codecogs.com/png.latex?s"> is the number of non-zero variables.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<section id="definition" class="level3">
<h3 class="anchored" data-anchor-id="definition">Definition</h3>
<p>An estimator <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> is said to have the oracle property if it can do two things:</p>
<ul>
<li>Selection consistency: <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BP%7D(%5Chat%20S%20=%20S)%20%5Cto%201,%20%5Ctext%7B%20where%20%7D%20%5Chat%20S%20=%20%5C%7Bj%20:%20%5Chat%5Cbeta_j%20%5Cneq%200%5C%7D,"></li>
<li>Asymptotic efficiency: <img src="https://latex.codecogs.com/png.latex?%5Csqrt%7Bn%7D(%5Chat%5Cbeta_S%20-%20%5Cbeta_S)%0A%5Coverset%7Bd%7D%7B%5Clongrightarrow%7D%0A%5Cmathcal%7BN%7D(0,%20%5Csigma%5E2%20(X_S%5E%5Ctop%20X_S)%5E%7B-1%7D),"> which is the same limiting distribution as the OLS estimator that knows <img src="https://latex.codecogs.com/png.latex?S"> in advance.</li>
</ul>
<p>If the support <img src="https://latex.codecogs.com/png.latex?S"> were known, estimation reduces to low-dimensional OLS on <img src="https://latex.codecogs.com/png.latex?X_S">. That estimator is unbiased, efficient, and easy to analyze. Some of you will remember the Gauss-Markov theorem from your econometrics course which states that, the OLS estimator is the best linear unbiased estimator (BLUE) under homoskedasticity.</p>
<div class="callout callout-style-default callout-note callout-titled" title="Oracle Property Definition">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>Oracle Property Definition
</div>
</div>
<div class="callout-body-container callout-body">
<p>Can a data-driven procedure simultaneously discover <img src="https://latex.codecogs.com/png.latex?S"> and then estimate as efficiently as if <img src="https://latex.codecogs.com/png.latex?S"> were given?</p>
</div>
</div>
<p>This is an appealing theoretical benchmark for sparse estimators. You can hardly do better than that.</p>
</section>
<section id="which-methods-achieve-it" class="level3">
<h3 class="anchored" data-anchor-id="which-methods-achieve-it">Which Methods Achieve It</h3>
<p>Classical <a href="https://vyasenov.github.io/blog/flavors-lasso.html">LASSO</a> does not generally satisfy the oracle property. Its <img src="https://latex.codecogs.com/png.latex?%5Cell_1"> penalty introduces shrinkage bias that persists asymptotically.</p>
<p>Nonconvex penalties (e.g., SCAD and MCP) were explicitly designed to achieve the oracle property under regularity conditions. Adaptive LASSO can also achieve it when weights are constructed from a root-<img src="https://latex.codecogs.com/png.latex?n"> consistent pilot estimator.</p>
<p>The key mechanism is reduced shrinkage for large coefficients while still penalizing small ones.</p>
</section>
<section id="practical-implications" class="level3">
<h3 class="anchored" data-anchor-id="practical-implications">Practical Implications</h3>
<p>The oracle property is always <em>asymptotic</em>. There are never such guarantees in finite samples. It requires conditions such as:</p>
<ul>
<li>correct model specification,</li>
<li>suitable signal strength (minimum nonzero coefficient size),</li>
<li>regularity conditions on the design matrix,</li>
<li>appropriate tuning parameter rates.</li>
</ul>
<p>I have written about the <a href="https://vyasenov.github.io/blog/lasso-theory-guarantees.html">theoretical guarantees of LASSO</a> and the design conditions they rely on before. In finite samples, especially when signals are weak or highly correlated, procedures that theoretically satisfy the oracle property may not outperform simpler methods. In practice, prediction risk often matters more than exact support recovery.</p>
<p>There is also a conceptual point: the oracle benchmark assumes that the “true” model is sparse and well-defined. In many modern applications, sparsity is an approximation rather than a literal truth.</p>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>The oracle property means consistent variable selection plus asymptotically efficient estimation on the true support.</li>
<li>Nonconvex penalties and adaptive LASSO can achieve it; standard LASSO typically does not.</li>
<li>The property is asymptotic and depends on strong conditions (signal strength, design assumptions, tuning rates).</li>
<li>In practice, predictive performance and stability often matter more than satisfying oracle-style guarantees.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>Fan and Li (2001) introduced SCAD and formalized the oracle property in penalized likelihood estimation. Zou (2006) shows how adaptive LASSO can achieve oracle behavior. Bühlmann and van de Geer’s Statistics for High-Dimensional Data provides a modern, rigorous treatment of sparsity, regularization paths, and inference in high-dimensional regimes.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Bühlmann, P., &amp; van de Geer, S. (2011). Statistics for High-Dimensional Data.</p>
<p>Fan, J., &amp; Li, R. (2001). Variable selection via nonconcave penalized likelihood and its oracle properties.</p>
<p>Zhang, C. H. (2010). Nearly unbiased variable selection under minimax concave penalty.</p>
<p>Zou, H. (2006). The adaptive LASSO and its oracle properties.</p>


</section>

 ]]></description>
  <category>machine learning</category>
  <category>variable selection</category>
  <guid>https://vyasenov.github.io/blog/oracle-property.html</guid>
  <pubDate>Fri, 13 Mar 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>Why Some Confidence Intervals Are Not Symmetric</title>
  <link>https://vyasenov.github.io/blog/nonsymmetric-conf-int.html</link>
  <description><![CDATA[ 





<div class="reading-time">5 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>Most of us were trained to think of a <img src="https://latex.codecogs.com/png.latex?95%5C%25"> confidence interval as</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Ctheta%7D%20%5Cpm%201.96%20%5Ccdot%20%5Cmathrm%7BSE%7D(%5Chat%7B%5Ctheta%7D)."></p>
<p>That template is deeply ingrained. It works beautifully for estimators whose sampling distributions are symmetric and well behaved. But have you ever come across a confidence interval with an off-center point estimate? (Confidence intervals trip people up in other ways too—I have written about how <a href="https://vyasenov.github.io/blog/overlapping-conf-intervals.html">overlapping confidence intervals do not imply statistical insignificance</a>.)</p>
<p>The “<img src="https://latex.codecogs.com/png.latex?%5Cpm"> margin of error” representation is not a defining property of confidence intervals. It is a <em>consequence of</em> symmetry. Once symmetry disappears because of skewed sampling distributions, nonlinear transformations, boundary constraints, or small-sample behavior, the interval need not be centered around the point estimate.</p>
<p>The goal of this note is to unpack where asymmetry comes from, when it is expected, and how different construction principles lead to intervals that look very different from the textbook <img src="https://latex.codecogs.com/png.latex?t">-interval. I will also illustrate the phenomenon with a bootstrap example in <code>R</code> and <code>Python</code>.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Let <img src="https://latex.codecogs.com/png.latex?%5Ctheta%20%5Cin%20%5CTheta"> denote a scalar parameter of interest, and let <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Ctheta%7D%20=%20%5Chat%7B%5Ctheta%7D(X_1,%5Cdots,X_n)"> be an estimator.</p>
<p>A <img src="https://latex.codecogs.com/png.latex?(1-%5Calpha)"> confidence interval is a random set <img src="https://latex.codecogs.com/png.latex?C(X)"> such that, by definition,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BP%7D_%5Ctheta%5Cbig(%5Ctheta%20%5Cin%20C(X)%5Cbig)%20%5Cge%201-%5Calpha%0A%5Cquad%20%5Ctext%7Bfor%20all%20%7D%20%5Ctheta%20%5Cin%20%5CTheta.%0A"></p>
<p>When <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Ctheta%7D"> satisfies an asymptotic normality result, then a Wald-type interval takes the familiar form</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Ctheta%7D%20%5Cpm%20z_%7B%5Calpha/2%7D%5C,%5Cwidehat%7B%5Cmathrm%7BSE%7D%7D(%5Chat%7B%5Ctheta%7D),"></p>
<p>where the critical value <img src="https://latex.codecogs.com/png.latex?z_%7B%5Calpha/2%7D"> is the <img src="https://latex.codecogs.com/png.latex?(1-%5Calpha/2)"> quantile of the standard normal.</p>
<p>This interval is symmetric around <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Ctheta%7D"> by construction. Its symmetry is inherited from the symmetry of the limiting Gaussian distribution. Remove that symmetry or step outside the world where the approximation is valid, and the interval will generally no longer be symmetric.</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<p>I will now examine four common sources of confidence interval asymmetry.</p>
<section id="skewed-sampling-distributions" class="level3">
<h3 class="anchored" data-anchor-id="skewed-sampling-distributions">Skewed Sampling Distributions</h3>
<p>Symmetry of the interval reflects symmetry of the sampling distribution, not symmetry of the data.</p>
<p>Consider estimating a proportion <img src="https://latex.codecogs.com/png.latex?p"> from a binomial model. The MLE is <img src="https://latex.codecogs.com/png.latex?%5Chat%7Bp%7D%20=%20X/n">. For moderate <img src="https://latex.codecogs.com/png.latex?n"> and <img src="https://latex.codecogs.com/png.latex?p"> near <img src="https://latex.codecogs.com/png.latex?0"> or <img src="https://latex.codecogs.com/png.latex?1">, the distribution of <img src="https://latex.codecogs.com/png.latex?%5Chat%7Bp%7D"> is visibly skewed. A Wald interval,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%7Bp%7D%20%5Cpm%20z_%7B%5Calpha/2%7D%5Csqrt%7B%5Cfrac%7B%5Chat%7Bp%7D(1-%5Chat%7Bp%7D)%7D%7Bn%7D%7D,"></p>
<p>may extend below <img src="https://latex.codecogs.com/png.latex?0"> or above <img src="https://latex.codecogs.com/png.latex?1">. That is a red flag: the procedure ignores the geometry of the parameter space.</p>
<p>Score intervals and logit-transformed intervals are asymmetric in <img src="https://latex.codecogs.com/png.latex?p"> precisely because they respect this skewness and the <img src="https://latex.codecogs.com/png.latex?%5B0,1%5D"> constraint. The asymmetry is not a flaw—it is the correction.</p>
</section>
<section id="nonlinear-transformations" class="level3">
<h3 class="anchored" data-anchor-id="nonlinear-transformations">Nonlinear Transformations</h3>
<p>Suppose <img src="https://latex.codecogs.com/png.latex?%5Cphi%20=%20g(%5Ctheta)"> for a nonlinear <img src="https://latex.codecogs.com/png.latex?g">. Even if <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Ctheta%7D"> is approximately normal, the distribution of</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Cphi%7D%20=%20g(%5Chat%7B%5Ctheta%7D)"></p>
<p>is generally not symmetric in finite samples.</p>
<p>A first-order <a href="https://vyasenov.github.io/blog/delta-method.html">delta method</a> approximation gives</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Csqrt%7Bn%7D%5Cbig(%5Chat%7B%5Cphi%7D%20-%20%5Cphi%5Cbig)%0A%5C;%5Coverset%7Bd%7D%7B%5Clongrightarrow%7D%5C;%0A%5Cmathcal%7BN%7D%5Cleft(0,%20%5Cbig(g'(%5Ctheta)%5Cbig)%5E2%20V(%5Ctheta)%5Cright),%0A"></p>
<p>which suggests a symmetric interval in <img src="https://latex.codecogs.com/png.latex?%5Cphi">-space. However, mapping that interval back to <img src="https://latex.codecogs.com/png.latex?%5Ctheta">-space via <img src="https://latex.codecogs.com/png.latex?g%5E%7B-1%7D"> typically produces asymmetry.</p>
<p>This is routine in practice. Log-scale confidence intervals for positive parameters (e.g., rate ratios, hazard ratios) are symmetric in <img src="https://latex.codecogs.com/png.latex?%5Clog%20%5Ctheta"> but asymmetric in <img src="https://latex.codecogs.com/png.latex?%5Ctheta">. The asymmetry reflects curvature in <img src="https://latex.codecogs.com/png.latex?g">.</p>
</section>
<section id="likelihood-based-intervals" class="level3">
<h3 class="anchored" data-anchor-id="likelihood-based-intervals">Likelihood-Based Intervals</h3>
<p>Likelihood-ratio intervals solve</p>
<p><img src="https://latex.codecogs.com/png.latex?2%5Cbig(%5Cell(%5Chat%7B%5Ctheta%7D)%20-%20%5Cell(%5Ctheta)%5Cbig)%20%5Cle%20%5Cchi%5E2_%7B1,1-%5Calpha%7D,"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?%5Cell(%5Ctheta)"> is the log-likelihood. When <img src="https://latex.codecogs.com/png.latex?%5Cell(%5Ctheta)"> is not quadratic as is common in small samples or near boundaries, the resulting set is not symmetric around <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Ctheta%7D">.</p>
<p>The quadratic approximation that underlies Wald intervals is a second-order Taylor expansion. If the likelihood is skewed, the quadratic approximation inherits bias, and symmetric intervals misrepresent uncertainty.</p>
</section>
<section id="bootstrap-percentile-intervals" class="level3">
<h3 class="anchored" data-anchor-id="bootstrap-percentile-intervals">Bootstrap Percentile Intervals</h3>
<p>Bootstrap percentile intervals are defined directly from empirical quantiles of the bootstrap distribution:</p>
<p><img src="https://latex.codecogs.com/png.latex?C_%7B%5Ctext%7Bperc%7D%7D%20=%20%5Cleft%5B%0A%5Chat%7B%5Ctheta%7D%5E*_%7B(%5Calpha/2)%7D,%0A%5Chat%7B%5Ctheta%7D%5E*_%7B(1-%5Calpha/2)%7D%0A%5Cright%5D,"></p>
<p>where <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Ctheta%7D%5E*"> are bootstrap replicates.</p>
<p>No symmetry is imposed. If the empirical distribution of <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Ctheta%7D%5E*"> is skewed, the interval is skewed. This is often desirable: the procedure adapts to the shape of the sampling distribution.</p>
<div class="callout callout-style-default callout-note callout-titled" title="Algorithm: Percentile Bootstrap CI">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Note</span>Algorithm: Percentile Bootstrap CI
</div>
</div>
<div class="callout-body-container callout-body">
<ol type="1">
<li>Draw <img src="https://latex.codecogs.com/png.latex?B"> bootstrap samples by resampling with replacement.</li>
<li>Compute <img src="https://latex.codecogs.com/png.latex?%5Chat%7B%5Ctheta%7D%5E%7B*(b)%7D"> for each resample.</li>
<li>Form the interval from the empirical <img src="https://latex.codecogs.com/png.latex?%5Calpha/2"> and <img src="https://latex.codecogs.com/png.latex?1-%5Calpha/2"> quantiles of <img src="https://latex.codecogs.com/png.latex?%5C%7B%5Chat%7B%5Ctheta%7D%5E%7B*(b)%7D%5C%7D_%7Bb=1%7D%5EB">.</li>
</ol>
</div>
</div>
<p>The percentile method is not universally optimal, but it makes the asymmetry explicit instead of suppressing it.</p>
</section>
</section>
<section id="an-example" class="level2">
<h2 class="anchored" data-anchor-id="an-example">An Example</h2>
<p>We simulate from an exponential distribution, which is right-skewed. Even the (asymptotically normal) sample mean can have a noticeably skewed sampling distribution at moderate <img src="https://latex.codecogs.com/png.latex?n">.</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true" href="">R</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false" href="">Python</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">set.seed</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generate 50 observations from Exp(1)</span></span>
<span id="cb1-4">x <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">rexp</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">rate =</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb1-5">sample_mean <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(x)</span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Bootstrap distribution of the mean</span></span>
<span id="cb1-8">boot_means <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">replicate</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mean</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sample</span>(x, <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">replace =</span> <span class="cn" style="color: #8f5902;
background-color: null;
font-style: inherit;">TRUE</span>)))</span>
<span id="cb1-9"></span>
<span id="cb1-10"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Percentile CI</span></span>
<span id="cb1-11">ci_percentile <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">quantile</span>(boot_means, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.025</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">0.975</span>))</span>
<span id="cb1-12"></span>
<span id="cb1-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Symmetric normal approximation</span></span>
<span id="cb1-14">se <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sd</span>(x) <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sqrt</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">length</span>(x))</span>
<span id="cb1-15">ci_symmetric <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">c</span>(sample_mean <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.96</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se,</span>
<span id="cb1-16">                  sample_mean <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.96</span> <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se)</span>
<span id="cb1-17"></span>
<span id="cb1-18">lower_distance <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> sample_mean <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> ci_percentile[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>]</span>
<span id="cb1-19">upper_distance <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> ci_percentile[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>] <span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> sample_mean</span>
<span id="cb1-20"></span>
<span id="cb1-21"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span>(lower_distance, upper_distance)</span></code></pre></div></div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> numpy <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> np</span>
<span id="cb2-2"></span>
<span id="cb2-3">np.random.seed(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1988</span>)</span>
<span id="cb2-4"></span>
<span id="cb2-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Generate 50 observations from Exp(1)</span></span>
<span id="cb2-6">x <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.random.exponential(scale<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.0</span>, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>)</span>
<span id="cb2-7">sample_mean <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.mean(x)</span>
<span id="cb2-8"></span>
<span id="cb2-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Bootstrap distribution of the mean</span></span>
<span id="cb2-10">boot_means <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb2-11">    np.mean(np.random.choice(x, size<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span>, replace<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">True</span>))</span>
<span id="cb2-12">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">for</span> _ <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">in</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">range</span>(<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10000</span>)</span>
<span id="cb2-13">]</span>
<span id="cb2-14"></span>
<span id="cb2-15"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Percentile CI</span></span>
<span id="cb2-16">ci_percentile <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.percentile(boot_means, [<span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">2.5</span>, <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">97.5</span>])</span>
<span id="cb2-17"></span>
<span id="cb2-18"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Symmetric normal approximation</span></span>
<span id="cb2-19">se <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> np.std(x, ddof<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span> np.sqrt(<span class="bu" style="color: null;
background-color: null;
font-style: inherit;">len</span>(x))</span>
<span id="cb2-20">ci_symmetric <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> [</span>
<span id="cb2-21">    sample_mean <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.96</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se,</span>
<span id="cb2-22">    sample_mean <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fl" style="color: #AD0000;
background-color: null;
font-style: inherit;">1.96</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> se</span>
<span id="cb2-23">]</span>
<span id="cb2-24"></span>
<span id="cb2-25">lower_distance <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> sample_mean <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> ci_percentile[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>]</span>
<span id="cb2-26">upper_distance <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> ci_percentile[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>] <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span> sample_mean</span>
<span id="cb2-27"></span>
<span id="cb2-28"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">print</span>(lower_distance, upper_distance)</span></code></pre></div></div>
</div>
</div>
</div>
<p>In typical runs, the upper distance exceeds the lower distance. The right tail of the exponential distribution propagates into the bootstrap distribution of the mean. The percentile interval reflects that skewness; the Wald interval does not.</p>
<p>As <img src="https://latex.codecogs.com/png.latex?n"> grows, the central limit theorem compresses this asymmetry. At <img src="https://latex.codecogs.com/png.latex?n=50">, it is still visible. At <img src="https://latex.codecogs.com/png.latex?n=5000">, it is largely gone. The interval geometry tracks the sampling distribution geometry.</p>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>Symmetric intervals arise from symmetric (often Gaussian) approximations; they are not a universal property of confidence intervals.</li>
<li>Skewness, nonlinear transformations, and boundary constraints naturally induce asymmetric intervals.</li>
<li>Likelihood-based and bootstrap methods often expose asymmetry that Wald intervals conceal.</li>
<li>If the parameter space or sampling distribution is asymmetric, an asymmetric interval is typically more faithful to the underlying uncertainty.</li>
</ul>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Casella, G., &amp; Berger, R. L. (2002). Statistical Inference.</p>
<p>Efron, B., &amp; Tibshirani, R. J. (1993). An Introduction to the Bootstrap.</p>


</section>

 ]]></description>
  <category>statistical inference</category>
  <category>hypothesis testing</category>
  <guid>https://vyasenov.github.io/blog/nonsymmetric-conf-int.html</guid>
  <pubDate>Tue, 10 Mar 2026 07:00:00 GMT</pubDate>
</item>
<item>
  <title>OLS with Fixed vs Random \(X\): What Actually Changes?</title>
  <link>https://vyasenov.github.io/blog/ols-fixed-random-x.html</link>
  <description><![CDATA[ 





<div class="reading-time">4 min read</div>
<!-- this is for social media sharing buttons -->
<div class="sharethis-inline-share-buttons pt-5">

</div>
<section id="background" class="level2">
<h2 class="anchored" data-anchor-id="background">Background</h2>
<p>In regression courses, you will eventually hear the phrase: “OLS works whether <img src="https://latex.codecogs.com/png.latex?X"> is fixed or random.” That statement is correct, but dangerously compressed.</p>
<p>The distinction between fixed and random regressors is not about how you compute <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta">. The algebra is identical. The difference is in what is random, what we condition on, and how we interpret sampling statements.</p>
<p>The goal of this note is to make that distinction precise, and to clarify what does—and does not—depend on treating <img src="https://latex.codecogs.com/png.latex?X"> as fixed.</p>
</section>
<section id="notation" class="level2">
<h2 class="anchored" data-anchor-id="notation">Notation</h2>
<p>Consider the well-known linear model</p>
<p><img src="https://latex.codecogs.com/png.latex?Y%20=%20X%5Cbeta%20+%20%5Cvarepsilon,"></p>
<p>where:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?Y%20%5Cin%20%5Cmathbb%7BR%7D%5En">,</li>
<li><img src="https://latex.codecogs.com/png.latex?X%20%5Cin%20%5Cmathbb%7BR%7D%5E%7Bn%20%5Ctimes%20p%7D"> with full column rank,</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Cbeta%20%5Cin%20%5Cmathbb%7BR%7D%5Ep">,</li>
<li><img src="https://latex.codecogs.com/png.latex?%5Cvarepsilon%20%5Cin%20%5Cmathbb%7BR%7D%5En"> with <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D%5B%5Cvarepsilon%20%5Cmid%20X%5D%20=%200"> and <img src="https://latex.codecogs.com/png.latex?%5Coperatorname%7BVar%7D(%5Cvarepsilon%20%5Cmid%20X)%20=%20%5Csigma%5E2%20I">.</li>
</ul>
<p>The standard OLS estimator is</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta%20=%20(X%5E%5Ctop%20X)%5E%7B-1%7D%20X%5E%5Ctop%20Y."></p>
<p>The key question is: are we conditioning on <img src="https://latex.codecogs.com/png.latex?X">, or is <img src="https://latex.codecogs.com/png.latex?X"> itself a random object in the data-generating process?</p>
</section>
<section id="a-closer-look" class="level2">
<h2 class="anchored" data-anchor-id="a-closer-look">A Closer Look</h2>
<p>Let’s take a closer look at the two cases.</p>
<section id="fixed-x-classical-linear-model" class="level3">
<h3 class="anchored" data-anchor-id="fixed-x-classical-linear-model">Fixed <img src="https://latex.codecogs.com/png.latex?X">: Classical Linear Model</h3>
<p>In the classical setup, <img src="https://latex.codecogs.com/png.latex?X"> is treated as fixed (non-stochastic). Then, all randomness comes from the error term <img src="https://latex.codecogs.com/png.latex?%5Cvarepsilon">.</p>
<p>Conditional on <img src="https://latex.codecogs.com/png.latex?X">,</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D%5B%5Chat%5Cbeta%20%5Cmid%20X%5D%20=%20%5Cbeta,"> <img src="https://latex.codecogs.com/png.latex?%5Coperatorname%7BVar%7D(%5Chat%5Cbeta%20%5Cmid%20X)%20=%20%5Csigma%5E2%20(X%5E%5Ctop%20X)%5E%7B-1%7D."></p>
<p>Inference is therefore <em>conditional</em> inference. Confidence intervals and <img src="https://latex.codecogs.com/png.latex?t">-tests are statements about the distribution of <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta"> given this specific design matrix, <img src="https://latex.codecogs.com/png.latex?X">.</p>
<p>This framework is natural in designed experiments, where <img src="https://latex.codecogs.com/png.latex?X"> is literally chosen by the researcher.</p>
</section>
<section id="random-x-econometric-view" class="level3">
<h3 class="anchored" data-anchor-id="random-x-econometric-view">Random <img src="https://latex.codecogs.com/png.latex?X">: Econometric View</h3>
<p>In most observational settings, <img src="https://latex.codecogs.com/png.latex?X"> is random. We observe i.i.d. draws <img src="https://latex.codecogs.com/png.latex?(X_i,%20Y_i)"> from an unknown joint distribution, <img src="https://latex.codecogs.com/png.latex?F_%7BX,Y%7D">. Under standard regularity conditions, the same OLS estimator, <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta">, satisfies</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta%0A%5C;%5Cxrightarrow%7Bp%7D%5C;%0A%5Cbeta%0A%5Cquad%20%5Ctext%7Bif%7D%20%5Cquad%0A%5Cmathbb%7BE%7D%5BX_i%20%5Cvarepsilon_i%5D%20=%200."></p>
<p>The asymptotic variance becomes</p>
<p><img src="https://latex.codecogs.com/png.latex?%20%5Coperatorname%7BAvar%7D(%5Chat%5Cbeta)=%5Cleft(%20%5Cmathbb%7BE%7D%5BX_i%20X_i%5E%5Ctop%5D%20%5Cright)%5E%7B-1%7D%5Cmathbb%7BE%7D%5BX_i%20X_i%5E%5Ctop%20%5Cvarepsilon_i%5E2%5D%5Cleft(%20%5Cmathbb%7BE%7D%5BX_i%20X_i%5E%5Ctop%5D%20%5Cright)%5E%7B-1%7D."></p>
<p>Under homoskedasticity, this simplifies to</p>
<p><img src="https://latex.codecogs.com/png.latex?%5Csigma%5E2%20%5Cleft(%20%5Cmathbb%7BE%7D%5BX_i%20X_i%5E%5Ctop%5D%20%5Cright)%5E%7B-1%7D."></p>
<p>The algebra mirrors the fixed-<img src="https://latex.codecogs.com/png.latex?X"> case, but the interpretation changes: we are no longer conditioning on a specific realization of <img src="https://latex.codecogs.com/png.latex?X">; we are <em>averaging over its distribution</em>.</p>
</section>
<section id="what-actually-changes" class="level3">
<h3 class="anchored" data-anchor-id="what-actually-changes">What Actually Changes?</h3>
<p>Three things matter.</p>
<p>First, the object of inference. With fixed <img src="https://latex.codecogs.com/png.latex?X">, inference is conditional on the design. With random <img src="https://latex.codecogs.com/png.latex?X">, inference is about repeated sampling of <img src="https://latex.codecogs.com/png.latex?F_%7BX,Y%7D">.</p>
<p>Second, exogeneity assumptions. In the fixed-<img src="https://latex.codecogs.com/png.latex?X"> model, we require <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D%5B%5Cvarepsilon%20%5Cmid%20X%5D%20=%200">. In the random-<img src="https://latex.codecogs.com/png.latex?X"> case, we need the same condition, but it now constrains the joint distribution: it says that once we know the regressors, there is no systematic remaining signal in the error term. Violations become statements about endogeneity, meaning <img src="https://latex.codecogs.com/png.latex?X"> is statistically related to omitted factors inside <img src="https://latex.codecogs.com/png.latex?%5Cvarepsilon">. Whether the resulting coefficient carries a causal meaning at all is a separate question I take up in <a href="https://vyasenov.github.io/blog/interpret-OLS-causal-inference.html">what OLS estimates in causal inference</a>.</p>
<p>Third, robustness. Heteroskedasticity-robust standard errors are naturally derived in the random-<img src="https://latex.codecogs.com/png.latex?X"> framework, where the conditional variance may depend on <img src="https://latex.codecogs.com/png.latex?X_i">. In other words, different parts of the regressor distribution can come with different noise levels, so inference has to account for that variation rather than rely on a single common variance.</p>
<p>What does not change is the formula for <img src="https://latex.codecogs.com/png.latex?%5Chat%5Cbeta">. Nor does unbiasedness depend on <img src="https://latex.codecogs.com/png.latex?X"> being fixed; it depends on the conditional mean-zero assumption.</p>
</section>
</section>
<section id="bottom-line" class="level2">
<h2 class="anchored" data-anchor-id="bottom-line">Bottom Line</h2>
<ul>
<li>The OLS estimator is algebraically identical whether <img src="https://latex.codecogs.com/png.latex?X"> is fixed or random.</li>
<li>Fixed-<img src="https://latex.codecogs.com/png.latex?X"> inference is conditional; random-<img src="https://latex.codecogs.com/png.latex?X"> inference averages over the joint distribution.</li>
<li>Consistency hinges on <img src="https://latex.codecogs.com/png.latex?%5Cmathbb%7BE%7D%5BX_i%20%5Cvarepsilon_i%5D%20=%200">, not on whether <img src="https://latex.codecogs.com/png.latex?X"> is stochastic.</li>
<li>Robust variance formulas arise naturally once <img src="https://latex.codecogs.com/png.latex?X"> is treated as random.</li>
</ul>
</section>
<section id="where-to-learn-more" class="level2">
<h2 class="anchored" data-anchor-id="where-to-learn-more">Where to Learn More</h2>
<p>For a classical treatment, see Greene’s <em>Econometric Analysis</em>, which clearly distinguishes fixed and stochastic regressors. Wooldridge’s <em>Econometric Analysis of Cross Section and Panel Data</em> provides a modern random-<img src="https://latex.codecogs.com/png.latex?X"> perspective with emphasis on exogeneity conditions and robust inference.</p>
</section>
<section id="references" class="level2">
<h2 class="anchored" data-anchor-id="references">References</h2>
<p>Greene, W. H. (2018). Econometric Analysis.</p>
<p>Wooldridge, J. M. (2010). Econometric Analysis of Cross Section and Panel Data.</p>


</section>

 ]]></description>
  <category>parametric models</category>
  <category>statistical inference</category>
  <guid>https://vyasenov.github.io/blog/ols-fixed-random-x.html</guid>
  <pubDate>Sun, 08 Mar 2026 08:00:00 GMT</pubDate>
</item>
</channel>
</rss>
