将数据估计/拟合到 Android 中的 exGaussian 分布

Estimate / fit data to exGaussian distribution in Android

如何使用 JAVA/Android estimate/fit 指数修正高斯分布 (exGaussian) 的参数?

我需要如下伪代码:

    // some observed data points
    double dataPoints[] = {200,300,400,278,366,466,325,335,322,332};

    // ex-gaussian distribution
    ExponentiallyModifiedGaussianDistribution exGaussian = new ExponentiallyModifiedGaussianDistribution();

    // MLE
    MaximumLikelihoodEstimation MLE = new MaximumLikelihoodEstimation(dataPoints, exGaussian);
    MLE.setGuess(3.0, 1.0, 1.0);
    MLE.compute();

    // get estimated / fitted parameters
    double[] parameterEstimates = MLE.getEstimates();

有一些示例演示了 Gamma Distribution 的参数估计。但是这个lib好像没有开源。

而且我在 JAVA 中找到了一个 ex-gaussian distribution implementation。但是缺少参数估计。

我认为有很多方法可以估计参数,例如使用 最大似然估计 (MLE) 等

更新 1:

我会避免使用 less than 40 dataPoints

更新二:

估计分布参数的一种简单替代方法是矩估计法 (described on wiki)

也许您可以在 stats.stackexchange.com 上得到更好的答案。

但我认为您可以创建一个进行矩匹配的优化算法。基本上你需要最小化样本数据和理论分布之间的第一矩(均值)、第二矩(方差)、第三矩(偏度)等的差异。

您可以将 objective 函数视为矩的和或乘积。您还可以对时刻使用不同的权重(均值获得更高的权重)。

求objective函数的导数可以尝试使用梯度下降法(使用Mathematica或Sage math),甚至可以使用有限差分法对导数进行数值计算。这种方法大量用于估计回归、逻辑回归和人工神经网络的参数。

您还可以使用元启发式算法(遗传、禁忌搜索等)。

估计分布参数的一种简单替代方法是矩量法 (described on wiki)。

实施:

    // some observed data points
    double dataPoints[] = {0.464,0.443,0.424,0.386,0.367,0.382,0.455,0.410,0.411,0.424,0.338,0.355,0.342,0.324,
            0.354,0.322,0.364,0.375,1.085,0.575,0.597,0.464,0.414,0.408,1.156,0.819,1.156,1.024,1.152,1.103,
            0.431,0.378,0.358,0.382,0.354,0.435,0.386,0.361,0.397,0.362,0.334,0.357,0.344,0.362,0.317,0.331,
            0.199,0.351,0.284,0.343,0.354,0.336,0.280,0.312,0.778,0.723,0.755,0.774,0.759,0.762,0.490,0.400,
            0.364,0.439,0.441,0.673};

    DescriptiveStatistics maths = new DescriptiveStatistics(dataPoints);
    double sampleMean = maths.getMean();
    double sampleStdDev = maths.getStandardDeviation();
    double sampleSkev = (Math.abs(sampleMean - maths.getPercentile(50)) / sampleStdDev);

    // parameter estimation using method of moments ex-gaussian distribution
    double mean = sampleMean - sampleStdDev * Math.pow(sampleSkev/2., 1./3) ;
    double stdDev = Math.sqrt(sampleStdDev*(1 - Math.pow(sampleSkev/2., 2./3)));
    double tau = sampleStdDev * (Math.pow(sampleSkev/2., 1./3));
    double lambda = 1 / tau;

    ExponentiallyModifiedGaussianDistribution exGaussian = new ExponentiallyModifiedGaussianDistribution(mean, stdDev, lambda);
    System.out.println(sampleStdDev);
    System.out.println(exGaussian.getStddev());

Gradle 依赖关系:

compile group: 'de.lmu.ifi.dbs.elki', name: 'elki', version: '0.7.1'

compile group: 'org.apache.commons', name: 'commons-math3', version: '3.6'

ELKI 包含分布的各种 估计器 (请注意,对于某些分布,我们有多种估计技术;而对于某些我们还没有 - 请 贡献!):

ExponentiallyModifiedGaussianDistribution dist = 
    EMGOlivierNorbergEstimator.STATIC.estimate(dataPoints, DoubleArrayAdapter.STATIC);

将产生 ExGaussian 分布:

> ExGaussianDistribution(mean=0.2675761092764285, stddev=0.07999178722695827,
      lambda=4.4179732613344)

您也可以尝试最佳拟合估计。

Distribution dist = BestFitEstimator.STATIC.estimate(dataPoints, DoubleArrayAdapter.STATIC);

这表明移位的对数正态分布可能更适合您的数据(但尽管如此,理论上 EMG 可能更适合您的问题 - 移位的对数正态分布总是有点奇怪)。

> LogNormalDistribution(logmean=-1.945322593396174, logstddev=0.968522285758599,
      shift=0.2654438504801123)