Skip to content
Kittycat.tech logo

Inferential Statistics Formulas in LaTeX, Python and Rust

✅ Copy-ready code for inferential statistics formulas in LaTeX, Python and Rust. For each formula, you'll see how to write it in LaTeX and how to calculate it in code. 😻

Every snippet runs on its own with no extra libraries, and the expected output is written in the comments. Use the tabs to switch between LaTeX, Python and Rust. To run a Rust snippet, save it as main.rs and run rustc main.rs, or paste it into the Rust Playground.

📚 Math Formulas in Code series

Just click the copy button in the top right corner of each code block!

Summary Overview ​

#FormulaExample
1Standard Error of the Mean[2,…,9]→0.7559
2Normal Distribution ProbabilityΦ(1.96)≈0.975
3Confidence Interval for the Meanx¯=50,s=10,n=100→(48.04,51.96)
4One-Sample z-Testz=2, p≈0.0455
5One-Sample t-Testt≈1.8898, df =5
6Two-Sample t-Testt≈2.9814
7Chi-Squared Statisticχ2=12.32
8Binomial Probability3 heads in 10 flips ≈0.1172
9Simple Linear Regression and R²β1=0.6, β0=2.2, R2=0.6
10Bayes' TheoremP(D∣+)≈0.1667

1. Standard Error of the Mean ​

Standard Error of the Mean

Formula:

SE=sn

The standard error shows how much the sample mean would change from sample to sample. Bigger samples give a smaller standard error.

Where it's used: confidence intervals, hypothesis tests, and error bars on charts.

markdown
$$
\text{SE} = \frac{s}{\sqrt{n}}
$$
python
import math

def standard_error(values: list[float]) -> float:
    n = len(values)
    m = sum(values) / n
    s = math.sqrt(sum((x - m) ** 2 for x in values) / (n - 1))
    return s / math.sqrt(n)

print(round(standard_error([2, 4, 4, 4, 5, 5, 7, 9]), 4))  # 0.7559
rust
fn standard_error(values: &[f64]) -> f64 {
    let n = values.len() as f64;
    let m = values.iter().sum::<f64>() / n;
    let s = (values.iter().map(|x| (x - m).powi(2)).sum::<f64>() / (n - 1.0)).sqrt();
    s / n.sqrt()
}

