【问题标题】:Fitting multimodal distributions in R; generating new values from fitted distribution在 R 中拟合多峰分布;从拟合分布中生成新值
【发布时间】:2013-07-29 07:09:45
【问题描述】:

我正在处理小样本数据:

>dput(dat.demand2050.unique)  
c(79, 56, 69, 61, 53, 73, 72, 86, 75, 68, 74.2, 80, 65.6, 60, 54)    

其密度分布如下所示:

我知道这些值来自两个状态 - 低和高 - 并假设底层过程是正常的,我使用 mixtools 包来拟合双峰分布:

set.seed(99)  
dat.demand2050.mixmdl <- normalmixEM(dat.demand2050.unique, lambda=c(0.3,0.7), mu=c(60,70), k=2)

这给了我以下结果:

(实线为拟合曲线,虚线为原始密度)。

# get the parameters of the mixture
dat.demand2050.mixmdl.prop <- dat.demand2050.mixmdl$lambda    #mix proportions
dat.demand2050.mixmdl.means <- dat.demand2050.mixmdl$mu    #modal means
dat.demand2050.mixmdl.dev <- dat.demand2050.mixmdl$sigma   #modal std dev  

混合参数为:

>dat.demand2050.mixmdl.prop  #mix proportions  
[1] 0.2783939 0.7216061  
>dat.demand2050.mixmdl.means  #modal means  
[1] 56.21150 73.08389  
>dat.demand2050.mixmdl.dev  #modal std dev  
[1] 3.098292 6.413906 

我有以下问题:

  1. 要生成一组近似于基础分布的新值,我的方法是正确的还是有更好的工作流程?
  2. 如果我的方法是正确的,我如何使用这个结果从这个混合分布中生成一组随机值?

【问题讨论】:

  • 我认为这个问题可能更适合 CrossValidated:stats.stackexchange.com
  • @DavidMarx 是的,我对此进行了辩论,甚至是否要交叉发布,但最终决定在这里写,因为我的第二个问题更多的是关于编码。但是,如果模组认为它更适合那里,我很乐意这样做。
  • 我不确定您的方法是否明智。您没有指定您打算如何处理随机数。此外,您的样本量非常小,从如此小的样本量估计正态分布有点可疑。也许引导程序是实现最终目标的更好方法?
  • @Roland 是的,样本量很小,但这就是我所拥有的。这些数据来自一组研究,而且只有这么多。我曾想过使用sample() 进行引导,但必须回到我的笔记中,为什么我没有采用这种方法..也许这部分讨论应该继续进行交叉验证..
  • 问题是你想从随机数中推断出什么。您的样本量可能太小,无法从您的方法中推断出任何合理的结果。

标签: r distribution random-sample mixed-models


【解决方案1】:

您的样本量是否适合混合有点令人怀疑,但没关系。您可以按如下方式从拟合的混合物中采样:

probs <- dat.demand2050.mixmdl$lambda
m <- dat.demand2050.mixmdl$mu
s <- at.demand2050.mixmdl$sigma

N <- 1e5
grp <- sample(length(probs), N, replace=TRUE, prob=probs)
x <- rnorm(N, m[grp], s[grp])

【讨论】:

  • 您的方法似乎过分强调了较低的分布,就像 Roland 的解决方案一样。将您的输出密度与@CnrL 解决方案的起始密度和输出进行比较。这段代码看起来正确,但结果似乎不对。我不知道为什么。
  • 结果和@CnrL 的完全一样。用 N = 1e5 运行他们的解决方案。至于起始密度;谁知道 15 个数据点会发生什么。
  • @DavidMarx 两种解决方案都没有给出与原始样本相同的密度图。这是一个样本量问题。
  • 查看我对为什么我使用小尺寸的问题的评论。我用大 N 运行了@CnrL 解决方案(检查我之前评论中的链接),它仍然给出了一个较低的峰值..
  • @HongOoi 我没有得到与 CrnL 解决方案相同的结果。这是我从您的解决方案 (N=1e5)、他的解决方案 (N=1e5) 和原始小数据集获得的密度的比较。:i.imgur.com/cMKnhhf.jpg
【解决方案2】:

你的方法是正确的。

对于混合分布中的每个样本,您只需选择样本应来自两个分量高斯分布中的哪一个,然后从该分布中抽取样本。

您可以使用找到的混合比例在两个分布之间进行选择:模拟 0 到 1 之间的随机数,如果随机数小于第一个比例,则从第一个分布中采样,否则从第二个分布中采样.

最后,使用 rnorm 函数从相关的高斯分布中采样。

dat.demand2050.mixmdl.prop=c(0.2783939,0.7216061)
dat.demand2050.mixmdl.means=c(56.21150,73.08389)
dat.demand2050.mixmdl.dev=c(3.098292,6.413906)

sampleMixture=function(prop,means,dev){
    # Generate a uniformly distributed random number between 0 and 1
    # in order to choose between the two component distributions
    distTest=runif(1)
    if(distTest<prop[1]){
        # Then sample from the first component of the mixture
        sample=rnorm(1,mean=means[1],sd=dev[1])
    }else{
        # Sample from the second component of the mixture
        sample=rnorm(1,mean=means[2],sd=dev[2])
    }
    return(sample)
}

# Generate a single sample
sampleMixture(dat.demand2050.mixmdl.prop,dat.demand2050.mixmdl.means,dat.demand2050.mixmdl.dev)

# Generate 100 samples and plot resulting distribution
samples=replicate(100,sampleMixture(dat.demand2050.mixmdl.prop,dat.demand2050.mixmdl.means,dat.demand2050.mixmdl.dev))
plot(density(samples))

【讨论】:

  • 不客气。不,这并不意味着。这是因为“如果”条件。使用 runif() 只是将随机性引入分布之间的选择的一种方式。 runif() 返回的值恰好有 28% 的机会小于 0.28(相反,有 72% 的机会返回更大的值)。通过检查 runif 是否大于或小于第一个比例(在本例中为 0.28)并相应地选择混合物的第一个或第二个成分,我们正确地加权概率。
  • 谢谢,您的解决方案似乎运作良好。然而,runif() 的选择 distTest 是否意味着它来自任一分布的值同样可能,而数据(和拟合)表明“概率”约为 0.3 和 0.7?跨度>
  • 你应该避免循环。从两个正态分布和均匀分布中各创建 100 个样本,并使用 ifelse
  • @AdvaitGodbole 在if 语句中考虑了这些概率。该函数从均匀分布中采样,以便我们从一种或另一种混合物中随机选择,但该选择将按照这些概率的规定进行。
  • @Roland 你上面的建议肯定会让事情变得更快,你下面的答案非常优雅,但是我更喜欢上面速度较慢的代码来解决这个问题,因为我认为它让 OP 更清楚如何采样工作。
猜你喜欢
  • 2019-06-06
  • 2017-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-02
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
相关资源
最近更新 更多