如何从截断正态分布中获得最佳样本?

2024-03-28 21:48:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经做了一些搜索,但我似乎无法找到一种合理的方法从截断正态分布中取样

没有截断,我正在做:

samples = [np.random.normal(loc=x,scale=d) for (x,d) in zip(X,D)]

XD是浮动列表

目前,我正在实施截断:

def truncnorm(loc,scale,bounds):
  s = np.random.normal(loc,scale)
  if s > bounds[1]:
    return bounds[1]
  elif s < bounds[0]:
    return bounds[0]
  return s

samples = [truncnorm(loc=x,scale=d,bounds=b) for (x,d,b) in zip(X,D,bounds)]

bounds是元组的列表(min,max)

这种方法感觉有点尴尬,所以我想知道是否有更好的方法


Tags: 方法in列表forreturnnprandomzip
1条回答
网友
1楼 · 发布于 2024-03-28 21:48:44

为超出边界的样本返回边界值将导致太多样本落在边界上。这并不代表实际的分布情况。边界上的值需要被拒绝并替换为新样本。这种代码可以是:

def test_truncnorm(loc, scale, bounds):
    while True:
        s = np.random.normal(loc, scale)
        if bounds[0] <= s <= bounds[1]:
            break
    return s

考虑到狭窄的边界,这可能非常缓慢。 Scipy的truncnorm更有效地处理此类案件。有点奇怪,边界是用标准法线的函数表示的,所以您的调用是:

s = scipy.stats.truncnorm.rvs((bounds[0]-loc)/scale, (bounds[1]-loc)/scale, loc=loc, scale=scale)

注意,使用numpy的vectorization and broadcasting时,scipy的工作速度要快得多。一旦你习惯了这种符号,它的书写和阅读也会变得简单。所有样品可一次性计算,如下所示:

X = np.array(X)
D = np.array(D)
bounds = np.array(bounds)
samples = scipy.stats.truncnorm.rvs((bounds[:, 0] - X) / D, (bounds[:, 1] - X) / D, loc=X, scale=D)

相关问题 更多 >