一、核心概念

1. 随机分布(Random Distributions)

在统计学中,随机分布描述了随机变量取值的概率规律。Java 中常用分布包括:

  • 均匀分布(Uniform):所有值等概率出现(如掷骰子)
  • 正态分布(Normal/Gaussian):钟形曲线,自然界常见(如身高、考试成绩)
  • 指数分布(Exponential):描述事件发生的时间间隔(如客户到达时间)
  • 泊松分布(Poisson):单位时间内事件发生的次数(如每小时电话数量)

2. 置信区间(Confidence Interval)

置信区间是对总体参数(如均值)的区间估计,表示“我们有 X% 的信心认为真实均值落在这个区间内”。

  • 常见置信水平:90%、95%、99%
  • 公式(正态分布,σ 已知):
    \[ \bar{x} \pm z \cdot \frac{\sigma}{\sqrt{n}} \]
  • 公式(t 分布,σ 未知):
    \[ \bar{x} \pm t \cdot \frac{s}{\sqrt{n}} \]

二、Java 实现工具与库

工具 说明
java.util.Random 基础随机数生成,仅支持均匀分布
java.util.concurrent.ThreadLocalRandom 高并发场景下的随机数生成
Apache Commons Math 推荐! 提供完整的统计与分布支持
java.security.SecureRandom 安全性要求高的场景(如加密)

强烈建议使用 Apache Commons Math:功能完整、文档丰富、性能优秀。

添加依赖(Maven)

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-math3</artifactId>
    <version>3.6.1</version>
</dependency>

三、操作步骤(超详细)

步骤 1:生成随机分布数据

1.1 正态分布(Normal Distribution)

import org.apache.commons.math3.distribution.NormalDistribution;

public class RandomDistributionExample {
    public static void main(String[] args) {
        // 创建正态分布:均值=100,标准差=15(如 IQ 分数)
        NormalDistribution normal = new NormalDistribution(100, 15);

        // 生成 10 个随机样本
        for (int i = 0; i < 10; i++) {
            double sample = normal.sample();
            System.out.printf("Sample %d: %.2f%n", i + 1, sample);
        }

        // 计算概率密度(PDF)和累积概率(CDF)
        double x = 115;
        double pdf = normal.density(x);  // 概率密度
        double cdf = normal.cumulativeProbability(x); // P(X <= 115)

        System.out.printf("PDF at x=115: %.4f%n", pdf);
        System.out.printf("P(X <= 115): %.4f%n", cdf);
    }
}

1.2 泊松分布(Poisson Distribution)

import org.apache.commons.math3.distribution.PoissonDistribution;

PoissonDistribution poisson = new PoissonDistribution(3.0); // λ = 3

for (int i = 0; i < 5; i++) {
    int sample = poisson.sample();
    System.out.println("Poisson sample: " + sample);
}

1.3 指数分布(Exponential Distribution)

import org.apache.commons.math3.distribution.ExponentialDistribution;

ExponentialDistribution exp = new ExponentialDistribution(2.0); // λ = 2

double waitTime = exp.sample();
System.out.printf("Next event in: %.2f units%n", waitTime);

步骤 2:计算置信区间(95%)

场景:我们有一组样本数据,估计总体均值的 95% 置信区间

import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math3.distribution.TDistribution;

public class ConfidenceIntervalExample {
    public static void main(String[] args) {
        // 样本数据(例如:测量值)
        double[] samples = {102, 98, 105, 110, 95, 103, 107, 99, 101, 104};

        // 1. 计算样本统计量
        DescriptiveStatistics stats = new DescriptiveStatistics();
        for (double val : samples) {
            stats.addValue(val);
        }

        double sampleMean = stats.getMean();        // 样本均值
        double sampleStdDev = stats.getStandardDeviation(); // 样本标准差
        int n = stats.getN();                       // 样本大小

        // 2. 设置置信水平(95%)
        double confidenceLevel = 0.95;
        double alpha = 1 - confidenceLevel;         // 0.05

        // 3. 使用 t 分布(因为总体标准差未知)
        TDistribution tDist = new TDistribution(n - 1); // 自由度 = n-1
        double tCritical = tDist.inverseCumulativeProbability(1 - alpha / 2);

        // 4. 计算标准误差(Standard Error)
        double standardError = sampleStdDev / Math.sqrt(n);

        // 5. 计算置信区间
        double marginOfError = tCritical * standardError;
        double lowerBound = sampleMean - marginOfError;
        double upperBound = sampleMean + marginOfError;

        // 6. 输出结果
        System.out.printf("样本均值: %.2f%n", sampleMean);
        System.out.printf("样本标准差: %.2f%n", sampleStdDev);
        System.out.printf("95%% 置信区间: [%.2f, %.2f]%n", lowerBound, upperBound);
        System.out.printf("误差范围: ±%.2f%n", marginOfError);
    }
}

