将数量分配到桶中 - 不均匀
Distribute quantities into buckets - Not evenly
我一直在四处寻找解决方案,但我认为由于我的思考方式,我的搜索短语可能有点偏向于不完全相关的主题。
我有一个数字,比如说950,000。这表示整个系统中的 [widgets] 清单。我有大约 200 "buckets" 个,每个都应该收到此库存的一部分,这样就没有剩余的小部件了。
我希望每个桶接收不同的金额。我现在没有任何可靠的代码可以展示,但这里有一些伪代码可以说明我一直在想的事情:
//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;
}
这是 statistically/mathematically 处理此问题的正确方法,还是有处理此问题的分配公式?更重要的是,虽然这个伪代码会 运行 200 次(因此每个桶都有机会改变它的数量),但它必须 运行 X 次,具体取决于小部件的类型(目前目前只有 11 种口味,但预计未来会显着增加)。
{编辑}
该系统用于商品交易游戏。 200 家商店的数量必须不同,因为库存将决定该站点的价格。发行版不可能是均匀的,因为那样会使所有价格都相同。随着时间的推移,价格自然会失衡,但库存必须从失衡开始。并且所有库存必须至少在范围上相似(即,没有一家商店可以有 1 件商品,而另一家有 900,000 件)
当然,有一个解决方案。您可以使用 Dirichlet Distribution 来完成这样的任务。 属性的分布是
总和i xi = 1
所以解决方案是从 Dirichlet 中抽取 200 个(等于桶的数量)随机值,然后将每个值乘以 950,000(或任何总库存),这将得到每个桶的项目数。如果你想要非均匀采样,你可以在 Dirichlet 采样中调整 alpha
。
当然,每个桶的项目都应四舍五入 up/down,但这很微不足道
我在某个地方的 C# 中有 Dirichlet 采样,如果你很难实现它 - 告诉我,我会挖掘出来
更新
我找到了一些代码,.NET Core 2,下面是摘录。我曾经用样本 alpha
s 对 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;
}
}
我一直在四处寻找解决方案,但我认为由于我的思考方式,我的搜索短语可能有点偏向于不完全相关的主题。
我有一个数字,比如说950,000。这表示整个系统中的 [widgets] 清单。我有大约 200 "buckets" 个,每个都应该收到此库存的一部分,这样就没有剩余的小部件了。
我希望每个桶接收不同的金额。我现在没有任何可靠的代码可以展示,但这里有一些伪代码可以说明我一直在想的事情:
//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;
}
这是 statistically/mathematically 处理此问题的正确方法,还是有处理此问题的分配公式?更重要的是,虽然这个伪代码会 运行 200 次(因此每个桶都有机会改变它的数量),但它必须 运行 X 次,具体取决于小部件的类型(目前目前只有 11 种口味,但预计未来会显着增加)。
{编辑} 该系统用于商品交易游戏。 200 家商店的数量必须不同,因为库存将决定该站点的价格。发行版不可能是均匀的,因为那样会使所有价格都相同。随着时间的推移,价格自然会失衡,但库存必须从失衡开始。并且所有库存必须至少在范围上相似(即,没有一家商店可以有 1 件商品,而另一家有 900,000 件)
当然,有一个解决方案。您可以使用 Dirichlet Distribution 来完成这样的任务。 属性的分布是
总和i xi = 1
所以解决方案是从 Dirichlet 中抽取 200 个(等于桶的数量)随机值,然后将每个值乘以 950,000(或任何总库存),这将得到每个桶的项目数。如果你想要非均匀采样,你可以在 Dirichlet 采样中调整 alpha
。
当然,每个桶的项目都应四舍五入 up/down,但这很微不足道
我在某个地方的 C# 中有 Dirichlet 采样,如果你很难实现它 - 告诉我,我会挖掘出来
更新
我找到了一些代码,.NET Core 2,下面是摘录。我曾经用样本 alpha
s 对 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;
}
}