将数量分配到桶中-不均匀

时间:2018-08-16 13:30:43

标签: c# random distribution

我一直在寻找解决方案,但是我认为由于我的想法,我的搜索词组可能有点不完整,以支持不完全相关的主题。

我有一个数字,例如950,000。这表示整个系统中的[小部件]清单。我大约有200个“存储桶”,每个存储桶都应接收此清单的一部分,这样就不会剩下任何窗口小部件。

我想让每个存储桶收到不同的金额。我现在没有任何可靠的代码可以显示,但是这里有一些伪代码来说明我一直在想的事情:

//List<BucketObject> _buckets is a collection of "buckets", each of which has a "quantity" property for holding these numbers.

int _widgetCnt = 950000;
int _bucketCnt = _buckets.Count;     //LINQ
//To start, each bucket receives (_widgetCnt / _bucketCnt) or 4750.

for (int _b = 0; b< _bucketCnt - 1; i++)
{
     int _rndAmt = _rnd.Next(1, _buckets[i].Quantity/2); //Take SOME from this bucket...
     int _rndBucket = _rnd.Next(0,_bucketCnt - 1);    //Get a random bucket index from the List<BucketObject> collection.

     _buckets.ElementAt(_rndBucket).Quantity += _rndAmt;
     _buckets.ElementAt(i).Quantity -= _rndAmt;
}

这是处理该问题的统计学/数学上正确的方法,还是那里有处理该问题的分配公式?更重要的是,虽然此伪代码将运行200次(因此每个存储桶都有机会更改其数量),但根据小部件的类型(目前只有11种口味,但它必须运行X次)。预计将来会大大扩展。

{EDIT} 该系统用于商品交易游戏。 200家商店的数量必须有所不同,因为库存将决定该站点的价格。发行版甚至不可能,因为那样会使所有价格相同。随着时间的流逝,价格自然会失衡,但是库存必须开始失衡。而且所有库存的范围都必须至少相似(即,没有一家商店可以拥有一件商品,而另一家商店可以拥有900,000件商品)

1 个答案:

答案 0 :(得分:0)

当然,有解决方案。您可以将Dirichlet Distribution用于此类任务。分布的属性是

Sum i x i = 1

因此,解决方案是从Dirichlet中抽取200个(等于存储桶数)随机值,然后将每个值乘以950,000(或任何总库存量),这将为您提供每个存储桶的项目数。如果您要进行非均匀采样,则可以调整Dirichlet采样中的alpha

每个存储桶中的项目应该四舍五入,但这很简单

如果您很难实现C#,我会在C#的某个地方进行Dirichlet采样-告诉我,我会进行挖掘

更新

我发现一些代码,.NET Core 2,摘录如下。我曾经用示例alpha对Dirichlet RN进行采样,使它们全部不同是很简单的。

//
// Dirichlet sampling, using Gamma sampling from Math .NET
//

using MathNet.Numerics.Distributions;
using MathNet.Numerics.Random;

static void SampleDirichlet(double alpha, double[] rn)
{
    if (rn == null)
        throw new ArgumentException("SampleDirichlet:: Results placeholder is null");

    if (alpha <= 0.0)
        throw new ArgumentException($"SampleDirichlet:: alpha {alpha} is non-positive");

    int n = rn.Length;
    if (n == 0)
        throw new ArgumentException("SampleDirichlet:: Results placeholder is of zero size");

    var gamma = new Gamma(alpha, 1.0);

    double sum = 0.0;
    for(int k = 0; k != n; ++k) {
        double v = gamma.Sample();
        sum  += v;
        rn[k] = v;
    }

    if (sum <= 0.0)
        throw new ApplicationException($"SampleDirichlet:: sum {sum} is non-positive");

    // normalize
    sum = 1.0 / sum;
    for(int k = 0; k != n; ++k) {
        rn[k] *= sum;
    }
}