- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想在总和为给定数字的范围内找到不同的随机数。
注意:我在 stackoverflow 中发现了类似的问题,但是它们并没有完全解决这个问题(即它们不考虑范围的负 lowerLimit)。
如果我希望随机数的总和等于 1,我只需生成所需的随机数,计算总和并将每个随机数除以总和即可;但是在这里我需要一些不同的东西;我将需要我的随机数加起来不同于 1,但我的随机数仍然必须在给定范围内。
示例:我需要 30 个介于 -50 和 50 之间的不同随机数(非整数),其中 30 个生成的数字之和必须等于 300;我写了下面的代码,但是当 n 远大于范围 (upperLimit - lowerLimit) 时它不会工作,该函数可能返回范围 [lowerLimit - upperLimit] 之外的数字。对改进当前解决方案有何帮助?
static void Main(string[] args)
{
var listWeights = GetRandomNumbersWithConstraints(30, 50, -50, 300);
}
private static List<double> GetRandomNumbersWithConstraints(int n, int upperLimit, int lowerLimit, int sum)
{
if (upperLimit <= lowerLimit || n < 1)
throw new ArgumentOutOfRangeException();
Random rand = new Random(Guid.NewGuid().GetHashCode());
List<double> weight = new List<double>();
for (int k = 0; k < n; k++)
{
//multiply by rand.NextDouble() to avoid duplicates
double temp = (double)rand.Next(lowerLimit, upperLimit) * rand.NextDouble();
if (weight.Contains(temp))
k--;
else
weight.Add(temp);
}
//divide each element by the sum
weight = weight.ConvertAll<double>(x => x / weight.Sum()); //here the sum of my weight will be 1
return weight.ConvertAll<double>(x => x * sum);
}
编辑 - 澄清
运行当前代码将生成以下 30 个数字,它们相加为 300。但是这些数字不在 -50 和 50 之间
-4.425315699
67.70219958
82.08592061
46.54014109
71.20352208
-9.554070146
37.65032717
-75.77280868
24.68786878
30.89874589
142.0796933
-1.964407284
9.831226893
-15.21652248
6.479463312
49.61283063
118.1853036
-28.35462683
49.82661159
-65.82706541
-29.6865969
-54.5134262
-56.04708803
-84.63783048
-3.18402453
-13.97935982
-44.54265204
112.774348
-2.911427266
-58.94098071
最佳答案
好的,这里是如何完成的
我们将使用 Dirichlet Distribution ,这是 [0...1] 范围内的随机数 xi 的分布,使得
求和i xi = 1
因此,在线性重新缩放后,总和的条件将自动满足。 Dirichlet 分布由 αi 参数化,但我们假设所有 RN 都来自相同的边缘分布,因此每个索引只有一个参数 α。
对于合理大的 α 值,采样的随机数的均值 =1/n,方差 ~1/(n * α),因此较大的 α 导致随机值更接近均值。
好的,现在回到重新缩放,
vi = A + B*xi
我们必须得到A
和B
。正如@HansKesting 正确指出的那样,只有两个自由参数,我们只能满足两个约束,但你有三个。所以我们会严格满足下限约束、和值约束,但偶尔会违反上限约束。在这种情况下,我们只需丢弃整个样本,然后再做一个。
同样,我们有一个旋钮可以转动,α 变大意味着我们接近平均值并且不太可能达到上限。当 α = 1 时,我很少得到好的样本,但当 α = 10 时,我得到接近 40% 的好样本。当 α = 16 时,我得到接近 80% 的好样本。
Dirichlet 采样是通过 Gamma 分布完成的,使用来自 MathDotNet 的代码.
代码,使用 .NET Core 2.1 测试
using System;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.Random;
class Program
{
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;
}
}
static bool SampleBoundedDirichlet(double alpha, double sum, double lo, double hi, 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");
if (lo >= hi)
throw new ArgumentException($"SampleDirichlet:: low {lo} is larger than high {hi}");
int n = rn.Length;
if (n == 0)
throw new ArgumentException("SampleDirichlet:: Results placeholder is of zero size");
double mean = sum / (double)n;
if (mean < lo || mean > hi)
throw new ArgumentException($"SampleDirichlet:: mean value {mean} is not within [{lo}...{hi}] range");
SampleDirichlet(alpha, rn);
bool rc = true;
for(int k = 0; k != n; ++k) {
double v = lo + (mean - lo)*(double)n * rn[k];
if (v > hi)
rc = false;
rn[k] = v;
}
return rc;
}
static void Main(string[] args)
{
double[] rn = new double [30];
double lo = -50.0;
double hi = 50.0;
double alpha = 10.0;
double sum = 300.0;
for(int k = 0; k != 1_000; ++k) {
var q = SampleBoundedDirichlet(alpha, sum, lo, hi, rn);
Console.WriteLine($"Rng(BD), v = {q}");
double s = 0.0;
foreach(var r in rn) {
Console.WriteLine($"Rng(BD), r = {r}");
s += r;
}
Console.WriteLine($"Rng(BD), summa = {s}");
}
}
}
更新
通常,当人们问这样的问题时,有一个隐含的假设/要求——所有的随机数都应该以相同的方式分布。这意味着如果我从采样数组中为索引为 0 的项目绘制边际概率密度函数 (PDF),我将获得与为数组中的最后一个项目绘制边际概率密度函数相同的分布。人们通常对随机数组进行采样,将其传递给其他例程来做一些有趣的事情。如果项目 0 的边际 PDF 与最后一个索引项目的边际 PDF 不同,那么仅恢复数组将产生与使用此类随机值的代码截然不同的结果。
在这里,我使用我的抽样例程绘制了原始条件 ([-50...50] sum=300) 下第 0 项和最后一项 (#29) 的随机数分布。看起来很相似,不是吗?
好的,这是您的采样例程的图片,相同的原始条件([-50...50] sum=300),相同的样本数
更新二
用户应该检查采样例程的返回值,并在(且仅当)返回值为真时接受和使用采样数组。这是接受/拒绝方法。作为说明,下面是用于直方图样本的代码:
int[] hh = new int[100]; // histogram allocated
var s = 1.0; // step size
int k = 0; // good samples counter
for( ;; ) {
var q = SampleBoundedDirichlet(alpha, sum, lo, hi, rn);
if (q) // good sample, accept it
{
var v = rn[0]; // any index, 0 or 29 or ....
var i = (int)((v - lo) / s);
i = System.Math.Max(i, 0);
i = System.Math.Min(i, hh.Length-1);
hh[i] += 1;
++k;
if (k == 100000) // required number of good samples reached
break;
}
}
for(k = 0; k != hh.Length; ++k)
{
var x = lo + (double)k * s + 0.5*s;
var v = hh[k];
Console.WriteLine($"{x} {v}");
}
关于c# - 获取两个值之间的 n 个不同的随机数,其总和等于给定数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51325425/
我基本上有三个表: hunt_c_usershunt_c_collected_eggshunt_c_achievements 我目前只使用 hunt_c_users 和 hunt_c_collecte
我已经计算了不同表中计数的总和。这会执行两次,每个 performanceID 一次。现在我想得到两个总和的总和。 下面是我目前做的两个总和的代码: SELECT SUM((COUNT (Bo
我有一个对 2 个值求和的脚本。我计划添加更多值(value),但首先我需要让它发挥作用。人们告诉我给他们 NUMBER 值,所以我这样做了,但现在它甚至没有给出输出。 base = 0; $("#F
我正在尝试计算在我们的数据库中跟踪的花费总额。每个订单文档包含一个字段“total_price” 我正在尝试使用以下代码: db.orders.aggregate({ $group: {
给定 Excel 2013(或更高版本)中的 2 个命名表: tbl发票 ID InvRef Total 1 I/123 45 2 I/234
希望你们一切都好。我来这里是因为我从今天早上开始就试图解决一个问题,我再也受不了了。 这就是上下文:我有一个 excel 工作簿,其中有不同的工作表,其中包含不同国家/地区的不同商业计划。我的目标是制
我有一份报告显示客户订购的产品及其价格: CompanyA Product 7 14.99 CompanyA Product 3 45.95 CompanyA Prod
我使用此python客户端: https://github.com/ryananguiano/python-redis-timeseries 如何汇总所有匹配? ts = TimeSeries(cli
希望创建一个总和和计数公式,该公式将自动调整以适应范围内插入的新行。 例如,如果我在单元格 D55 中有公式 =SUM(D17:D54)。每次我在该范围内插入新行时,我都需要更改公式的顶部范围来解释它
所以,我需要聚合日期相同的行。 到目前为止,我的代码返回以下内容: date value source 0 2018-04-08 15:52:26.1
我有数字输入 数量约为 30 我需要将它们全部汇总到一个字段 我拥有的在下面 查看:
您好,我正在尝试根据以下数据计算过去三个月中出现不止一次的不同帐户 ID 的数量;我想要 2 作为查询结果,因为 test1@gmail.com 和 test2@gmail.com 出现超过 1 次。
我有两个带有以下字段的表: ... orders.orderID orders.orderValue 和 payments.orderID payments.payVal 在 payments.pay
我想按 image_gallery 和 video_gallery 两列的 DESC 进行排序。 SELECT b.*, c.title as category, (S
实际上我的原始数据库为 SELECT sum(data1,data2) as database_value,sum(data3,data4) as database_not_value from t
我试图获取三个分数中每一个的值并将它们相加并显示在“总计:”中。我的问题是,我不知道如何做到这一点,以便每次其中一个分数值发生变化时,相应的总分值也会随之变化。 我可以在某处调用“onchange”来
如何获得按第一个值分组的元组列表中第二个和第三个值的总和? 即: list_of_tuples = [(1, 3, 1), (1, 2, 4), (2, 1, 0), (2, 2, 0)] expec
我正在尝试将我的列表中的整数转换为列表的总和和平均值,并说明任何低于冰点 F<32 的温度。每当我尝试获取总和或平均值时,我都会收到错误提示“+: 'int' 和 'str' 不支持的操作数类型”。我
在我的 ios 项目中,我使用了两个实体 (CoreData):具有一对多关系的 Person 和 Gifts 我知道如何计算给一个人的礼物总和: NSDecimalNumber *orderSum=
我有两个表(输入和类别): CREATE TABLE categories ( iId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, sNam
我是一名优秀的程序员,十分优秀!