【问题标题】:Generating a sequence with custom distribution [closed]使用自定义分布生成序列[关闭]
【发布时间】:2020-11-11 14:00:11
【问题描述】:

我有不同概率的n 元素vector<elem> v; 的向量。概率在[0, 1] 范围内,它们的总和为1

struct elem
{
   int value;
   double probability;
}

如何生成一个新的vector<elem>,其中每个elem 都是根据该分布以概率选择的?如果我可以选择新向量的长度就更好了。

【问题讨论】:

  • 澄清一下,您希望添加到新向量中的每个elem 都根据原始向量的概率进行选择?
  • @cigien 是的,新向量中也可以有多个相同的元素
  • 考虑使用alias method。维基百科页面甚至有一个 C++ 实现的链接。别名表需要 O(k) 时间来初始化具有 k 个结果的分布,但从该表生成是 O(1)。
  • @SamuelLiew 我认为应该重新提出这个问题。要求很明确,问题的范围也足够窄。

标签: c++ algorithm distribution


【解决方案1】:

如果您想从向量v 中选择一个概率与成员值成正比的elem,您需要实施称为fitness-proportionate 或轮盘选择的选择方案。

要实现这一点,您可以首先根据数据成员的值创建一个“轮盘赌”:

std::vector<double> wheel, probs;

// extract the probabilities
std::transform(std::begin(v), std::end(v),
               std::back_inserter(probs),
               [](auto const & e) { return e.probability ; });

// then create the roulette wheel
std::partial_sum(std::begin(probs), std::end(probs),
                 std::back_inserter(wheel));

现在要做出一个选择,您可以旋转wheel,然后查看它落在轮子的哪个索引处。鉴于wheel 的构造,任何索引的着陆概率与elemv 中同一索引处的probability 值成正比。

// create the random spinner, and uniformly distributed tip
std::mt19937 spinner;
std::uniform_real_distribution<double> tip(0., 1.); // since the sum is 1.
                                                    // In general, the second argument can be wheel.back()

// spin the wheel and selects an elem
auto spin = [&] {
   auto choice = std::lower_bound(std::begin(wheel), std::end(wheel), 
                                  tip(spinner));
   return v[std::distance(std::begin(wheel), choice)];
};

现在您可以生成任意大小的新向量。

// spin the wheel N times to generate next population
std::vector<elem> new_v;
std::generate_n(std::back_inserter(new_v), N, spin);

注意,如果你想生成一个新的向量不重复元素,你将不得不付出更多的努力来确保选择仍然是随机分布的。此选择还会受到您要生成的新向量大小的影响。

【讨论】:

  • 需要一段时间才能理解它为什么起作用。我会在您提供的链接中了解它。
  • @JordanMironski 尝试使用一些硬编码值,然后转动轮子几次。这应该有助于更好地理解它的工作原理。
  • 既然你使用的是部分和,那么原始向量中的元素应该如何根据概率排列?
  • @JordanMironski 没关系,部分和可以是任何顺序。重要的是各个部分总和的大小。再次,以几个不同的顺序尝试原始向量,您会发现它不会影响结果。
  • 顺便说一句,在您完全理解之前,请不要接受答案。这使得其他人不太可能以更容易理解的方式发布解决您问题的答案。
猜你喜欢
  • 2017-05-10
  • 1970-01-01
  • 2022-06-10
  • 1970-01-01
  • 2012-01-19
  • 1970-01-01
  • 2017-03-18
  • 1970-01-01
  • 2011-03-21
相关资源
最近更新 更多