user3875610 user3875610 - 18 days ago 5
R Question

Optimize with Constraints in R

I am attempting to work on portfolio optimisation problem, basically we have some product, the %portfolio and the return rate. Basically I have to optimise the overall return rate to be maximum. The problem gets tricky because there is a minimum constraint specific to product

Data:

product share_per return_per min_share_per
prod1 0.5 0.1 0.2
prod2 0.2 0.4 0.1
prod3 0.2 0.05 0.0
prod4 0.1 0.04 0.0
prod5 0.0 0.3 0.0


Basically we are performing the optimising on column share_per so as to make product *(share_per * return_per)* maximum
My hopelessly bad attempt to this was

mat <- matrix(c(0.5, 0.2, 0.2, 0.1, 0.0))
colnames(mat) <- c("return_per")

minmax <- function(x, a) (sum(a*x))
opt <- apply(mat, 1, function(i) {
optimize(minmax, c(0, 1), a = i[["return_per"]], maximum=T)$maximum
})

mat2 <- cbind(mat, opt)
mat2


As you can see I can neither figure out where to specify the constraint specific to a row

I know constrOptim is something i should be looking but I can't figure the constraint part.

Answer

You can try this:

df <- read.table(text='product share_per return_per min_share_per
                 prod1   0.5       0.1        0.2
                 prod2   0.2       0.4        0.1
                 prod3   0.2       0.05       0.0
                 prod4   0.1       0.04       0.0
                 prod5   0.0       0.3        0.0', header=TRUE)

ret <- df$return_per

fn <- function(sp) sum(ret*sp) # objective

Amat <- rbind(diag(nrow(df)), diag(-1,nrow(df)), rep(-1,nrow(df))) # constraints
bvec  <- c(df$min_share_per, rep(-1, nrow(df)), -1)                # sp_j >= min_share_per,  
                                                                   # sp_j <= 1 and 
                                                                   # sum_j sp_j <= 1
init <- c(0.5,0.2,0.2,0.05,0.01) # making sure that the initial value is in the feasible region

sol <- constrOptim(init, fn, NULL, ui = Amat, ci = bvec, control=list(fnscale=-1)) # maximize
round(sol$par, 2)
# [1] 0.2 0.8 0.0 0.0 0.0