2016-06-28 5 views
2

К сожалению о плохо сформулированного названии ....Выбор случайный элемент из списка с учетом вероятности каждого элемента

У меня есть объект с именем 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); 

Как выбрать случайный элемент из этого списка при факторизации распределения вероятностей.

Например, предположим, что grams[0].Probability == 0.5 то должно быть 50% вероятность выбора grams[0]

Я полагал, что, возможно, потребуется что-то вроде rand.NextDouble() но я в догадках.

+0

вы хотите выбрать на основе их от вероятности значение? – ajputnam

ответ

2

Вот более универсальный способ чтобы сделать это (то есть вы не необходимости утверждать, что вероятности добавить к 1):

static Random rand = new Random(); 

public NGram GetRandom(IEnumerable<NGram> pool) 
{ 
    // get universal probability 
    double u = pool.Sum (p => p.Probability); 

    // pick a random number between 0 and u 
    double r = rand.NextDouble() * u; 

    double sum = 0; 
    foreach(NGram n in pool) 
    { 
     // loop until the random number is less than our cumulative probability 
     if(r <= (sum = sum + n.Probability)) 
     { 
      return n; 
     } 
    } 
    // should never get here 
    return null; 
} 
+0

Ah ha. Мне не хватало накопительной линии к сумме. Все работает хорошо сейчас. Спасибо за все ответы, но я использовал это сначала :) William – William

+0

Предположим, что у вас есть такие данные {0,7, 0,15, 0,15}, работает ли этот алгоритм !? –

+0

@ FatihTürker Попробуйте и посмотрите! По номиналу я не понимаю, почему это не сработает. –

2

Сортировка списка, согласно Вероятность, по возрастанию.

Сумма поля вероятности для всех элементов в списке. Назовем эту сумму P.

Получить случайное число между [0, P], давайте назовем его г

Iterate списка, сохраняя при этом значения накопления суммы вероятностей до текущего элемента, который перебирает (pe). Завершение поиска, когда найти первый элемент, для которого ре> = г

Случай всех элементов массива подводить 1 теперь просто частный случай :)

+2

Спасибо. Я реализовал, как вы сказали, но я заметил эту проблему: предположим, что я генерирую случайное число 0.955. Не для элементов в списке есть вероятность 0,955, поэтому значение вероятности> = r никогда не будет истинным в этом случае – William

+0

Забыл сказать, что вы должны аккумулировать проблему. итерации, позвольте мне просмотреть его –

+1

Хорошо, он отредактирован с правильным алгоритмом. При проверке случайного значения с накопленной вероятностью вы не столкнетесь с проблемой, которую вы указали –

0

в псевдокоде

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 

Вы можете представить, что каждый элемент имеет длину, равную его назначенной вероятности. Алгоритм подобен случайному бросанию дротика на линейке длины один, причем все вероятности складываются вдоль линейки. Вероятность попадания элемента пропорциональна его размеру (то есть заданной вероятности).

+0

Предположим, что у вас есть такие данные {0,7, 0,15, 0,15}, работает ли этот алгоритм !? –

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 }); 

Это дает мне результаты, как это:

result

 Смежные вопросы

  • Нет связанных вопросов^_^