【问题标题】:create distribution from a list and generate random numbers which follow that distribution in Python从列表创建分布并在 Python 中生成遵循该分布的随机数
【发布时间】:2015-01-20 23:29:33
【问题描述】:

假设我有一个数字列表(在这个特定示例中,所有数字都在 0.5 到 1.5 之间,当然它是一个离散集)。

my_list=  [0.564, 1.058, 0.779, 1.281, 0.656, 0.863, 0.958, 1.146, 0.742, 1.139, 0.957, 0.548, 0.572, 1.204, 0.868, 0.57, 1.456, 0.586, 0.718, 0.966, 0.625, 0.951, 0.766, 1.458, 0.83, 1.25, 0.7, 1.334, 1.015, 1.43, 1.376, 0.942, 1.252, 1.441, 0.795, 1.25, 0.851, 1.383, 0.969, 0.629, 1.008, 0.729, 0.841, 0.619, 0.63, 1.189, 0.514, 0.899, 0.807, 0.63, 1.101, 0.528, 1.385, 0.838, 0.538, 1.364, 0.702, 1.129, 0.639, 0.557, 1.28, 0.664, 1.021, 1.43, 0.792, 1.229, 0.837, 1.183, 0.54, 0.831, 1.279, 1.385, 1.377, 0.827, 1.32, 0.537, 1.19, 1.446, 1.222, 0.762, 1.302, 0.626, 1.352, 1.316, 1.286, 1.239, 1.027, 1.198, 0.961, 0.515, 0.989, 0.979, 1.123, 0.889, 1.484, 0.734, 0.718, 0.758, 0.782, 1.163, 0.579, 0.744, 0.711, 1.13, 0.598, 0.913, 1.305, 0.684, 1.108, 1.373, 0.945, 0.837, 1.129, 1.005, 1.447, 1.393, 1.493, 1.262, 0.73, 1.232, 0.838, 1.319, 0.971, 1.234, 0.738, 1.418, 1.397, 0.927, 1.309, 0.784, 1.232, 1.454, 1.387, 0.851, 1.132, 0.958, 1.467, 1.41, 1.359, 0.529, 1.139, 1.438, 0.672, 0.756, 1.356, 0.736, 1.436, 1.414, 0.921, 0.669, 1.21, 1.041, 0.597, 0.541, 1.162, 1.292, 0.538, 1.011, 0.828, 1.356, 0.897, 0.831, 1.018, 1.412, 1.363, 1.371, 1.231, 1.278, 0.564, 1.134, 1.324, 0.593, 1.307, 0.66, 1.376, 1.469, 1.315, 0.959, 1.099, 1.313, 1.032, 1.128, 1.175, 0.64, 0.581, 1.09, 0.934, 0.698, 1.272]

我可以从中制作直方图分布图

hist(my_list, bins=20, range=[0.5,1.5])
show()

产生

现在,我想创建另一个随机数列表(假设这个新列表包含 100 个数字),它将遵循相同的分布(不知道如何将离散集链接到连续分布!!!)旧列表 ( my_list ) ,所以如果我从新列表中绘制直方图分布,它基本上会产生相同的直方图分布。

在 Python 2.7 中有什么方法可以做到这一点吗?我提前感谢任何帮助。

【问题讨论】:

  • 您可以使用 approx_dist = scipy.stats.kde.gaussian_kde(my_list) 对您的发行版进行 KDE 近似,然后使用 approx_dist.resample(n) 从中采样。这取决于您希望近似如何工作,所以也许您应该阅读 KDE 并查看它是否满足您的需求。

标签: python random distribution


【解决方案1】:

您首先需要“收集”感兴趣的范围,当然您可以使用来自 scipy &c 的工具来完成,但为了了解发生了什么,一个小的 Python 版本可能会有所帮助 - 无需优化,为便于理解:

import collections

