根据区间内的分布生成随机数

机器算法验证 r 正态分布 matlab 模拟 随机生成
2022-01-20 02:00:00

我需要在区间内按照正态分布生成随机数(a,b). (我在 R 工作。)

我知道该函数rnorm(n,mean,sd)会按照正态分布生成随机数,但是如何在其中设置区间限制?是否有任何特定的 R 函数可用?

4个回答

听起来您想从截断的分布中进行模拟,在您的具体示例中,是截断的 normal

有多种方法可以做到这一点,有些简单,有些相对有效。

我将在您的正常示例中说明一些方法。

  1. 这是一次生成一个非常简单的方法(在某种伪代码中):

    repeat产生xi从 N(平均值,标准差)until降低xi

    在此处输入图像描述

    如果大部分分布都在界限内,这是非常合理的,但如果您几乎总是在界限之外生成,它可能会变得很慢。

    在 R 中,您可以通过计算边界内的区域来避免一次一个循环,并生成足够的值,您几乎可以肯定,在丢弃边界外的值后,您仍然拥有所需数量的值。

  2. 您可以在间隔内使用带有一些合适的专业化函数的接受拒绝(在某些情况下,统一就足够了)。例如,如果限制相对于 sd 相当窄,但您离尾部不远,则统一的专业化将适用于正常情况。

    在此处输入图像描述

  3. 如果您有相当有效的 cdf 和逆 cdf(例如对于 Rpnorm中的正态分布),您可以使用截断法线的维基百科页面qnorm的模拟部分第一段中描述的逆 cdf 方法[实际上,这与采用截断的统一(在所需的分位数处截断,实际上根本不需要拒绝,因为这只是另一个统一)并对其应用逆正态 cdf 相同。请注意,如果您远远落后,这可能会失败]

    在此处输入图像描述

  4. 还有其他方法;同一个维基百科页面提到了调整ziggurat方法,它应该适用于各种发行版。

一个 Wikipedia 链接提到了两个特定的包(都在 CRAN 上),它们具有生成截断法线的功能:

R 中的MSM包有一个函数 ,rtnorm它计算截断法线的绘制。R 中的truncnorm包还具有从截断法线中提取的功能。


环顾四周,其中很多都包含在其他问题的答案中(但不完全重复,因为这个问题比截断的法线更笼统)......请参阅

一种。这个答案

湾。Xi'an's answer here,其中有他的 arXiv 论文的链接(以及其他一些有价值的回复)。

快速而简单的方法是使用68-95-99.7 规则

在正态分布中,99.7% 的值落在平均值的 3 个标准差以内。因此,如果将平均值设置为所需最小值和最大值的中间值,并将标准差设置为平均值的 1/3,则(大部分)值会落在所需区间内。然后你就可以清理剩下的了。

minVal <- 0
maxVal <- 100
mn <- (maxVal - minVal)/2
# Generate numbers (mostly) from min to max
x <- rnorm(count, mean = mn, sd = mn/3)
# Do something about the out-of-bounds generated values
x <- pmax(minVal, x)
x <- pmin(maxVal, x)

我最近遇到了同样的问题,试图为测试数据生成随机学生成绩在上面的代码中,我使用pmaxandpmin用最小或最大界内值替换了界外值。这适用于我的目的,因为我生成的数据量相当小,但对于大量数据,它会在最小值和最大值处给您带来明显的颠簸。因此,根据您的目的,最好丢弃这些值,用NAs 替换它们,或者“重新滚动”它们直到它们在界内。

这里没有一个答案给出了生成截断正常变量的有效方法,该方法不涉及拒绝任意大量生成的值。如果要从截断的正态分布生成值,并指定下限和上限a<b,这可以通过在截断允许的分位数范围内生成统一的分位数并使用逆变换采样来获得相应的正常值来完成——无需拒绝。

Φ表示标准正态分布的 CDF。我们要生成X1,...,XN从截断的正态分布(平均参数μ和方差参数σ2)具有截断上下界a<b. 这可以按如下方式完成:

Xi=μ+σΦ1(Ui)U1,...,UNIID U[Φ(aμσ),Φ(bμσ)].

从截断分布中生成的值没有内置函数,但是使用普通函数来编程这个方法来生成随机变量是微不足道的。这是一个简单的R函数rtruncnorm,只需几行代码即可实现此方法。

rtruncnorm <- function(N, mean = 0, sd = 1, a = -Inf, b = Inf) {
  if (a > b) stop('Error: Truncation range is empty');
  U <- runif(N, pnorm(a, mean, sd), pnorm(b, mean, sd));
  qnorm(U, mean, sd); }

这是一个向量化函数,将从N截断的正态分布中生成 IID 随机变量。通过相同的方法为其他截断分布编写函数会很容易。为截断分布编程相关的密度和分位数函数也不会太困难。


请注意,截断会改变分布的均值和方差,因此μσ2不是截断分布均值和方差。

三种方法对我有用:

  1. 使用带有 rnorm() 的 sample():

    sample(x=min:max, replace= TRUE, rnorm(n, mean))

  2. 使用 msm 包和 rtnorm 函数:

    rtnorm(n, mean, lower=min, upper=max)

  3. 使用 rnorm() 并指定下限和上限,正如 Hugh 在上面发布的那样:

    sample <- rnorm(n, mean=mean); sample <- sample[x > min & x < max]