如何将加权曲线添加到随机选择中
How to add weighting curve to random selection
我想要一个 returns 两个给定值之间的随机数的函数。问题是,我希望它总是 "prefer" 较低的值超过较高的值,以某种 "curve".
的方式上升
所以,假设我给它数字 100 和 1000,它可以给我这两个值之间的任何数字...但是它给我的 100 到 200 远远超过你期望的 11.11%,相反,它可能会在大约 30-40% 的时间内给出这些值,而最高值可能只在 2-4% 的时间内给出。关于如何最好地解决这个问题有什么想法吗?
语言是 C#,但可能并不重要。
那么我建议您使用自己的自定义方式来实现随机数生成器。例如,编写一个包装器 class,它将创建一个 1-100 之间的随机数,如果它落在 1-40 之间,它会返回 100-200 之间的随机数,依此类推,因此您基本上添加了自己的集合优先考虑您的号码生成。如果该值介于 41 - 100 之间,它将返回一个介于 201 - 1000 之间的数字。你喜欢哪种方式
我会说使用 y=ab^x 创建指数曲线,这将在两个输入数字之间创建一条您想要的曲线,然后获取 0 和 1 之间的随机数以获得标准化位置曲线的 x 轴和 return y 值。
您可以对您的随机数求平方,这会将数字加权到您范围的底部:
public double GetWeightedRandom(int min, int max)
{
Random random = new Random();
double randomZeroToOne = random.NextDouble();
double weightedRandom = randomZeroToOne * randomZeroToOne * (max - min) + min;
return weightedRandom;
}
在我对 100 到 1000 的测试中,它给出的平均值是 400,而不是 550。然后,如果您希望它对底部的权重更大,您可以对数字进行立方。
加权随机可能是你想要的,一个很好的想象方法是考虑一个包含重复元素的列表,其中权重较高
var elements = new[]{1,1,2,2,3,3,10,11,12,13};
var rnd = elements[rnd.Next(0,elements.length-1)];
从上面可以看出rnd等于1
,2
或3
的几率是10
,11
的两倍,12
, 或 13
.
您可以使用采用平面列表和相关权重的函数生成相同的列表:
public List<int> GenerateWeighedList(int[] list, float[] weight) {
var weighedList = new List<int>();
// Loop over weights
for (var i = 0; i < weight.Length; i++) {
var multiples = weight[i] * 100;
// Loop over the list of items
for (var j = 0; j < multiples; j++) {
weighedList.push(list[i]);
}
}
return weighedList;
};
所以上面的列表可以用
生成
var input = new[]{1,2,3,10,11,12,13};
var weight = new[]{0.2,0.2,0.2,0.1,0.1,0.1,0.1};
var weightedList = GenerateWeighedList(input,weight);
weightedList
然后可用于从指定权重的所需集合中生成加权随机数
我会分两步完成。第一步 - 是确定您的号码是否应该降低。第二步return一个对应范围内的随机数
public int RandomWeighted(int min, int max, int cap, int percent)
{
Random rand = new Random();
bool isInCap = rand.Next(0, 101) < percent;
return isInCap? rand.Next(min, cap) : rand.Next(cap, max);
}
并像这样使用它:int num = RandomWeighted(100, 1000, 200, 50);
这会给你 100 - 200 在 50% 的时间和 200 - 1000 在其他 50%
我想要一个 returns 两个给定值之间的随机数的函数。问题是,我希望它总是 "prefer" 较低的值超过较高的值,以某种 "curve".
的方式上升所以,假设我给它数字 100 和 1000,它可以给我这两个值之间的任何数字...但是它给我的 100 到 200 远远超过你期望的 11.11%,相反,它可能会在大约 30-40% 的时间内给出这些值,而最高值可能只在 2-4% 的时间内给出。关于如何最好地解决这个问题有什么想法吗?
语言是 C#,但可能并不重要。
那么我建议您使用自己的自定义方式来实现随机数生成器。例如,编写一个包装器 class,它将创建一个 1-100 之间的随机数,如果它落在 1-40 之间,它会返回 100-200 之间的随机数,依此类推,因此您基本上添加了自己的集合优先考虑您的号码生成。如果该值介于 41 - 100 之间,它将返回一个介于 201 - 1000 之间的数字。你喜欢哪种方式
我会说使用 y=ab^x 创建指数曲线,这将在两个输入数字之间创建一条您想要的曲线,然后获取 0 和 1 之间的随机数以获得标准化位置曲线的 x 轴和 return y 值。
您可以对您的随机数求平方,这会将数字加权到您范围的底部:
public double GetWeightedRandom(int min, int max)
{
Random random = new Random();
double randomZeroToOne = random.NextDouble();
double weightedRandom = randomZeroToOne * randomZeroToOne * (max - min) + min;
return weightedRandom;
}
在我对 100 到 1000 的测试中,它给出的平均值是 400,而不是 550。然后,如果您希望它对底部的权重更大,您可以对数字进行立方。
加权随机可能是你想要的,一个很好的想象方法是考虑一个包含重复元素的列表,其中权重较高
var elements = new[]{1,1,2,2,3,3,10,11,12,13};
var rnd = elements[rnd.Next(0,elements.length-1)];
从上面可以看出rnd等于1
,2
或3
的几率是10
,11
的两倍,12
, 或 13
.
您可以使用采用平面列表和相关权重的函数生成相同的列表:
public List<int> GenerateWeighedList(int[] list, float[] weight) {
var weighedList = new List<int>();
// Loop over weights
for (var i = 0; i < weight.Length; i++) {
var multiples = weight[i] * 100;
// Loop over the list of items
for (var j = 0; j < multiples; j++) {
weighedList.push(list[i]);
}
}
return weighedList;
};
所以上面的列表可以用
生成var input = new[]{1,2,3,10,11,12,13};
var weight = new[]{0.2,0.2,0.2,0.1,0.1,0.1,0.1};
var weightedList = GenerateWeighedList(input,weight);
weightedList
然后可用于从指定权重的所需集合中生成加权随机数
我会分两步完成。第一步 - 是确定您的号码是否应该降低。第二步return一个对应范围内的随机数
public int RandomWeighted(int min, int max, int cap, int percent)
{
Random rand = new Random();
bool isInCap = rand.Next(0, 101) < percent;
return isInCap? rand.Next(min, cap) : rand.Next(cap, max);
}
并像这样使用它:int num = RandomWeighted(100, 1000, 200, 50);
这会给你 100 - 200 在 50% 的时间和 200 - 1000 在其他 50%