C# 从给定每个项目概率的列表中选择随机项目

C# 从给定每个项目概率的列表中选择随机项目,c#,random,probability,n-gram,C#,Random,Probability,N Gram,很抱歉,标题措词不当 我有一个物体叫做NGram class NGram { //other properties double Probability {get; set;} //Value between 1 and 0 } 现在假设我有一个这些对象的列表,这样 List<NGrams> grams = GetNGrams(); Debug.Assert(grams.Sum(x => x.Probability) == 1); List grams

很抱歉,标题措词不当

我有一个物体叫做NGram

class NGram
{
     //other properties
     double Probability {get; set;} //Value between 1 and 0 
}
现在假设我有一个这些对象的列表,这样

List<NGrams> grams = GetNGrams();
Debug.Assert(grams.Sum(x => x.Probability) == 1);
List grams=GetNGrams();
断言(grams.Sum(x=>x.Probability)==1);
在考虑概率分布时,如何从该列表中选择随机项

例如,假设
grams[0]。概率==0.5
那么选择
grams[0]


我想我可能需要像rand.NextDouble()这样的东西,但我不知所措。

对列表排序,按概率排序,升序

对列表中所有元素的概率字段求和。让我们称之为总和P

获取一个介于[0,p]之间的随机数,我们称之为r

迭代列表,同时将概率总和的累积值保留到当前正在迭代的元素(pe)。当找到pe=r


数组中所有元素加和为1的情况现在只是一种特殊情况:)

这里有一种更通用的方法(这意味着您不需要断言概率加1):

static Random rand=new Random();
公共NGram GetRandom(IEnumerable池)
{
//得到普遍概率
double u=池和(p=>p.Probability);
//选择一个介于0和u之间的随机数
double r=rand.NextDouble()*u;
双和=0;
foreach(池中的NGram n)
{
//循环,直到随机数小于我们的累积概率
伪码中的if(r

r = Get a random number between 0 and 1
sum = 0
i = 0
Loop  
    sum = sum + grams[i].Probability  
    If sum >= r Then  
        Exit Loop
    End
    i = i + 1  
End
i is the index of the random item in the list
想法是将项目的概率相加,直到总和大于或等于一个随机数。由于概率总和为1,且随机数在0..1范围内,因此在任何情况下,您都会找到一个项目。概率较大的项目更有可能被选中

∑P= 0 0.08     0.3 0.43 0.53          0.88  1
    +--+--------+----+---+-------------+----+
    |  |        |    |   |             |    |
    +--+--------+----+---+-------------+----+ 
i =  0      1      2   3       4         5  
您可以想象每个项目的长度等于其分配的概率。该算法就像随机向长度为1的标尺投掷省道,所有概率沿标尺堆叠。项目被击中的概率与其大小(即其分配的概率)成正比。

尝试以下方法:

List<NGram> grams = new List<NGram>()
{
    new NGram() { Probability = 0.5 },
    new NGram() { Probability = 0.35 },
    new NGram() { Probability = 0.15 }
};

var rnd = new Random();

var result =
    grams
        .Aggregate(
            new { sum = 0.0, target = rnd.NextDouble(), gram = (NGram)null },
            (a, g) =>
                a.gram == null && a.sum + g.Probability >= a.target
                    ? new { sum = a.sum + g.Probability, a.target, gram = g }
                    : new { sum = a.sum + g.Probability, a.target, a.gram });
List grams=新列表()
{
新的NGram(){Probability=0.5},
新的NGram(){Probability=0.35},
新的NGram(){Probability=0.15}
};
var rnd=新随机数();
var结果=
克
.合计(
新的{sum=0.0,target=rnd.NextDouble(),gram=(NGram)null},
(a,g)=>
a、 gram==null&&a.sum+g.概率>=a.target
?新的{sum=a.sum+g.概率,a.target,gram=g}
:new{sum=a.sum+g.概率,a.target,a.gram});
它给了我这样的结果:


你想根据概率值进行选择吗?谢谢。我已经按照你说的实现了,但是我注意到了这个问题:假设我生成了一个0.955的随机数。列表中没有一个项目的概率为0.955,所以概率值>=r在这种情况下永远不会为真。忘记了说你应该在迭代时累积概率ng,让我回顾一下itOk,它是用正确的算法编辑的。当用累积概率检查随机值时,你不会碰到你指出的问题。啊哈。我错过了总和的累积行。现在一切都很好。谢谢你提供的所有答案,但我首先使用了这个:)威廉姆斯假设你有这样的数据{0.7,0.15,0.15}这个算法有效吗?@FatihTürker试试看!从表面上看,我不明白为什么它不起作用。假设你有这种数据{0.7,0.15,0.15},这个算法有效吗!?
List<NGram> grams = new List<NGram>()
{
    new NGram() { Probability = 0.5 },
    new NGram() { Probability = 0.35 },
    new NGram() { Probability = 0.15 }
};

var rnd = new Random();

var result =
    grams
        .Aggregate(
            new { sum = 0.0, target = rnd.NextDouble(), gram = (NGram)null },
            (a, g) =>
                a.gram == null && a.sum + g.Probability >= a.target
                    ? new { sum = a.sum + g.Probability, a.target, gram = g }
                    : new { sum = a.sum + g.Probability, a.target, a.gram });