6

Sono abbastanza nuovo per R e sto cercando di scrivere uno script per quello che facevo con Solver in Excel. Nei miei dati di seguito, ho un elenco di lavoratori con tipi di lavoro A-E. Ogni lavoratore ha uno stipendio e un tasso di produzione. Quello che voglio che R faccia è trovare la massima produzione che posso ottenere da 10 lavoratori con uno stipendio cumulativo < 100.000. Le restrizioni sono che ho bisogno di un totale esatto di 10 lavoratori e ho bisogno di 2 dai tipi di lavoro A-D, 1 da E, e 1 di qualsiasi tipo.Come usare R per risolvere/scegliere le persone migliori per un lavoro - con restrizioni?

Ho cercato e cercato un modo per farlo con ottim, IpSolve, ecc., Ma con le mie conoscenze limitate non ho avuto molta fortuna.

Grazie per il vostro aiuto!

Name Pos Salary Producton 
Joe  A 12001 13.1 
Jim  A 17753 23.5 
Jill A 11447 14.8 
Brian A 11447 14.8 
Sally B 2171 1.2 
Nancy B 4537 2.1 
Francis B 2840 1.8 
Ace  B 2840 1.8 
Bill C 3818 1.6 
Ted  C 11447 0.1 
Henry C 2000 1.1 
Kyle C 3818 1.6 
Sam  D 11447 0.1 
Trevor D 2000 1.1 
John D 4317 11.7 
Jerome D 2000 1.1 
Rebecca E 3818 1.6 
Sunny E 11447 0.1 
Britt E 2000 1.1 
Sara E 4317 11.7 
+0

Sì, un minimo di 2. Grazie! –

+0

Solo un pensiero: scegliere (20,10) = 184756, quindi non ci vorrà molto tempo per testare ogni possibile combinazione in questo piccolo caso. A meno che, naturalmente, questo non sia compito e tu * devi * usare un risolutore. –

+0

Fortunatamente non sono i compiti, ma l'elenco completo contiene oltre trecento persone. Il mio errore, avrei dovuto menzionarlo nel post originale. –

risposta

6

Uso lp nel pacchetto lpSolve per risolvere il problema sottostante programmazione intera. I primi 5 vincoli sono rispettivamente sul numero di posizioni A, B, C, D ed E, il sesto è sul numero di dipendenti da scegliere e il settimo è sul salario totale. Supponendo DF è il frame di dati indicato nella domanda provate questo:

library(lpSolve) 

obj <- DF$Prod 
con <- rbind(t(model.matrix(~ Pos + 0, DF)), rep(1, nrow(DF)), DF$Salary) 
dir <- c(">=", ">=", ">=", ">=", ">=", "==", "<") 
rhs <- c(2, 2, 2, 2, 1, 10, 100000) 

result <- lp("max", obj, con, dir, rhs, all.bin = TRUE) 

che dà:

> result 
Success: the objective function is 84.7 
> DF[result$solution == 1, ] 
    Name Pos Salary Producton 
2  Jim A 17753  23.5 
3 Jill A 11447  14.8 
4 Brian A 11447  14.8 
6 Nancy B 4537  2.1 
8  Ace B 2840  1.8 
9 Bill C 3818  1.6 
12 Kyle C 3818  1.6 
14 Trevor D 2000  1.1 
15 John D 4317  11.7 
20 Sara E 4317  11.7 

Nota che la produzione è errato nella domanda o forse che era destinato.

aggiunto:

Per quanto riguarda la soluzione di ripiego l'idea è quella di aggiungere un vincolo che rende la soluzione migliore non fattibile, ma non esclude altre possibili soluzioni:

con2 <- rbind(con, result$solution) 
dir2 <- c(dir, "<=") 
rhs2 <- c(rhs, 9) 
result2 <- lp("max", obj, con2, dir2, rhs2, all.bin = TRUE) 

In questo caso si ottiene la seguente che ha lo stesso valore oggettivo ottimale come la soluzione migliore quindi sarebbe altrettanto buono:

> result2 
Success: the objective function is 84.7 
> DF[result2$solution == 1, ] 
    Name Pos Salary Producton 
2  Jim A 17753  23.5 
3 Jill A 11447  14.8 
4 Brian A 11447  14.8 
6 Nancy B 4537  2.1 
8  Ace B 2840  1.8 
9 Bill C 3818  1.6 
12 Kyle C 3818  1.6 
15 John D 4317  11.7 
16 Jerome D 2000  1.1 
20 Sara E 4317  11.7 

ci sono anche argomenti per 01.236.406,816399 millionsche consentono di produrre direttamente più soluzioni; tuttavia, il file di aiuto menziona alcuni bug e potrebbe essere più sicuro adottare l'approccio di cui sopra.

+0

Incredibile, grazie mille! Come ciliegina sulla torta, c'è un modo per ottenere la seconda migliore soluzione? –

+0

Domanda: stavo pensando ad un algoritmo come: 1) calcolare una cifra di merito, cioè Produzione/Salario, 2) Prendere il primo candidato FOM da ogni categoria richiesta (AE), 3) riempire gli spazi rimanenti con il FOM rimanente superiore valori. Questo è essenzialmente ciò che sta facendo lpSolve? –

+0

@Derek, ho aggiunto una seconda soluzione migliore. @Carl, 'lp' usa l'algoritmo branch-and-bound. –

Problemi correlati