Как разделить общее значение 1 между x переменными с предвзятым взвешиванием - PullRequest
0 голосов
/ 05 ноября 2019

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

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

Цель метода - разделить всего 1,0 между каждой позицией в массиве. Это достаточно просто, однако дополнительная сложность заключается в том, что деление должно быть предвзятым. Значения слева должны быть выше, чем значения справа (см. Пример выходных данных ниже).

Примером будет передача массива int размера 7. Я ожидаю, что результат будет похож на:

[. 3, .25, .15, .1, .09, .07, 0,04] ​​

, где сумма всех значений = 1

Я использую Java, но даже псевдокод поможет!

Ответы [ 3 ]

5 голосов
/ 05 ноября 2019

Я бы сгенерировал список уникальных случайных чисел, а затем нормализовал его, разделив их все на их сумму.

Затем отсортировал и перевернул ваш список.

int n = 7;

// make a list of n unique random numbers 
double[] randomValues = new Random().doubles(0, 1).distinct().limit(n).toArray();

// normalize the list and reverse sort it
double sum = Arrays.stream(randomValues).sum();
List<Double> array = Arrays.stream(randomValues).boxed()
        .map(d -> d/sum)
        .sorted(Comparator.reverseOrder())
        .collect(Collectors.toList());

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

Предостережение:

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

1 голос
/ 05 ноября 2019
double[] distributeDecreasing(int n) {
    Random random = new Random();
    double[] values = new double[n];
    final double nEps = 0.0001 * n;
    double sum = 0.0;
    for (int i = 0; i < n; ++n) {
        double value = nEps + random.next();
        sum += value;
        values[i] = value;
    }
    double sumFrom1 = 0.0;
    for (int i = 1; i < n; ++n) {
        values[i] /= sum;
        sumFrom1 += values[i];
    }
    if (n > 0) {
        values[0] = 1.0 - sumFrom1;
    }
    Arrays.sort(values, Comparator.reverseOrder());
    return values;
}
  • Смещение выполняется в порядке убывания.
  • Сумма 1,0, полученная путем деления суммы Random.next (между 0 и 1), плюс эпсилон, чтобы не быть нулем.
  • Для минимальной ошибки с плавающей запятой исправьте первый элемент как 1,0 - сумму остальных.
1 голос
/ 05 ноября 2019

Вы не указали точно, какой уклон вы ищете или какое распределение, но прямой подход к смещенному неравномерному распределению будет:

Нарисуйте первое число a1 из [0,1]нарисуйте второе число a2 из [0,1-a1], третье число a3 из [0,1-a1-a2] и так далее. установите an в качестве дополнения к 1 текущей суммы и отсортируйте все в конце.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...