相信数学模型可以是这样的:
这里i
是商店和j
是治疗。在R中,这可以用不同的工具来实现。我在这里使用OMPR。为完整的R脚本如下:
library(dplyr)
library(tidyr)
library(ROI)
library(ROI.plugin.symphony)
library(ompr)
library(ompr.roi)
df<-read.table(text="
Store Treatment Cost Profit
1 A 50 100
1 B 100 200
1 C 75 50
2 A 25 25
2 B 150 0
2 C 50 25
3 A 100 300
3 B 125 250
3 C 75 275
4 A 25 25
4 B 50 75
4 C 75 125
",header=T)
stores<-unique(df$Store)
treatments<-levels(df$Treatment)
num_treatments <- length(treatments)
cost <- as.matrix(spread(subset(df,select=c(Store,Treatment,Cost)),Treatment,Cost)[,-1])
profit <- as.matrix(spread(subset(df,select=c(Store,Treatment,Profit)),Treatment,Profit)[,-1])
max_cost <- 300
m <- MIPModel() %>%
add_variable(x[i,j],i=stores,j=1:num_treatments,type="binary") %>%
add_constraint(sum_expr(x[i,j],j=1:num_treatments)<=1,i=stores) %>%
add_constraint(sum_expr(cost[i,j]*x[i,j],i=stores,j=1:num_treatments)<=max_cost) %>%
set_objective(sum_expr(profit[i,j]*x[i,j],i=stores,j=1:num_treatments),"max") %>%
solve_model(with_ROI(solver = "symphony"))
cat("Status:",solver_status(m))
cat("Objective:",objective_value(m))
get_solution(m,x[i, j]) %>%
filter(value > 0) %>%
mutate(Treatment = treatments[j],Store = i) %>%
select(Store,Treatment)
这应该给:
Status: optimal
Objective: 650
Store Treatment
1 2 A
2 3 A
3 1 B
4 4 C
嗨欧文,感谢这一点,这是真的很有帮助。但是,我试图在完整数据集上运行时遇到错误:protect():保护堆栈溢出。对此有何帮助? – user2778822
这取决于这一切正在发生的地方以及数据集有多大。一些想法:(1)如果MIP问题变得非常大,可以增加保护栈的大小(2),使用一些外部最先进的商业解决方案(3)我认为有很好的机会来预处理数据只保留有趣的候选人(4)实施一些启发式而不是正式的优化步骤。在我看来,就像一个小小的研究项目。 –