Получить рандомизированное отклонение от заданной стоимости

Я хотел бы добавить своего рода рябь в массив известных значений типа ******. Я указываю это потому, что Random.Next/Random.**********() ведут себя разные.

Как мне лучше всего выполнить эту задачу?

Скажем, у меня есть 20 значений в массиве, List<******> arr = new List<******>() { 40, 40, 40, 40 ..... };</******> </******> 20 значений, которые усредняются по сумме 40, всего 800, чтобы облегчить ее.

После этого метода я бы хотел, чтобы общее общее количество оставалось 800, но каждое отдельное значение должно быть изменено. Значения должны быть положительными, поскольку после этого они добавляются total+=i.

До сих пор эта проблема решалась с использованием процента от заданного количества значений. 1.0 / 20 = 0.05, then multiplicate that with the total and the iteration number. Then subtract the result from the remainder. Finally i just return a sort by new Guid().

Как вы уже заметили, этот метод был только немного потрясающим, тогда как было около 5-20 значений. В моем случае сегодня этот массив должен выдерживать 500-2000 значений (0,2-0,05% каждого значения).

Вместо этого я хотел бы иметь производную или такую, которая делает искажение с + -x% от значения 40 в качестве базы. Или, может быть, даже лучше, + -x% от любого единственного значения в массиве).

[ОБНОВЛЕНИЕ]

Я добавлю вопрос с обновлением, основанным на ответах на этот вопрос.

Random rnd = new Random();
 List<******> ripple = new List<******>();
 int qty = bArray.Count();
 ****** diff = last.Value - first.Value;
 if (qty == 1)
 {
 ****** linearAvg = (diff / qty) / 2;
 ripple.Add(linearAvg);
 }
 else
 {
 ******[] rndarr = new ******[qty];
 for (int i = 0; i < qty; i++)
 rndarr[i] = rnd.**********();
 ****** rndArrSum = rndarr.Sum();
 for (int i = 0; i < qty; i++)
 rndarr[i] /= rndArrSum; 
 for (int i = 0; i < qty; i++)
 ripple.Add(diff * rndarr[i]);
 }
 ****** valueOverall = first.Value;
 for (int i = (qty > 1) ? 1 : 0; i < qty; i++)
 valueOverall += ripple[i];
</******></******>

Допустим, что последнее сгенерированное значение не перекрывается. Кроме того, исключение, когда список содержит только два значения. qty=1 может выглядеть волшебным, но это относится к тому, как выглядит объект bArray в реальном. Я думаю, что вся идея в любом случае ясна.

4 ответа

Один из способов сделать это - создать N случайных чисел от 0 до 1 (эксклюзивный). Суммируйте их. Затем разделим каждое число на сумму. Теперь у вас есть список из N случайных чисел, сумма которых равна 1. Теперь умножьте каждое из этих чисел на нужную сумму, чтобы получить числа, которые войдут в ваш окончательный массив.

Если вы хотите, чтобы ваши значения составляли +/- некоторый процент, используйте Random.Next для генерации случайных чисел в пределах некоторого диапазона и суммирования их. Затем разделите на общее число, чтобы получить список чисел, сумма которых равна 1. Последний шаг тот же.


Другим методом будет цикл через массив и perturb по проценту. После завершения вычислите, как далеко от общей суммы, и добавьте избыточное количество, равномерно распределенное по всем номерам. Вот пример кода:

var test = Enumerable.Repeat<******>(40, 100).ToArray();
var percent = 0.5d;
var rand = new Random();
var expectedTotal = test.Sum();
var currentTotal = 0d;
var numCount = test.Count();
for (var i = 0; i < numCount; i++)
{
 var num = test[i];
 var range = num * percent * 2;
 var newNum = num + (rand.**********() - 0.5) * (range);
 currentTotal += newNum;
 test[i] = newNum;
}
var overage = (expectedTotal - currentTotal);
for (var i = 0; i < numCount; i++)
 test[i] += overage / numCount;
</******>


Ниже мое решение.

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

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

// prepare data
******[] values = new ******[20];
for (int i = 0; i < values.Length; i++)
{
 values[i] = 40.0;
}
// get the original total
****** originalTotal = 0.0;
for (int i = 0; i < values.Length; i++)
{
 originalTotal += values[i];
}
// specify an abberation percentage
****** x = 0.05;
// jitter each value +/- the abberation percentage
// also capture the total of the jittered values
Random rng = new Random();
****** intermediateTotal = 0.0;
for (int i = 0; i < values.Length; i++)
{
 values[i] += values[i] * (rng.**********() - 0.5) * (2.0 * x);
 intermediateTotal += values[i];
}
// calculate the difference between the original total and the current total
****** remainder = originalTotal - intermediateTotal;
// add a flat amount to each value to make the totals match
****** offset = remainder / values.Length;
for (int i = 0; i < values.Length; i++)
{
 values[i] += offset;
}
// calculate the final total to verify that it matches the original total
****** finalTotal = 0.0;
for (int i = 0; i < values.Length; i++)
{
 finalTotal += values[i];
}


Выберите случайное число (симметричное относительно нуля) для каждого шага между последовательными числами. Затем добавьте его к первому и вычтите из второго:

for(int i=1; i
<p>Это должно гарантировать, что сумма массива останется той же (по модулю с плавающей запятой), в то время как все элементы массива будут изменены.</p>

licensed under cc by-sa 3.0 with attribution.