[英]Approximate two target values from a list of values
我有一個值列表(這些是指權重)和 2 個目標值(它們是這些權重選擇的總和)。 應將權重分配給兩個目標值之一,以便權重之和接近其目標值。 應該同時最大化兩個目標值的近似值。
例如,這是一個權重列表
重量 |
---|
4.528 |
4.773 |
4.253 |
4.688 |
4.21 |
3.841 |
4.005 |
4.545 |
3.825 |
5.123 |
4.757 |
並且有兩個目標值:
價值觀 |
---|
22.08 |
21.37 |
權重選擇的總和可能不會完全等於目標值,所以我需要一個近似值。
據我所知,Excel Solver 可以一次處理一個目標值,但我需要它一次處理多個目標值。 有誰知道如何解決這個問題? 最好在 R 但 Python 或 Excel 也可以。
這是一個替代方案:
n= length(Weight)
# all combinations 2 to n-1
cms = lapply(2:(n-1), function(x) combn(n,x))
# sum weights selected and not selected and compute square errors
res = lapply(cms, function(cm)
+ apply(cm,2,function(sel){
+ sum1 = sum(Weight[sel])
+ sum2 = sum(Weight[-sel])
+ sum((Values-c(sum1,sum2))^2)
+ }))
# find the min square error
mins = sapply(res,function(re){
+ wm = which.min(re)
+ minv= re[wm]
+ c(wm=wm,minv=minv)})
mins
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#wm 18.0000 81.000 169.00000 300.0000 163.00000 162.00000 85.0000 38.0000 2.000
#minv 447.1174 212.036 68.92069 14.0989 12.99698 54.91097 184.7123 406.2839 719.574
which.min(mins[2,])
#[1] 5
mins[,which.min(mins[2,])]
# wm minv
#163.00000 12.99698
(sel = cms[[5]][,163]) # group 1
#[1] 1 3 5 6 7 9
(1:n)[-sel] # group 2
#[1] 2 4 8 10 11
c(sum(Weight[sel]), sum(Weight[-sel])) # sums
#[1] 24.662 23.886
Values
#[1] 22.08 21.37
library(tidyverse)
weight<-c(4.528
,4.773
,4.253
,4.688
,4.21
,3.841
,4.005
,4.545
,3.825
,5.123
,4.757)
values <- c(
22.08,21.37)
# a heuristic that says I'm not going to add more than "these" number of entries to hit a target
(most_to_sum <- ceiling(max(values)/min(weight)))
#make combs
combs_to_do <- expand_grid(
set_1 = seq_len(most_to_sum),
set_2 = seq_len(most_to_sum)
) |> rowwise() |> mutate(rsum=sum(set_1,set_2)) |> filter(rsum<=length(weight)) |> ungroup()
unique_sets <- map(seq_len(most_to_sum),
~combn(weight,.x,simplify=FALSE)) |> flatten()
unique_sets_evals <- map_dbl(unique_sets,
~abs(values[[1]] - sum(.x)))
# opportunity here to trade accuracy for speed/memoirt
(set1_reduced <- quantile(unique_sets_evals,1)) # use 1 for exhaustive search; though I got the correct result reducing to 0.01 and even good approximations with less
set1_reduced_sets <- unique_sets[which(unique_sets_evals<=set1_reduced)]
do_second_set <- function(first_sets,size_of_second_set,weight,values){
second_sets <- map(first_sets,~{
available <- setdiff(weight,.x)
if(length(available) < size_of_second_set) return(Inf)
combn(available,size_of_second_set,simplify = FALSE)
})
coeval <- map2(first_sets,second_sets,
~{
x <- .x
y <- .y
xsum <- sum(x)
ysums <- map(y,sum)
evals <- map(ysums,
~sqrt((values[[1]]-xsum)^2+(values[[2]]-.x)^2))
best_y <- y[which.min(evals)]
list(best_second = best_y,
eval=evals[[which.min(evals)]])
})
map2(first_sets,coeval,~c(list(set1=.x),.y))
}
almost_ <- map(seq_len(most_to_sum),
~do_second_set(set1_reduced_sets,.x,weight=weight,values=values)) |> flatten()
all_evals <- map_dbl(almost_,~.x$eval)
(best_eval_num <- which.min(all_evals))
almost_[[best_eval_num]]
> almost_[[best_eval_num]]
$set1
[1] 4.528 4.773 4.253 4.688 3.825
$best_second
$best_second[[1]]
[1] 4.210 3.841 4.005 4.545 4.757
$eval
[1] 0.01769181
> sum( 4.528, 4.773, 4.253,4.688 ,3.825)
[1] 22.067
> sum(4.210, 3.841, 4.005,4.545, 4.757)
[1] 21.358
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.