🎉 75% of content is free forever — Unlock Premium from $10/mo →
CW
Search courses…
💼 Servicesℹ️ About✉️ ContactView Pricing Plansfrom $10

High-Dimensional Statistics

Advanced Statistical MethodsModern Methods🟢 Free Lesson

Advertisement

High-Dimensional Statistics

Advanced Statistical Methods

When Features Outnumber Samples

High-dimensional statistics addresses the challenge of p >> n problems where classical methods break down. Sparse estimation techniques like LASSO, SCAD, and MCP recover signals from high-dimensional noise.

  • Genomics — Identify important genes from thousands of expression features with few samples
  • Image recognition — Select relevant pixels or features from high-dimensional image data
  • Text classification — Build sparse models from tens of thousands of word features

High-dimensional statistics finds needles in haystacks when the haystack has more needles than hay.


When the number of parameters grows with or exceeds the sample size , classical asymptotic theory breaks down. The classical estimator does not exist when , confidence intervals lose coverage, and the maximum likelihood estimator may not be unique. High-dimensional statistics develops the theory and methods for inference under this regime.


The Curse of Dimensionality


Sparse Estimation

Sparsity assumes that only of the parameters are nonzero. This is the key structural assumption enabling estimation in high dimensions.

LASSO (Least Absolute Shrinkage and Selection Operator)

The penalty induces exact zeros in , performing automatic variable selection. The regularization path is piecewise linear and can be computed exactly via the LARS algorithm.

SCAD (Smoothly Clipped Absolute Deviation)

The SCAD penalty is quadratic near zero (like ridge) and constant for large coefficients (like hard thresholding). It satisfies three properties: unbiasedness (for large coefficients), sparsity, and continuity.

MCP (Minimax Concave Penalty)

The MCP interpolates between LASSO () and hard thresholding (). For , MCP is an unbiased, sparse, and continuous penalty.


Compressed Sensing

Random matrices with i.i.d. sub-Gaussian entries satisfy the RIP with high probability when . This is the foundation of the compressed sensing revolution.


Random Projections

The dimension reduction is independent of the original dimension —distances are approximately preserved after projecting to dimensions.


Concentration of Measures


Double Descent

The variance term dominates near (explaining the peak), while for , the variance decreases because the minimum-norm solution spreads mass across many directions.


Benign Overfitting


Python Implementation

import numpy as np
import pandas as pd
from scipy.optimize import minimize
from sklearn.linear_model import Lasso, LassoCV
from sklearn.model_selection import cross_val_score
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt

np.random.seed(42)

# --- Generate high-dimensional data ---
n, p, s = 100, 500, 10
X = np.random.randn(n, p)
beta_true = np.zeros(p)
support = np.random.choice(p, s, replace=False)
beta_true[support] = np.random.randn(s) * 3
y = X @ beta_true + np.random.randn(n) * 0.5

print(f"Setup: n={n}, p={p}, s={s}")
print(f"True support: {sorted(support)}")

# --- LASSO with cross-validation ---
lasso_cv = LassoCV(cv=5, random_state=42).fit(X, y)
beta_lasso = lasso_cv.coef_

n_selected = np.sum(beta_lasso != 0)
true_pos = len(set(np.where(beta_lasso != 0)[0]) & set(support))
false_pos = n_selected - true_pos
false_neg = s - true_pos

print(f"\nLASSO Results (λ={lasso_cv.alpha_:.4f}):")
print(f"  Selected: {n_selected} variables")
print(f"  True positives: {true_pos}/{s}")
print(f"  False positives: {false_pos}")
print(f"  False negatives: {false_neg}")
print(f"  MSE: {mean_squared_error(y, X @ beta_lasso):.4f}")

# --- SCAD penalty (proximal gradient) ---
def scad_penalty(t, lam, a=3.7):
    t_abs = np.abs(t)
    penalty = np.where(t_abs <= lam, lam * t_abs,
                       np.where(t_abs <= a * lam,
                               (-t_abs**2 + 2*a*lam*t_abs - lam**2) / (2*(a-1)),
                               (a+1)*lam**2 / 2))
    return penalty

def scad_prox(v, lam, a=3.7):
    """Proximal operator for SCAD."""
    result = np.zeros_like(v)
    for i in range(len(v)):
        t = v[i]
        t_abs = np.abs(t)
        if t_abs <= 2 * lam:
            result[i] = np.sign(t) * max(t_abs - lam, 0)
        elif t_abs <= a * lam:
            result[i] = (t - np.sign(t) * a * lam / (a - 1)) / (1 - 1/(a-1))
            result[i] = np.sign(t) * max(np.abs(result[i]), 0)
        else:
            result[i] = t
    return result

