Я хотел реализовать простой метод выборки из полиномиального распределения на C# (первый аргумент — это массив целых чисел, которые мы хотим выбрать, а второй — вероятности выбора каждого из этих целых чисел).
Когда я делаю это с помощью numpy в python, результаты имеют смысл.
np.random.choice(np.array([1,2,3,4,5,6]),p=np.array([.624,.23,.08,.04, .02, .006]),size=len(b))
Я получаю много единиц (вероятность 62%), много двоек, немного троек и т. д.
Однако, когда я пробую приведенную ниже реализацию на C# (довольно простая выборка с обратным преобразованием для многочлена, основанная только на универсальной случайной величине), я получаю действительно странные результаты. Для всех 1000 образцов я часто нахожу все единицы. Иногда я нахожу все 3 (!!??). Результаты никогда не выглядят так, как вы ожидаете (и что вы получаете от функции python — попробуйте запустить ее самостоятельно несколько раз). Это действительно страшно, так как мы полагаемся на эти примитивы. Кто-нибудь знает, что может быть не так с версией С#?
static void Main(string[] args)
{
int[] iis = new int[7];
int[] itms = new int[] { 1, 2, 3, 4, 5, 6 };
double[] probs = new double[] { .624, .23, .08, .04, .02, .006 };
for (int i = 0; i < 1000; i++)
{
iis[MultinomialSample(itms, probs)] += 1;
}
foreach (var ii in iis)
{
Console.Write(ii + ",");
}
Console.Read();
}
private static int MultinomialSample(int[] s, double[] ps)
{
double[] cumProbs = new double[ps.Length];
cumProbs[0] = ps[0];
for (int i = 1; i < ps.Length; i++)
{
cumProbs[i] = cumProbs[i - 1] + ps[i];
}
Random random = new Random();
double u = random.NextDouble();
for (int i = 0; i < cumProbs.Length - 1; i++)
{
if (u < cumProbs[i])
{
return s[i];
}
}
return s[s.Length - 1];
}
Random
каждый раз, когда вызываетеMultinomialSample
. Если эти вызовы очень близки друг к другу,Random
будет инициализирован с одним и тем же начальным числом (на основе системных часов). Попробуйте либо сделатьRandom
приватным полем класса:private static Random random = new Random();
, либо передать его в метод в качестве аргумента изMain
, где оно будет инициализировано только один раз. - person Rufus L   schedule 18.11.2017