fn main() {
    let data = [2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
    println!("{:.4}", standard_error(&data)); // 0.7559
}

2. Normal Distribution Probability ​

Normal Distribution Probability

Formula:

Φ(z)=P(Z≤z)=12[1+erf(z2)]

Φ(z) is the area under the standard normal curve to the left of z. For example, Φ(1.96)≈0.975.

Where it's used: turning z-scores into probabilities, and calculating p-values.

markdown
$$
\Phi(z) = P(Z \le z) = \frac{1}{2} \left[ 1 + \operatorname{erf}\left( \frac{z}{\sqrt{2}} \right) \right]
$$
python
import math

def normal_cdf(z: float) -> float:
    return 0.5 * (1 + math.erf(z / math.sqrt(2)))

print(round(normal_cdf(1.96), 4))  # 0.975
print(round(normal_cdf(0), 4))     # 0.5
rust
// Rust's standard library has no erf, so this uses the Abramowitz and Stegun
// approximation, accurate to about 7 decimal places.
fn erf(x: f64) -> f64 {
    let sign = if x < 0.0 { -1.0 } else { 1.0 };
    let x = x.abs();
    let t = 1.0 / (1.0 + 0.3275911 * x);
    let poly = t * (0.254829592 + t * (-0.284496736 + t * (1.421413741
        + t * (-1.453152027 + t * 1.061405429))));
    sign * (1.0 - poly * (-x * x).exp())
}

fn normal_cdf(z: f64) -> f64 {
    0.5 * (1.0 + erf(z / 2f64.sqrt()))
}

fn main() {
    println!("{:.4}", normal_cdf(1.96)); // 0.9750
    println!("{:.4}", normal_cdf(0.0)); // 0.5000
}

3. Confidence Interval for the Mean ​

Confidence Interval for the Mean

Formula:

x¯±z∗sn95% CI:z∗=1.96

This uses the normal distribution, which works well for large samples. For small samples, use the t value for n−1 degrees of freedom instead of 1.96.

Where it's used: reporting an estimate together with its uncertainty, such as model accuracy across test runs.

markdown
$$
\bar{x} \pm z^{*} \, \frac{s}{\sqrt{n}} \qquad 95\% \text{ CI}: \; z^{*} = 1.96
$$
python
import math

def confidence_interval(mean: float, s: float, n: int, z: float = 1.96):
    margin = z * s / math.sqrt(n)
    return round(mean - margin, 2), round(mean + margin, 2)

print(confidence_interval(50, 10, 100))  # (48.04, 51.96)
rust
fn confidence_interval(mean: f64, s: f64, n: f64, z: f64) -> (f64, f64) {
    let margin = z * s / n.sqrt();
    (mean - margin, mean + margin)
}

fn main() {
    let (low, high) = confidence_interval(50.0, 10.0, 100.0, 1.96);
    println!("({:.2}, {:.2})", low, high); // (48.04, 51.96)
}

4. One-Sample z-Test ​

One-Sample z-Test

Formula:

z=x¯−μ0σ/np=2(1−Φ(|z|))

Use it when the population standard deviation σ is known. This is a two-sided test, so the p-value counts both tails.

Where it's used: checking whether a sample mean is really different from a target value.

markdown
$$
z = \frac{\bar{x} - \mu_0}{\sigma / \sqrt{n}} \qquad p = 2 \big( 1 - \Phi(\lvert z \rvert) \big)
$$
python
import math

def normal_cdf(z: float) -> float:
    return 0.5 * (1 + math.erf(z / math.sqrt(2)))

def z_test(mean: float, mu0: float, sigma: float, n: int):
    z = (mean - mu0) / (sigma / math.sqrt(n))
    p = 2 * (1 - normal_cdf(abs(z)))
    return round(z, 4), round(p, 4)

print(z_test(52, 50, 10, 100))  # (2.0, 0.0455)
rust
// Rust's standard library has no erf, so this uses the Abramowitz and Stegun
// approximation, accurate to about 7 decimal places.
fn erf(x: f64) -> f64 {
    let sign = if x < 0.0 { -1.0 } else { 1.0 };
    let x = x.abs();
    let t = 1.0 / (1.0 + 0.3275911 * x);
    let poly = t * (0.254829592 + t * (-0.284496736 + t * (1.421413741
        + t * (-1.453152027 + t * 1.061405429))));
    sign * (1.0 - poly * (-x * x).exp())
}

fn normal_cdf(z: f64) -> f64 {
    0.5 * (1.0 + erf(z / 2f64.sqrt()))
}

fn z_test(mean: f64, mu0: f64, sigma: f64, n: f64) -> (f64, f64) {
    let z = (mean - mu0) / (sigma / n.sqrt());
    let p = 2.0 * (1.0 - normal_cdf(z.abs()));
    (z, p)
}

fn main() {
    let (z, p) = z_test(52.0, 50.0, 10.0, 100.0);
    println!("{:.4} {:.4}", z, p); // 2.0000 0.0455
}

5. One-Sample t-Test ​

One-Sample t-Test

Formula:

t=x¯−μ0s/n,df=n−1

Use it when you only have the sample standard deviation s. Compare t with a t-table: for 5 degrees of freedom, the 95% two-sided cut-off is 2.571, so t=1.89 is not significant.

Where it's used: testing a mean with a small sample, such as a few repeated experiments.

markdown
$$
t = \frac{\bar{x} - \mu_0}{s / \sqrt{n}}, \qquad \text{df} = n - 1
$$
python
import math

def t_statistic(values: list[float], mu0: float):
    n = len(values)
    m = sum(values) / n
    s = math.sqrt(sum((x - m) ** 2 for x in values) / (n - 1))
    return round((m - mu0) / (s / math.sqrt(n)), 4), n - 1

print(t_statistic([5.1, 4.9, 5.3, 5.5, 5.0, 5.2], 5))  # (1.8898, 5)
rust
fn t_statistic(values: &[f64], mu0: f64) -> (f64, usize) {
    let n = values.len() as f64;
    let m = values.iter().sum::<f64>() / n;
    let s = (values.iter().map(|x| (x - m).powi(2)).sum::<f64>() / (n - 1.0)).sqrt();
    ((m - mu0) / (s / n.sqrt()), values.len() - 1)
}

fn main() {
    let (t, df) = t_statistic(&[5.1, 4.9, 5.3, 5.5, 5.0, 5.2], 5.0);
    println!("{:.4} {}", t, df); // 1.8898 5
}

6. Two-Sample t-Test ​

Two-Sample t-Test

Formula:

t=x¯1−x¯2s12n1+s22n2

This is Welch's t-test, which does not assume the two groups have the same variance.

Where it's used: A/B testing, and comparing two models, groups or treatments.

markdown
$$
t = \frac{\bar{x}_1 - \bar{x}_2}{\sqrt{\frac{s_1^2}{n_1} + \frac{s_2^2}{n_2}}}
$$
python
import math

def welch_t(a: list[float], b: list[float]) -> float:
    def mean_var(x):
        m = sum(x) / len(x)
        return m, sum((v - m) ** 2 for v in x) / (len(x) - 1)
    m1, v1 = mean_var(a)
    m2, v2 = mean_var(b)
    return (m1 - m2) / math.sqrt(v1 / len(a) + v2 / len(b))

print(round(welch_t([20, 22, 19, 24, 25], [18, 17, 20, 16, 19]), 4))  # 2.9814
rust
fn mean_var(x: &[f64]) -> (f64, f64) {
    let n = x.len() as f64;
    let m = x.iter().sum::<f64>() / n;
    (m, x.iter().map(|v| (v - m).powi(2)).sum::<f64>() / (n - 1.0))
}

fn welch_t(a: &[f64], b: &[f64]) -> f64 {
    let (m1, v1) = mean_var(a);
    let (m2, v2) = mean_var(b);
    (m1 - m2) / (v1 / a.len() as f64 + v2 / b.len() as f64).sqrt()
}

fn main() {
    let a = [20.0, 22.0, 19.0, 24.0, 25.0];
    let b = [18.0, 17.0, 20.0, 16.0, 19.0];
    println!("{:.4}", welch_t(&a, &b)); // 2.9814
}

7. Chi-Squared Statistic ​

Chi-Squared Statistic

Formula:

χ2=∑i(Oi−Ei)2Ei

Oi are the observed counts and Ei the expected counts. Compare the result with a chi-squared table: for 3 degrees of freedom, the 5% cut-off is 7.815.

Where it's used: testing whether counts match what you expected, and whether categories are related.

markdown
$$
\chi^2 = \sum_{i} \frac{(O_i - E_i)^2}{E_i}
$$
python
def chi_squared(observed: list[float], expected: list[float]) -> float:
    return sum((o - e) ** 2 / e for o, e in zip(observed, expected))

print(chi_squared([18, 22, 20, 40], [25, 25, 25, 25]))  # 12.32
rust
fn chi_squared(observed: &[f64], expected: &[f64]) -> f64 {
    observed.iter().zip(expected).map(|(o, e)| (o - e).powi(2) / e).sum()
}

fn main() {
    println!("{}", chi_squared(&[18.0, 22.0, 20.0, 40.0], &[25.0; 4])); // 12.32
}

8. Binomial Probability ​

Binomial Probability

Formula:

P(X=k)=(nk)pk(1−p)n−k

Python has math.comb built in. Rust does not, so the code calculates the combination step by step.

Where it's used: the chance of exactly k successes, such as 3 heads in 10 coin flips.

markdown
$$
P(X = k) = \binom{n}{k} p^{k} (1 - p)^{n - k}
$$
python
import math

def binomial_pmf(k: int, n: int, p: float) -> float:
    return math.comb(n, k) * p**k * (1 - p)**(n - k)

print(round(binomial_pmf(3, 10, 0.5), 4))  # 0.1172
rust
fn comb(n: u64, k: u64) -> f64 {
    (0..k).fold(1.0, |acc, i| acc * (n - i) as f64 / (i + 1) as f64)
}

fn binomial_pmf(k: u64, n: u64, p: f64) -> f64 {
    comb(n, k) * p.powi(k as i32) * (1.0 - p).powi((n - k) as i32)
}

fn main() {
    println!("{:.4}", binomial_pmf(3, 10, 0.5)); // 0.1172
}

9. Simple Linear Regression and R² ​

Simple Linear Regression and R²

Formula:

β1=∑i(xi−x¯)(yi−y¯)∑i(xi−x¯)2β0=y¯−β1x¯R2=1−∑i(yi−y^i)2∑i(yi−y¯)2

The fitted line is y^=β0+β1x. R2 is the share of the variation in y that the line explains.

Where it's used: predicting one variable from another, the first model in Machine Learning.

markdown
$$
\beta_1 = \frac{\sum_{i} (x_i - \bar{x})(y_i - \bar{y})}{\sum_{i} (x_i - \bar{x})^2} \qquad \beta_0 = \bar{y} - \beta_1 \bar{x} \qquad R^2 = 1 - \frac{\sum_{i} (y_i - \hat{y}_i)^2}{\sum_{i} (y_i - \bar{y})^2}
$$
python
def linear_regression(x: list[float], y: list[float]):
    n = len(x)
    mx, my = sum(x) / n, sum(y) / n
    b1 = sum((a - mx) * (b - my) for a, b in zip(x, y)) / sum((a - mx) ** 2 for a in x)
    b0 = my - b1 * mx
    ss_res = sum((b - (b0 + b1 * a)) ** 2 for a, b in zip(x, y))
    ss_tot = sum((b - my) ** 2 for b in y)
    return round(b1, 4), round(b0, 4), round(1 - ss_res / ss_tot, 4)

print(linear_regression([1, 2, 3, 4, 5], [2, 4, 5, 4, 5]))  # (0.6, 2.2, 0.6)
rust
fn linear_regression(x: &[f64], y: &[f64]) -> (f64, f64, f64) {
    let n = x.len() as f64;
    let mx = x.iter().sum::<f64>() / n;
    let my = y.iter().sum::<f64>() / n;
    let b1 = x.iter().zip(y).map(|(a, b)| (a - mx) * (b - my)).sum::<f64>()
        / x.iter().map(|a| (a - mx).powi(2)).sum::<f64>();
    let b0 = my - b1 * mx;
    let ss_res: f64 = x.iter().zip(y).map(|(a, b)| (b - (b0 + b1 * a)).powi(2)).sum();
    let ss_tot: f64 = y.iter().map(|b| (b - my).powi(2)).sum();
    (b1, b0, 1.0 - ss_res / ss_tot)
}

fn main() {
    let (b1, b0, r2) = linear_regression(&[1.0, 2.0, 3.0, 4.0, 5.0], &[2.0, 4.0, 5.0, 4.0, 5.0]);
    println!("{:.4} {:.4} {:.4}", b1, b0, r2); // 0.6000 2.2000 0.6000
}

10. Bayes' Theorem ​

Bayes' Theorem

Formula:

P(D∣+)=P(+∣D)P(D)P(+∣D)P(D)+P(+∣¬D)P(¬D)

Example: a disease affects 1% of people, the test catches 99% of cases, and gives a false positive 5% of the time. A positive result still means only about a 16.67% chance of having the disease.

Where it's used: medical tests, spam filters and Naive Bayes classifiers.

markdown
$$
P(D \mid +) = \frac{P(+ \mid D) \, P(D)}{P(+ \mid D) \, P(D) + P(+ \mid \neg D) \, P(\neg D)}
$$
python
def bayes(prior: float, sensitivity: float, false_positive: float) -> float:
    true_pos = sensitivity * prior
    false_pos = false_positive * (1 - prior)
    return true_pos / (true_pos + false_pos)

print(round(bayes(0.01, 0.99, 0.05), 4))  # 0.1667
rust
fn bayes(prior: f64, sensitivity: f64, false_positive: f64) -> f64 {
    let true_pos = sensitivity * prior;
    let false_pos = false_positive * (1.0 - prior);
    true_pos / (true_pos + false_pos)
}

fn main() {
    println!("{:.4}", bayes(0.01, 0.99, 0.05)); // 0.1667
}

✅Summarized reviews based on Kittycat's insights from the best online courses at top universities