# Proximal gradient descent for SCAD
def fit_scad(X, y, lam, a=3.7, lr=0.01, max_iter=1000):
    n, p = X.shape
    beta = np.zeros(p)
    L = np.linalg.norm(X.T @ X) / n

    for iteration in range(max_iter):
        grad = -X.T @ (y - X @ beta) / n
        beta_new = scad_prox(beta - lr * grad, lam * lr, a)
        if np.linalg.norm(beta_new - beta) < 1e-8:
            break
        beta = beta_new
    return beta

beta_scad = fit_scad(X, y, lam=0.1)
n_scad = np.sum(beta_scad != 0)
true_pos_scad = len(set(np.where(beta_scad != 0)[0]) & set(support))
print(f"\nSCAD Results:")
print(f"  Selected: {n_scad} variables")
print(f"  True positives: {true_pos_scad}/{s}")

# --- MCP penalty ---
def mcp_penalty(t, lam, gamma=3.0):
    t_abs = np.abs(t)
    return np.where(t_abs <= gamma * lam,
                    lam * t_abs - t_abs**2 / (2 * gamma),
                    gamma * lam**2 / 2)

def mcp_prox(v, lam, gamma=3.0):
    result = np.zeros_like(v)
    for i in range(len(v)):
        t_abs = np.abs(v[i])
        if t_abs <= lam:
            result[i] = np.sign(v[i]) * max(t_abs - lam, 0)
        elif t_abs <= gamma * lam:
            result[i] = v[i] * (gamma - 1) / gamma - np.sign(v[i]) * lam / gamma
            result[i] = np.sign(v[i]) * max(np.abs(result[i]), 0)
        else:
            result[i] = v[i]
    return result

def fit_mcp(X, y, lam, gamma=3.0, lr=0.01, max_iter=1000):
    n, p = X.shape
    beta = np.zeros(p)
    for _ in range(max_iter):
        grad = -X.T @ (y - X @ beta) / n
        beta_new = mcp_prox(beta - lr * grad, lam * lr, gamma)
        if np.linalg.norm(beta_new - beta) < 1e-8:
            break
        beta = beta_new
    return beta

beta_mcp = fit_mcp(X, y, lam=0.1)
n_mcp = np.sum(beta_mcp != 0)
true_pos_mcp = len(set(np.where(beta_mcp != 0)[0]) & set(support))
print(f"\nMCP Results:")
print(f"  Selected: {n_mcp} variables")
print(f"  True positives: {true_pos_mcp}/{s}")

# --- Double descent demonstration ---
ratios = np.linspace(0.2, 3.0, 50)
test_errors = []
train_errors = []

for ratio in ratios:
    n_i = int(ratio * p) if ratio * p < n * 3 else int(n * 3)
    X_sub = X[:n_i, :n_i] if n_i <= p else X[:min(n_i, n), :p]
    y_sub = y[:X_sub.shape[0]]

    if X_sub.shape[0] >= X_sub.shape[1]:
        try:
            beta_hat = np.linalg.lstsq(X_sub, y_sub, rcond=None)[0]
        except:
            beta_hat = np.zeros(X_sub.shape[1])
    else:
        # Minimum norm solution
        beta_hat = X_sub.T @ np.linalg.solve(X_sub @ X_sub.T + 1e-10*np.eye(X_sub.shape[0]), y_sub)

    y_pred = X[:X_sub.shape[0], :X_sub.shape[1]] @ beta_hat
    test_errors.append(mean_squared_error(y[:len(y_pred)], y_pred))
    train_errors.append(np.mean((X_sub @ beta_hat - y_sub)**2))

plt.figure(figsize=(8, 5))
plt.plot(ratios, test_errors, 'b-', label='Test Error', lw=2)
plt.plot(ratios, train_errors, 'r--', label='Train Error', lw=2)
plt.axvline(x=1.0, color='gray', ls=':', label='p/n = 1')
plt.xlabel('Ratio p/n')
plt.ylabel('Mean Squared Error')
plt.title('Double Descent Phenomenon')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("double_descent.png", dpi=150, bbox_inches="tight")
plt.show()

print("\nDouble descent: test error peaks near p/n = 1, then decreases in overparameterized regime")

Summary

Need Expert Statistics Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement