文章目录

  • 1、简介
  • 2、RandomDataGenerator
  • 3、随机向量: RandomVector
  • 4、准随机序列
  • 5、随机排序、混合、采样


1、简介

英文

中文

Uniform Distribution

均匀分布

bivariate normal distribution

二元正态分布

PRNG(pseudo-random number generator)

伪随机数产生器

org.apache.commons.math3.random 包中包含以下工具类:

  • 生成随机数值
  • 生成随机向量
  • 生成随机字符串
  • 生成安全的随机数
  • 生成随机样本或序列
  • 分析输入文件中值的分布情况,并生成类似的数据;
  • generating data for grouped frequency distributions or histograms

工具类产生的随机数都是伪随机,当给定 seed 后,序列中的值是确定的,是可预测的:

public void randomTest() {
        Random random = new Random(100);
        for (int i = 0; i < 10; i++) {
            System.out.print(random.nextInt());
            System.out.print(" ");
        }

// -1193959466 -1139614796 837415749 -1220615319 -1429538713 118249332 -951589224 1301674577 -1638067850 -1279751870 
        System.out.println("");
        random = new Random(100);
        for (int i = 0; i < 10; i++) {
            System.out.print(random.nextInt());
            System.out.print(" ");
        }
// -1193959466 -1139614796 837415749 -1220615319 -1429538713 118249332 -951589224 1301674577 -1638067850 -1279751870 
    }

从上例可见,相同的 seed 产生的随机序列也是相同的。

可以通过配置来生成符合特定概率分布的随机序列,随机数之间并不是完全孤立的,只是看起来很随机。使用 JDK 自带的 Math.random() 生成的数据符合均匀分布,也就是说所有数值平均的分布在 0,1 之间,出现的概率相等。

java如何快速构造mock模拟数据 java生成模拟数据_math3

尽管产生的数据看上去很随机,但是根据产生器的算法,对应的随机序列是完全可以预测的,当需要获取不可预测的随机序列时,就需要 SecureRandom 产生器。一般情况,安全的随机数产生器会基于真正随机的事物,比如白噪音等。

UniformRandomProvider rg = RandomUtils.asUniformRandomProvider(new java.security.SecureRandom());

2、RandomDataGenerator

1、贝塔分布

在概率论中,贝塔分布,也称B分布,是指一组定义在 区间的连续概率分布,有两个参数 。

java如何快速构造mock模拟数据 java生成模拟数据_随机数_02


通过以下代码,可以模拟贝塔分布的图形:

public void generatorTest() {
        RandomDataGenerator generator = new RandomDataGenerator();
        Frequency frequency = new Frequency();
        for (int i = 0; i < 100000; i++) {
            double value = generator.nextBeta(0.5, 0.5);
            frequency.addValue((int)(value*100));
        }

        double[][] data = new double[100][2];
        for (int i = 0; i < 100; i++) {
            double[] tmp = { i, frequency.getCount(i)};
            data[i] = tmp;
        }

        JavaPlot p = new JavaPlot("D:\\Programs\\gnuplot\\bin\\gnuplot.exe");
        p.addPlot(data);
        p.plot();
    }

最终的显示效果如下:

java如何快速构造mock模拟数据 java生成模拟数据_java如何快速构造mock模拟数据_03


2、Binomial : 二项分布

在概率论和统计学中,二项分布是n个独立的是/非试验中成功的次数的离散概率分布,其中每次试验的成功概率为p。这样的单次成功/失败试验又称为伯努利试验。实际上,当 java如何快速构造mock模拟数据 java生成模拟数据_math3_04

// probabilityOfSuccess 为事件发生的概率,numberOfTrials 为伯努利试验的次数
int nextBinomial(int numberOfTrials, double probabilityOfSuccess) {}

java如何快速构造mock模拟数据 java生成模拟数据_i++_05

3、Cauchy: 柯西分布

柯西分布也叫作柯西一洛伦兹分布,它是以奥古斯丁-路易-柯西与亨德里克-洛伦兹名字命名的连续概率分布,如图所示。其概率密度函数为

java如何快速构造mock模拟数据 java生成模拟数据_i++_06


式中: java如何快速构造mock模拟数据 java生成模拟数据_数据生成_07 为定义分布峰值位置的位置参数; java如何快速构造mock模拟数据 java生成模拟数据_i++_08

double nextCauchy(double median, double scale){}

java如何快速构造mock模拟数据 java生成模拟数据_数据生成_09


模拟数据:

RandomDataGenerator generator = new RandomDataGenerator();
        Frequency frequency = new Frequency();
        for (int i = 0; i < 100000; i++) {
            double value = generator.nextCauchy(0, 0.5);
            frequency.addValue((int)(value*100));
        }

        double[][] data = new double[1000][2];
        for (int i = -500; i < 500; i++) {
            double[] tmp = { i/100D, frequency.getCount(i)/1000D};
            data[i+500] = tmp;
        }

        JavaPlot p = new JavaPlot("D:\\Programs\\gnuplot\\bin\\gnuplot.exe");
        p.addPlot(data);
        p.plot();

java如何快速构造mock模拟数据 java生成模拟数据_math3_10


4、chi-square distribution : 卡方分布

若n个相互独立的随机变量ξ₁,ξ₂,…,ξn ,均服从标准正态分布(也称独立同分布于标准正态分布),则这n个服从标准正态分布的随机变量的平方和构成一新的随机变量,其分布规律称为卡方分布(chi-square distribution): java如何快速构造mock模拟数据 java生成模拟数据_数据生成_11