✅ 输出示例:

样本均值: 102.40
样本标准差: 4.83
95% 置信区间: [98.76, 106.04]
误差范围: ±3.64

四、常见错误与注意事项

❌ 常见错误

错误 说明 修复方法
使用 Random.nextGaussian() 但不知是标准正态 nextGaussian() 生成 N(0,1),需线性变换 mean + stdDev * random.nextGaussian()
σ 已知时仍用 t 分布 浪费精度,应使用 z 分布 σ 已知 → z;σ 未知 → t
忽略样本大小 n < 30 小样本下正态假设不成立 小样本优先用 t 分布
多次调用 new Random() 导致重复种子 时间种子精度低,多线程易重复 使用 ThreadLocalRandom 或单例 Random

✅ 注意事项

  1. 分布选择:根据实际场景选择分布类型,不要强行用正态分布。
  2. 样本独立性:确保样本是独立同分布(i.i.d),否则统计无效。
  3. 置信区间解释:不是“有 95% 概率包含真值”,而是“重复实验 100 次,约 95 次区间包含真值”。
  4. 边界检查:对 inverseCumulativeProbability 输入值应在 (0,1) 范围内。

五、使用技巧与最佳实践

✅ 技巧 1:封装置信区间计算工具类

public class ConfidenceIntervalUtils {
    public static double[] computeConfidenceInterval(double[] data, double confidenceLevel) {
        DescriptiveStatistics stats = new DescriptiveStatistics();
        for (double d : data) stats.addValue(d);

        int df = stats.getN() - 1;
        double t = new TDistribution(df).inverseCumulativeProbability(1 - (1 - confidenceLevel) / 2);
        double se = stats.getStandardDeviation() / Math.sqrt(stats.getN());
        double margin = t * se;

        return new double[]{stats.getMean() - margin, stats.getMean() + margin};
    }
}

✅ 技巧 2:使用 ThreadLocalRandom 提升性能

// 推荐:线程安全且高效
double uniform = ThreadLocalRandom.current().nextDouble(0, 1);
double gaussian = // 仍需转换或使用 Commons Math

✅ 技巧 3:预生成随机数池(高频调用场景)

// 对性能要求极高时,可预生成随机数数组复用
double[] randomPool = new double[1000];
NormalDistribution norm = new NormalDistribution(0, 1);
for (int i = 0; i < randomPool.length; i++) {
    randomPool[i] = norm.sample();
}
// 使用时从 pool 取,定期刷新

六、性能优化建议

优化点 建议
避免频繁创建分布对象 如正态分布参数不变,应复用实例
小样本慎用 Bootstrap Bootstrap 重采样计算量大,n > 1000 再考虑
使用 DescriptiveStatistics 批量处理 比逐个计算 mean/std 更快
并发场景使用 ThreadLocalRandom Random 性能提升 3-5 倍

七、扩展:蒙特卡洛模拟示例(估算 π)

public static double estimatePi(int numSamples) {
    int insideCircle = 0;
    for (int i = 0; i < numSamples; i++) {
        double x = ThreadLocalRandom.current().nextDouble(-1, 1);
        double y = ThreadLocalRandom.current().nextDouble(-1, 1);
        if (x*x + y*y <= 1) insideCircle++;
    }
    return 4.0 * insideCircle / numSamples;
}

总结

项目 推荐做法
随机分布 使用 Apache Commons Math
置信区间 小样本用 t 分布,大样本可用 z 近似
性能 复用对象、使用 ThreadLocalRandom
实践 封装工具类,避免重复代码