как сделать оптимальный комбинаторный выбор в R - PullRequest
0 голосов
/ 11 декабря 2018

Проблема, которую я пытаюсь решить, в основном та же, что и в этом посте:

https://stats.stackexchange.com/questions/339935/python-library-for-combinatorial-optimization

И моя текущая реализация действительно использует оптимизатор на основе генетического алгоритма.

Тем не менее, я хотел бы решить ее как бинарную задачу линейного программирования (по крайней мере, попытаться, хотя, по-видимому, это 'NP-hard').

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

Ниже приведена упрощенная версия того, с чем я имею дело, которая, однако, точно показывает, в чем проблема.

Мы создаем m * n (в данном случае 6) объектов комбинаторным процессом, беря m (3) объектов типа 'R1' (скажем, {A, B, C}) и n (2) объектов типа 'R2' (скажем {X, Y}).
6 объектов {AX, AY, BX, BY, CX, CY} оцениваются, и каждый получает оценку D, в данном случае {0.8,0.7,0.5,0.9,0.4,0.0}, в этом порядке.

CL <- cbind(expand.grid(R2=LETTERS[24:25],R1=LETTERS[1:3],stringsAsFactors = FALSE),D=c(0.8,0.7,0.5,0.9,0.4,0.0))

Теперь мы хотим выбрать 2 различных R1 и 1 R2 так, чтобы сумма D была максимальной.

В этом примере ответом является R1 = {A, B}, R2 = {Y}.

Однако нельзя прийти к такому выводу, принимая, например, 2 R1 и R2 ссамый высокий средний D.
Это будет работать для R1, но не для R2:

aggregate(D~R1,CL,mean)
#  R1    D
#1  A 0.75
#2  B 0.70
#3  C 0.20
aggregate(D~R2,CL,mean)
#  R2         D
#1  X 0.5666667
#2  Y 0.5333333

Я знаю, как сформулировать это как задачу линейного программирования;только я не уверен, что моя формулировка эффективна, потому что в основном это приводит к проблеме с m n + m + n переменными и 2 (m + n) +2 ограничениями.
Основная трудность заключается в том, чтоМне нужно как-то подсчитать количество выбранных R1 и R2, и я не знаю никакого способа сделать это, кроме того, что я покажу ниже (и также описано в моем другом посте здесь ).

Вот что я бы сделал:

CL["Entry"] <- seq_len(dim(CL)[[1]])

R1.mat <- table(CL$R1,CL$Entry)
R2.mat <- table(CL$R2,CL$Entry)

N_R1 <- dim(R1.mat)[[1]]
N_R2 <- dim(R2.mat)[[1]]
N_Entry <- dim(CL)[[1]]

constr.mat <- NULL
dir <- NULL
rhs <- NULL

constr.mat <- rbind(constr.mat,cbind(R1.mat,-diag(table(CL$R1)),matrix(0,N_R1,N_R2)))
dir <- c(dir,rep("<=",N_R1))
rhs <- c(rhs,rep(0,N_R1))

constr.mat <- rbind(constr.mat,cbind(R2.mat,matrix(0,N_R2,N_R1),-diag(table(CL$R2))))
dir <- c(dir,rep("<=",N_R2))
rhs <- c(rhs,rep(0,N_R2))

constr.mat <- rbind(constr.mat,constr.mat)
dir <- c(dir,rep(">=",N_R1+N_R2))
rhs <- c(rhs,1-table(CL$R1),1-table(CL$R2))

constr.mat <- rbind(constr.mat,c(rep(0,N_Entry),rep(1,N_R1),rep(0,N_R2)))
dir <- c(dir,"==")
rhs <- c(rhs,2)

constr.mat <- rbind(constr.mat,c(rep(0,N_Entry),rep(0,N_R1),rep(1,N_R2)))
dir <- c(dir,"==")
rhs <- c(rhs,1)

obj <- c(aggregate(D~Entry,CL,c)[["D"]],rep(0,N_R1+N_R2))

Что можно решить, например, с помощью lpSolve:

sol <- lp("max", obj, constr.mat, dir, rhs, all.bin = TRUE,num.bin.solns = 1, use.rw=FALSE, transpose.constr=TRUE)
sol$solution
#[1] 0 1 0 1 0 0 1 1 0 0 1

, показывающего, что продукты {AY, BY}были выбраны, соответствующие R1 = {A, B} и R2 = {Y}:

CL[as.logical(sol$solution[1:N_Entry]),]
#  R2 R1   D Entry
#2  Y  A 0.7     2
#4  Y  B 0.9     4

Я обнаружил, что при больших проблемах lpSolve застревает на века;Rsymphony, кажется, работал лучше.
Но опять же, мой главный вопрос: эффективен ли этот способ формулировки LP?Должен ли я сделать это по-другому?

Спасибо!


РЕДАКТИРОВАТЬ

А пока, работая над несколько связанной проблемой, я обнаружил , что может быть достаточно только одного набора ограничений, если добавить «затраты» (в данном примере, отрицательные) к целевому вектору для «различных переменных R1 и R2».
Здесь вместо:

obj <- c(aggregate(D~Entry,CL,c)[["D"]],rep(0,N_R1+N_R2))

Я бы сделал:

obj <- c(aggregate(D~Entry,CL,c)[["D"]],rep(-1,N_R1+N_R2))

Это сделало бы ненужными ограничения m + n .
Это все еще остается огромной проблемой для решения,даже для относительно небольших m, n , поэтому, если кто-нибудь может посоветовать, как это сделать лучше ...
Я посмотрел на lp.transport, но это будет ограничено двумя измерениями (т.е. толькоR1 и R2, а не R1, R2, R3, например), и я не думаю, что вы можете ограничить количество различных объектов на категорию в этом типе решателя.

...