def buckets(discrete_set, amin=None, amax=None, bucket_size=None):
    if amin is None: amin=min(discrete_set)
    if amax is None: amax=min(discrete_set)
    if bucket_size is None: bucket_size = (amax-amin)/20
    def to_bucket(sample):
        if not (amin <= sample <= amax): return None  # no bucket fits
        return int((sample - amin) // bucket_size)
    b = collections.Counter(to_bucket(s)
            for s in discrete_set if to_bucket(s) is not None)
    return amin, amax, bucket_size, b

所以,现在您有一个 Counter(本质上是一个 dict)将每个桶从 0 映射到离散集中观察到的计数。

接下来,您需要生成与调用buckets(discrete_set) 测量的桶分布匹配的随机样本。 Counter 的elements 方法可以提供帮助,但您需要random.sample 的列表...:

mi, ma, bs, bks = buckets(discrete_set) 
buckelems = list(bks.elements())

(这可能会浪费大量空间,但您可以稍后对其进行优化,与这个以理解为中心的概述分开:-)。

现在很容易得到一个 N 大小的样本,例如:

def makesample(N, buckelems, mi, ma, bs):
    s = []
    for _ in range(N):
        buck = random.choice(buckelems)
        x = random.uniform(mi+buck*bs, mi+(buck+1)*bs)
        s.append(x)
    return s

在这里,我假设存储桶的粒度足够细,可以在每个存储桶内使用均匀分布。

现在,优化这一点当然很有趣——buckelems 将拥有与 discrete_set 中最初一样多的项目,如果这对内存造成了过多的负载,则可以构建和使用累积分布。

或者,可以完全绕过Counter,只需将离散集中的每个项目“四舍五入”到其存储桶的下限,如果内存还可以,但需要更快的速度。或者,可以在“扰乱”所选值之前将discrete_set 单独留下,将random.choice 留在其中(根据确切问题的约束以不同的方式)。乐趣无穷……!-)

【讨论】:

  • 太棒了!无疑是完美的答案!但是让我再问一件事,你认为有没有其他更快的方法可以做到这一点,bcoz,我的实际问题有超过 50 个这样的独立分布,整个过程正在优化,所以要经过多次迭代。
  • “完美答案”甚至没有一个赞?!是的,有可能进行优化(请参阅我的最后 2 段),您可以避免使用分桶直方图,但我敢肯定,除非得到支持,否则我不会花更多时间在这上面!-)
  • 哈哈,你为什么还要担心投票,而你肯定知道我不仅要投票,还要接受你的回答,正如我所说的,“完美答案”。我只是花了一些时间来理解你写的整个代码:-)
  • “我担心什么?” (一个:-)。只是在暗示。顺便说一句,如果您使用更多详细信息编辑 Q(或打开另一个),我将很高兴为可能更优化的方法显示代码(如果您不需要直方图,而只需要具有相同分布的“模拟样本”;特别是. 如果您只需要一个起始离散集合中的许多模拟样本;等等等等)。
【解决方案2】:

当您尝试进行分布拟合时,不要过多了解样本量较小的直方图的谷值和峰值。

我对您的数据执行了 Kolmogorov-Smirnov 检验,以检验它们来自均匀 (0.5,1.5) 分布的假设,并且未能拒绝。因此,您可以生成任何大小的 Uniform(0.5,1.5) 样本。

鉴于您所说的基础分布是连续的,我认为分布拟合方法比基于直方图/桶的方法更好。

【讨论】:

  • 有趣(!!!)作为我最初的目标(虽然我没有在问题中提及)是根据旧分布创建从旧列表生成的新列表并执行 Kolmogorov- Smirnov 测试以检查新发行版与旧发行版的接近程度。你能举个例子说明如何用你提到的“分布拟合方法”编写python代码吗?
  • 并不断重复该过程(循环)以获得最接近原始/旧分布的分布(通过优化)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-18
相关资源
最近更新 更多