Как эффективно вписать набор чисел в предопределенное распределение - PullRequest
1 голос
/ 22 июня 2019

Скажем, у меня есть набор чисел, и я хочу суммировать их, чтобы они соответствовали когортам на основе заранее определенного распределения. Простым примером будет, если совокупное количество набора чисел равно 100, а распределение равно 0,2, 0,3, 0,5 для когорт 1,2 и 3 соответственно, тогда я бы хотел найти подмножество чисел, сумма которых равна 20, другое уникальное подмножество, сумма которого равна 30, и последнее уникальное подмножество, сумма которого равна 50. Очевидно, что оно не обязательно должно быть точным, оно просто должно достаточно близко соответствовать распределению.

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

Как только это будет сделано, любое число в этом подмножестве будет удалено, и мы выполним метод решателя с сокращенным подмножеством. Я приложил изображение эволюции процедуры, которое, я надеюсь, понятно, цвета соответствуют итерации. Первая (зеленая) итерация, у нас есть полный список, и переменные, которые меняются, - это переменные в соответствующем зеленом столбце, содержащем 0/1, чтобы получить сумму, близкую к 142 449,09

Обратите внимание, что в этом примере сумма полного списка: 1 424 490,85. enter image description here

Линия «Разница» является решающей задачей, и после каждой итерации целью является сдвиг столбца вправо. (Я установил его так, чтобы, если разница была в пределах 1000, тогда она отображала ноль - как это казалось, чтобы ускорить метод). Имитация - это то, что рассчитывается по соответствующему цветному субпродукту, а теоретическая - это просто вероятность, умноженная на общую сумму всех чисел.

enter image description here

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

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

Кто-нибудь делал такое в R?

Я также понимаю, что это может быть проблемой для Cross Validated - я действительно не был уверен, поэтому не стесняйтесь двигаться. Я приложил код и таблицы в текстовой форме ниже.

Заранее спасибо,

  Sub solversimple()

Dim wb As Workbook
Dim ws As Worksheet
Dim rCell, rIter, rSum
Dim i as Integer

Set wb = Application.ThisWorkbook

Set ws = wb.Sheets("Output")


For i = 1 To 5
    rCell = ws.Range("q8").Offset(0, i - 1).Address
    rChange = ws.Range("h4:h36").Offset(0, i - 1).Address
    rSum = ws.Range("I5:I39").Offset(0, i - 1).Address
    solverreset

        SolverOk SetCell:=rCell, MaxMinVal:=2, ValueOf:=0, ByChange:=rChange, _
            Engine:=3, EngineDesc:="Evolutionary"
        SolverAdd CellRef:=rChange, Relation:=5, FormulaText:="binary"
        SolverAdd CellRef:=rSum, Relation:=5, FormulaText:="binary"
        SolverSolve True

Next i



End Sub




    Full List   List after 1st It   List after 2nd  List after 3rd  List after 4th  1   2   3   4   5
49000.21    49000.21    49000.21    49000.21    49000.21    0.00    0.00    0.00    0.00    1.00
51591.99    51591.99    51591.99    51591.99    51591.99    0.00    0.00    0.00    0.00    1.00
18390.18    18390.18    0.00    0.00    0.00    0.00    1.00    1.00    0.00    1.00
45490.39    45490.39    45490.39    45490.39    45490.39    0.00    0.00    0.00    0.00    1.00
37506.41    0.00    0.00    0.00    0.00    1.00    0.00    0.00    0.00    1.00
1460.11 1460.11 1460.11 0.00    0.00    0.00    0.00    1.00    1.00    0.00
136564.86   136564.86   136564.86   136564.86   0.00    0.00    0.00    0.00    1.00    1.00
41581.29    0.00    0.00    0.00    0.00    1.00    0.00    1.00    0.00    0.00
6138.26 6138.26 6138.26 0.00    0.00    0.00    0.00    1.00    0.00    0.00
23831.37    23831.37    23831.37    23831.37    0.00    0.00    0.00    0.00    1.00    1.00
4529.44 4529.44 0.00    0.00    0.00    0.00    1.00    1.00    1.00    1.00
1291.53 1291.53 1291.53 0.00    0.00    0.00    0.00    1.00    0.00    0.00
1084.88 1084.88 1084.88 0.00    0.00    0.00    0.00    1.00    0.00    0.00
33516.76    33516.76    0.00    0.00    0.00    0.00    1.00    0.00    1.00    0.00
43393.83    43393.83    0.00    0.00    0.00    0.00    1.00    1.00    0.00    0.00
81000.69    81000.69    81000.69    0.00    0.00    0.00    0.00    1.00    0.00    0.00
25397.64    25397.64    0.00    0.00    0.00    0.00    1.00    0.00    0.00    1.00
29473.54    29473.54    29473.54    0.00    0.00    0.00    0.00    1.00    1.00    1.00
39097.70    0.00    0.00    0.00    0.00    1.00    0.00    0.00    1.00    1.00
59669.99    59669.99    0.00    0.00    0.00    0.00    1.00    1.00    1.00    1.00
18639.97    18639.97    0.00    0.00    0.00    0.00    1.00    0.00    0.00    0.00
97198.13    97198.13    97198.13    0.00    0.00    0.00    0.00    1.00    0.00    1.00
5558.69 5558.69 0.00    0.00    0.00    0.00    1.00    1.00    1.00    0.00
16298.63    16298.63    0.00    0.00    0.00    0.00    1.00    0.00    1.00    1.00
67621.61    67621.61    67621.61    0.00    0.00    0.00    0.00    1.00    0.00    0.00
69388.09    69388.09    0.00    0.00    0.00    0.00    1.00    1.00    1.00    0.00
193524.89   193524.89   193524.89   193524.89   0.00    0.00    0.00    0.00    1.00    1.00
12455.61    0.00    0.00    0.00    0.00    1.00    1.00    0.00    0.00    1.00
7261.88 0.00    0.00    0.00    0.00    1.00    0.00    0.00    0.00    0.00
77879.68    77879.68    0.00    0.00    0.00    0.00    1.00    1.00    0.00    1.00
53891.97    53891.97    0.00    0.00    0.00    0.00    1.00    0.00    0.00    0.00
70602.68    70602.68    70602.68    70602.68    70602.68    0.00    0.00    0.00    0.00    1.00
4157.96 0.00    0.00    0.00    0.00    1.00    1.00    1.00    0.00    1.00






Cohort  1.00    2.00    3.00    4.00    5.00
Probability 0.10    0.30    0.20    0.25    0.15
Theoretical 142449.09   427347.26   284898.17   356122.71   213673.63

Simulated   142060.85   426554.86   285268.75   353921.12   216685.28
Difference  0.00    0.00    0.00    2201.59 3011.65

1 Ответ

1 голос
/ 22 июня 2019

Используя R, создайте тестовый ввод.Затем, используя жадный подход, определяют индексы порядка o.Используйте findInterval для определения точек останова b, а затем создайте вектор группировки и переставьте его так, чтобы он соответствовал исходному порядку x, чтобы x[i] находился в группе g[i].Обратите внимание, что split(x, g) создает список групп length(d).

# test input
set.seed(123)
x <- sample(20, 20)
d <- c(.2, .3, .5) # assume in increasing order

o <- order(x)
b <- findInterval(cumsum(d) * sum(x), cumsum(x[o]))
g <- rep(seq_along(d), diff(c(0, b)))[order(o)]

# check distribution of result
tapply(x, g, sum) / sum(x)
##         1         2         3 
## 0.1714286 0.3285714 0.5000000 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...