2016-08-13 2 views
1

Может ли кто-нибудь помочь мне в решении этой задачи для оптимизации многомерных параметров функции в R, у меня есть набор данных, подобный этому. Это всего лишь подмножество данных, размер полного набора данных - n type * m regions * 12 months.Минимизировать целевую функцию, используя R

Month region type physics maths allsub 
Jan  r1  1  4  5  9   
Feb  r1  1  3  8  11  
Mar  r1  1  5  4  9 
Apr  r1  1  6  7  13 
May  r1  1  4  4  8 
Jun  r1  1  8  9  17 
Jul  r1  1  4  3  7 
Aug  r1  1  5  4  9 
Sep  r1  1  3  8  11 
Oct  r1  1  9  2  11 
Nov  r1  1  4  7  11 
Dec  r1  1  7  3  10 
Jan  r1  2  5  8  13 
Feb  r1  2  4  9  13 
Mar  r1  2  8  3  11 
Apr  r1  2  5  6  11 
May  r1  2  6  4  10 
Jun  r1  2  7  6  13 
Jul  r1  2  3  7  10 
Aug  r1  2  4  8  12 
Sep  r1  2  4  4  8 
Oct  r1  2  8  1  9 
Nov  r1  2  2  3  5 
Dec  r1  2  1  6  7 

...  ...  .. ... ... .... 
...  ...  .. ... ... .... 

У меня есть еще один набор данных, который имеет максимальное количество студентов по физике и математике в каждом регионе. И моя целевая функция такова: 100*(physics) + 65*(maths) >= 0. Я хочу свести к минимуму эту функцию, и мои ограничения: 1. Сумма физики и математики всегда должна быть равна allsub для этого региона и месяца. 2. Общее количество студентов-физиков в регионе каждый месяц должно быть меньше максимального числа студентов-физиков, доступных в этом регионе. 3. Общее количество студентов-математиков в регионе каждый месяц должно быть меньше максимального количества студентов-математиков, доступных в этом регионе.

Я пытаюсь использовать R. Вся идея состоит в том, чтобы найти нужное количество студентов-физиков и математиков в каждом регионе/типе/месяце, минимизируя целевую функцию и удовлетворяя ограничениям. Может кто-то помочь мне с этим?

EDIT: По просьбе в комментариях. Вот полный набор данных о емкости. Имя dataframe = totalcap

Month region physicscap mathscap 
1 Jan r1 9   13 
2 Feb r1 7   17 
3 Mar r1 13   7 
4 Apr r1 11   13 
5 May r1 10   8 
6 Jun r1 15   15 
7 Jul r1 7   10 
8 Aug r1 9   12 
9 Sep r1 7   12 
10 Oct r1 17   3 
11 Nov r1 6   10 
12 Dec r1 8   9 

Вот сценарий, я пытался,

library(dplyr) 
library(MASS) 
library(Rsolnp) 

Month <- c('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec') 
region <- c('r1') 
physicscap <- c(5,5,8,6,7,9,5,6,4,10,5,8) 
mathscap <- c(5,8,5,8,5,10,5,5,8,5,8,5) 

totalcap <- data.frame(Month,region,physicscap,mathscap) 
    #Constraints for the optimization. 
constraints2 <- function(efforts){ 
    # constraints are: 
    # 1. effort - allsub <= 0 in each region/month 
    #  
    efforts$effort_calculated <- efforts$physics + efforts+maths 
    reqeff <- summarise(group_by(efforts,region,Month),monthlyeffreg=sum(effort_calculated)) 
    reqeffallsub <- summarise(group_by(efforts,region,Month),allsubsum=sum(allsub)) 
    cons1 <- mutate(inner_join(reqeff,reqeffallsub,by=c('region'='region','Month'='Month')) 
    ,diff=monthlyeffreg-allsubsum) 
    constout <- cons1$diff 


    # 2. sum(physics) - total physics available <= 0 in each region/month 
    # 
    phyreqeff <- summarise(group_by(efforts,region,Month),physicseff=sum(physics)) 
    cons2 <- mutate(inner_join(totalcap,phyreqeff,by=c('region'='region','Month'='Month')), 
        diff=physicseff-physicscap) 
    constout <- c(constout,cons2$diff) 


    # 3. sum(maths) - total maths available <= 0 in each region/month 
    # 
    matreqeff <- summarise(group_by(efforts,region,Month),mathseff=sum(maths)) 
    cons3 <- mutate(inner_join(totalcap,matreqeff,by=c('region'='region','Month'='Month')), 
        diff=mathseff-mathscap) 
    constout <- c(constout,cons3$diff) 
    constout 
} 


#Objective function to minimize the cost function. 
objectivefunc <- function(efforts){ 
    nb_physics <- sum(efforts$physics) 
    nb_maths <- sum(efforts$maths) 
    objective <- (100*nb_physics + 55*nb_maths - 110) 
    objective 
} 

Out2 <- solnp(pars = efforts,fun=objectivefunc,ineqfun=constraints2,ineqLB = rep(-100000,36), 
       ineqUB = rep(0,36), LB = rep(0,length(u))) 

Здесь ошибка я получаю,

Error in p0/vscale[(neq + 2):(nc + np + 1)] : 
    non-numeric argument to binary operator 

Надеется, что это очищает вопросы в комментариях. Я пробовал свой уровень лучше здесь, надеюсь, кто-то поможет мне в решении этого.

+1