// @param df the degrees of freedom of the ChiSquare distribution
double nextChiSquare(double df){};

5、 其他

// 泊松分布
long nextPoisson(double mean){};
double nextGamma(double shape, double scale){};
double nextGaussian(double mu, double sigma){};
double nextExponential(double mean){};
double nextF(double numeratorDf, double denominatorDf){};

3、随机向量: RandomVector

有些算法,更需要的可能是一组随机向量,而不是一个个的随机数。

  • UncorrelatedRandomVectorGenerator : 产生不相关的多组随机向量,只需要指定随机向量的标准差即可;
  • CorrelatedRandomVectorGenerator :产生相关的多组随机向量,需要指定所需的协方差矩阵;

生成一组符合高斯分布的随机向量:

RandomVectorGenerator generator = new UncorrelatedRandomVectorGenerator(10, new GaussianRandomGenerator(RandomGeneratorFactory.createRandomGenerator(new Random(100))));

        double[] result = generator.nextVector();
        for (int i = 0; i < result.length; i++) {
            System.out.println(result[i]);
        }

CorrelatedRandomVectorGenerator 的构造函数:

/**
 * @param mean Expected mean values for all components.
 * @param covariance Covariance matrix.
 * @param small Diagonal elements threshold under which  column are
 * considered to be dependent on previous ones and are discarded
 * @param generator underlying generator for uncorrelated normalized
 */
public CorrelatedRandomVectorGenerator(double[] mean,
                                           RealMatrix covariance, double small,
                                           NormalizedRandomGenerator generator){}

其中 mean 参数为 double[] 数组,数组元素为随机向量的均值,二元随机向量对应的数组长度为 2;参数 covariance 是一个 java如何快速构造mock模拟数据 java生成模拟数据_数据生成_12

public void vector3Test() {
        long seed = 17399225432L; // 固定的种子会产生固定的随机序列
        double[] mean = {1, 5};
        double[][] cov = {{1, 0.09}, {0.09, 1}};
        RealMatrix covariance = MatrixUtils.createRealMatrix(cov);
        RandomGenerator rawGenerator = RandomGeneratorFactory.createRandomGenerator(new Random(seed));

        CorrelatedRandomVectorGenerator generator =
                new CorrelatedRandomVectorGenerator(mean, covariance, 1.0e-12 * covariance.getNorm(), new GaussianRandomGenerator(rawGenerator));

        List<double[]> list = new LinkedList<>();
        for (int i = 0; i < 100; i++) {
            double[] source = generator.nextVector();

            double v = source[0];

            int len = list.size();
            if (len == 0) {
                list.add(source);
                continue;
            } else {
                for (int j = 0; j < len ; j++) {
                    if (v <= list.get(j)[0]) {
                        list.add(j, source);
                        break;
                    }
                }
            }

            if (len == list.size()) {
                list.add(source);
            }
        }

        double[][] x1 = new double[100][2];
        double[][] x2 = new double[100][2];
        for (int i = 0; i < 100; i++) {
            double[] vector = list.get(i);
            x1[i][0] = i;
            x2[i][0] = i;
            x1[i][1] = vector[0];
            x2[i][1] = vector[1];
        }

        JavaPlot p = new JavaPlot("D:\\Programs\\gnuplot\\bin\\gnuplot.exe");
        p.addPlot(x1);
        p.addPlot(x2);
        p.plot();

    }

协方差与皮尔逊相关系数之间的转换公式为:

java如何快速构造mock模拟数据 java生成模拟数据_数据生成_13


当 mean = [1, 5], variance = [1, 1], covariance 0.09 (说明两个向量相关性不大):

java如何快速构造mock模拟数据 java生成模拟数据_随机数_14

当 mean = [1, 5], variance = [1, 1], covariance 0.99 (强相关):

java如何快速构造mock模拟数据 java生成模拟数据_i++_15

4、准随机序列

准随机序列又称为低差异序列(low-discrepancy sequence),顾名思义,它们既不是随机序列,也不是伪随机序列,常被用来代替均匀分布随机序列。

高效的生成在高维空间分布均匀的随机数是在计算机程序中非常常见的组成部分。对于一切需要采样的算法来说,分布均匀的随机数就意味着更加优秀的样本分布。光线传递的模拟(渲染)基于蒙特卡洛积分(Monte Carlo Integration),这个过程中采样无处不在,所以好的样本分布直接影响积分过程的收敛速度。与常见的伪随机数对比,低差异序列(Low Discrepancy Sequence)非常广泛的被用在图形,甚至于金融领域。它们除了在高维空间中的分布更加均匀以外还有许多其他的性质更利于渲染程序的执行。

一个直观的理解可以看下面的图片,左边为伪随机数组成的二维点集,右边则是由低差异序列点集的对整个空间的覆盖更加完整。

java如何快速构造mock模拟数据 java生成模拟数据_java如何快速构造mock模拟数据_16


下面是更详细的几组不同类型的序列的比较:

java如何快速构造mock模拟数据 java生成模拟数据_数据生成_17

5、随机排序、混合、采样

Random Permutations, Combinations, Sampling

RandomDataGenerator generator = new RandomDataGenerator();
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        generator.nextSample(list, 4);

        generator.nextPermutation(10, 4);
  • nextSample : 随机采样是从给定的集合中随机选择指定数目的数据
  • nextPermutation : 会先创建一个整数数列,然后从中获取指定数据的数据