首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从分布相等的数组中选择随机项

从分布相等的数组中选择随机项
EN

Stack Overflow用户
提问于 2020-09-08 19:29:04
回答 3查看 964关注 0票数 1

我想随机地从数组中选择一个随机项。

代码语言:javascript
复制
Math.floor(Math.random() * array.length);

是要走的路,但据我所知,这将导致均匀分布,这意味着平均值是(lowbound+upperbound)/2转换成一个包含10个元素的数组,下界是第一个元素,上界是最后一个元素,导致平均5,即而不是随机

因此,我查看了这种随机挑选项目的频率分布,方法是有10个元素,并使用上面的代码来选择一个元素。元素表示索引,并被推入数组中。在10000个数字后,计数并给出频率。

这方面的结果如下:

代码语言:javascript
复制
Index: Frequency
0: 1083
1: 996
2: 1022
3: 966
4: 958
5: 962
6: 1044
7: 1045
8: 972
9: 952

Ofc,这只是一个10k的数字。指数0的概率为10.8%,指数9的概率为9.5%。这个差距是1.3%,我觉得相当多。

有什么方法能做得更好吗?例如,数字相差0.05%?理想的情况是,它们都是10% (平均分布)。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-09-08 19:36:13

如果您可以预先计算结果(即您需要有限的结果,而不是无限流),并且结果的数量可以被项目数除以,那么您可以得到一个完美的分布:

  1. 生成一个重复这些项的数组,直到得到足够多的项,即[1, 2, 3, 1, 2, 3, 1, 2, 3, ...]。因此,保证数组具有与每个项相同的实例。
  2. 使用公平的洗牌算法(例如费舍-耶茨 )对数组进行洗牌。该数组仍然具有与每个项完全相同的实例。

如果您确实需要一个无限流,您可以使用类似于“项目包”模型(顺便说一句,这就是在俄罗斯方块的选择):

  1. 用你的物品填充一个“袋子”([1, 2, 3])。洗牌(如上)。
  2. 当你需要一件物品时,把第一件东西从拖着的袋子里拿出来。
  3. 如果袋子是空的,请按照步骤1重新填入。

唯一的情况,这没有一个完美的分布是,如果你停止“中袋”。

票数 1
EN

Stack Overflow用户

发布于 2020-09-08 21:26:33

您在问题中所展示的只是这样一个事实: JavaScript随机数生成器不仅模拟均匀分布的随机数,而且模拟独立的随机数;每个选定的数字的行为似乎独立于任何其他选择。由于这种独立性,每个数字“不关心”每个数字被选择的频率,只要每个选择,每个可能的结果都与任何其他的结果一样(根据JavaScript生成器)。

如果您想要一个“感觉”更一致的分布,您将不得不调整每个结果的机会,以便机会取决于先前的结果。先前的一个答案说明了如何做到这一点。这是另一个,我给出了一个相似问题的答案。

  1. 赋予每个项目相同的权重,指定为正整数。例如,每个项目的权重为20。
  2. 使用加权选择和替换算法。也许最简单的是拒绝抽样,描述如下。假设最高的权重是max,并且每个权重都是0或更大。若要在间隔1中选择整数,请使用拒绝抽样进行weights.length
代码语言:javascript
复制
1. Choose a uniform random integer `i` in [1, `weights.length`].
2. With probability `weights[i]/max`, return `i`. Otherwise, go to step 1.  (For example, if all the weights are integers greater than 0, choose a uniform random integer in [1, `max`] and if that number is `weights[i]` or less, return `i`, or go to step 1 otherwise.)

除了拒绝抽样之外,还有许多其他方法可以进行加权选择;参见我的关于加权选择算法的注记

  1. 当每个项目都被选中时,将其重量减少1,以减少被选择的可能性。
  2. 如果所有权重都为0,则为每个项目分配步骤1中选择的相同权重(在本例中为20)。

你没有具体说明你想到的是哪种应用程序,但我看到这种“更均匀”分布的愿望经常出现在那些希望控制哪个随机数出现的游戏中,以使随机结果对玩家来说更“公平”。然而,在这种情况下,你也应该考虑是否应该做一个(普通的)独立的一致随机选择,特别是当你关心玩家是否可以通过预测随机结果获得不公平的优势时。

票数 0
EN

Stack Overflow用户

发布于 2020-09-09 15:52:31

在这里,另一种方法--计数样本数已经发生,从范畴分布中选择值,但与计数的概率相反,因此更频繁的项目下一次采样的可能性较小。

一些代码(在C#中)

代码语言:javascript
复制
import MathNet.Numerics.Distributions;

static void Main() {

    const int N = 4;

    var counts  = new int [N] {1, 1, 1, 1};
    var weights = new double [N] {1.0, 1.0, 1.0, 1.0};

    while (true) {
        int v = Categorical.Sample(weights[k]); // sample one value in [0...N)
        // update counts and weights
        counts[v] += 1;
        weights[v] = 1.0/(double)counts[v];
        
        // use v here for something
        ...
    }
}

实际上,计数的任何单调增长函数都可以,f.e。

代码语言:javascript
复制
weights[v] = 1.0/(1.0 + .5*(double)counts[v]);

可能有用,或者

代码语言:javascript
复制
var squared => (x) => x*x;
weights[v] = 1.0/(7.0 + .25*squared((double)counts[v]));

代码语言:javascript
复制
weights[v] = 1.0/(3.0 + Math.Sqrt((double)counts[v]));
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63800423

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档