Формулируя это как целочисленное программирование, где целевая функция минимизирует сумму квадратов между назначенным и целевым выделением с учетом минимальных и максимальных ограничений выделения:
dt1[, TARGET := POPULATION / sum(POPULATION) * TOTAL]
system.time({
library(CVXR)
x <- Variable(nrow(dt1), integer=TRUE)
mini <- dt1$MIN
maxi <- dt1$MAX
target <- dt1$TARGET
obj <- Minimize(sum_squares(x - target))
constr <- list(mini <= x, x <= maxi, sum(x) == TOTAL)
prob <- Problem(obj, constr)
result <- solve(prob)
})
# user system elapsed
# 1.60 0.17 1.76
dt1[, ALLOCATION := as.integer(round(result$getValue(x)))]
вывод:
ZONE POPULATION MIN MAX TARGET ALLOCATION
1: A34 40 1 10 2.020202 4
2: G345 110 0 9 5.555556 7
3: H62 80 0 2 4.040404 2
4: D563 70 1 11 3.535354 5
5: T63 90 0 12 4.545455 6
6: P983 90 1 8 4.545455 6
7: S24 130 0 5 6.565657 5
8: J54 140 1 3 7.070707 3
9: W953 80 1 2 4.040404 2
10: L97 30 0 0 1.515152 0
11: V56 80 1 8 4.040404 6
12: R99 50 1 8 2.525253 4
данные :
library(data.table)
dt1 <- data.table(ZONE = c("A34","G345","H62","D563","T63","P983","S24","J54","W953","L97","V56","R99"),
POPULATION = c(40,110,80,70,90,90,130,140,80,30,80,50),
MIN = c(1,0,0,1,0,1,0,1,1,0,1,1),
MAX = c(10,9,2,11,12,8,5,3,2,0,8,8))
TOTAL <- 50L