SO - это не поиск пакетов и обработка кода. У вас должно быть 1) поиск необходимых R-библиотек, а 2) затем отправлен весь код R, который закодировал функцию, установил необходимые библиотеки, загрузил их и представил все ограничения. –

+0

Этот вопрос представляется дубликатом: http://stackoverflow.com/questions/5436630/constrained-optimization-in-r, хотя я не согласен с тем, что '100 * (физика) + 65 * (maths)> = 0' может быть объективная функция. Это логическое выражение и может принимать только одно из двух значений. –

+0

Спасибо за ваши комментарии. вы правы, я сделал свое кодирование, написал свои ограничения и целевую функцию. когда я пытаюсь запустить его с помощью пакета solnp, я получил эту ошибку.Ошибка в p0/vscale [(neq + 2) :(nc + np + 1)]: нечисловой аргумент двоичному оператору. Поэтому я пытаюсь понять, что я делаю что-то неправильно и вижу, есть ли другие варианты для достижения результата. И то, что я здесь привел, является лишь примером, поэтому не стоит слишком беспокоиться о структуре. еще раз спасибо. –

ответ

1

Вот подход с lpSolveAPI:

dat <- data.frame(
    mon=rep(c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"),2), 
    region="r1", 
    type=c(rep("1", 12), rep("2", 12)), 
    physicsmin=1, 
    mathsmin=1, 
    allsub=c(9, 11, 9, 13, 8, 17, 7, 9, 11, 11, 11, 10, 13,13,11,11,10,13,10,12,8,9,5,7), 
    stringsAsFactors=FALSE 
) 
dat 
capdat <- data.frame(
    mon=c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"), 
    region="r1", 
    physicscap=c(9,7,13,11,10,15,7,9,7,17,6,8), 
    mathscap=c(13,17,7,13,8,15,10,12,12,3,10,9), 
    stringsAsFactors=FALSE 
) 
capdat 

Теперь для каждого месяца/комбинации региона задача оптимизации должна быть решена. Именно поэтому мы оборачиваем расчет в функции:

library(lpSolveAPI) 
ntypes <- length(unique(dat[,"type"])) # number of types 
typemap <- setNames(seq.int(ntypes), unique(dat[,"type"])) # map typename to 1,...,ntypes 

solve_one <- function(subdat, capdat) { 

    # create object 
    lprec <- make.lp(0, ncol=2*ntypes) # for each type, two decision variables 

    # By convention, we assume that the first ntypes variables are physics for type 1, ..., ntypes 
    # and the second ntypes variables are maths 

    # add objective and type 
    set.objfn(lprec, obj=c(rep(100, ntypes), rep(65, ntypes))) 
    set.type(lprec, columns=seq.int(2*ntypes), type="integer") # no reals 

    # add capacity constraints 
    idx <- which(capdat[,"mon"]==subdat[1,"mon"] & capdat[,"region"]==subdat[1,"region"]) # lookup the right cap 
    add.constraint(lprec, rep(1, ntypes), type="<=", rhs=capdat[idx,"physicscap"], indices=seq.int(ntypes)) 
    add.constraint(lprec, rep(1, ntypes), type="<=", rhs=capdat[idx,"mathscap"], indices=seq.int(ntypes+1, 2*ntypes)) 

    # add allsub equality constraints and minimum constraints 
    for (typ in subdat[,"type"]) { 
     add.constraint(lprec, c(1,1), type="=", rhs=subdat[typemap[typ], "allsub"], indices=c(typemap[typ], ntypes+typemap[typ])) 
     add.constraint(lprec, 1, type=">=", rhs=subdat[typemap[typ],"physicsmin"], indices=typemap[typ]) 
     add.constraint(lprec, 1, type=">=", rhs=subdat[typemap[typ],"mathsmin"], indices=ntypes+typemap[typ]) 
    } 

    # solution data.frame 
    ans <- subdat[, c("mon", "region", "type")] 

    # solve  
    if(solve(lprec)==0) { 
     sol <- get.variables(lprec) 
     for (i in seq.int(nrow(subdat))) { 
      ans[i, "physics"] <- sol[typemap[subdat[i,"type"]]] 
      ans[i, "maths"] <- sol[typemap[subdat[i,"type"]]+ntypes] 
     } 
    } else ans[,c("physics", "maths")] <- NA # no solution found 

    return(ans) 
} 

Теперь мы применим функцию к каждому subdataset, которая включает в себя все типы для каждой комбинации месяц/региона. Мы использовать split/apply/combine подход здесь:

sp <- split(dat, list(dat[,"mon"], dat[,"region"])) 
results <- lapply(sp, solve_one, capdat=capdat) 
results <- do.call(rbind, results) 
rownames(results) <- NULL 
results 

код не предполагает, что для каждой комбинации месяца/региона всех типов присутствуют (некоторые типы могут быть опущены), однако решение будет неправильным, если есть несколько записей присутствуют в течение того же месяца/региона/комбинации типов. (для этого потребуется адаптировать код).

+0

Считаете ли вы, что физикака и mathscap - это уровень региона, а не уровень каждого типа. Таким образом, ограничения 1 и 2 являются суммой (физикой) в области, которая должна быть меньше, чем физика в этой области. Аналогично для математики. –

+0

Таким образом, ограничение состоит в том, что для каждого месяца и региона сумма студентов-физиков над всеми типами должна быть ниже физического уровня этого региона/месяца? (и аналогично для математики) –

+0

Да, это правильно –