Translating code that carries out SOCP/SDP optimisation from MATLAB to R - r

I have the following MATLAB code which was used in the linked paper (http://www.optimization-online.org/DB_FILE/2014/05/4366.pdf), and would like to be able to use the Rsocp package to be able to carry out the same function but in R. The Rsocp package is available by using the command:
install.packages("Rsocp", repos="http://R-Forge.R-project.org")
and through the socp() function it carries out a similar function to solvesdp(constraints, -wcvar, ops) in the MATLAB code below.
I do not have MATLAB which makes this problem more difficult for me to solve.
The issue I have is the R's socp() function takes matrices as inputs that reflect the data(/covariance matrix and average return values) and constraints all together, where as the MATLAB code seems to be optimising a function...in this specific case it looks like its optimising -wcvar to get the optimal weights, so I am unsure of how to set up my problem in R to get similar results.
The MATLAB code I would therefore like help in translating to R is as follows:
function [w] = rgop(T, mu, sigma, epsilon)
% This function determines the robust growth-optimal portfolio
% Input parameters:
% T - the number of time periods
% mu - the mean vector of asset returns
% sigma - the covariance matrix of asset returns
% epsilon - violation probability
% Output parameters:
% w - robust growth-optimal portfolios
% the number of assets
n = length(mu);
% portfolio weights
w = sdpvar(n,1);
% mean and standard deviation of portfolio
rp = w'*mu;
sigmap = sqrt(w'*sigma*w);
% preclude short selling
constraints = [w >= 0]; %#ok<NBRAK>
% budget constraint
constraints = [constraints, sum(w) == 1];
% worst-case value-at-risk (theorem 4.1)
wcvar = 1/2*(1 - (1 - rp + sqrt((1-epsilon)/epsilon/T)*sigmap)^2 - ((T-1)/epsilon/T)*sigmap^2);
% maximise WCVAR
ops = sdpsettings('solver','sdpt3','verbose',0);
solvesdp(constraints, -wcvar, ops);
w = double(w);
end
For the square root function of the covariance matrix one can use:
Rsocp:::.SqrtMatrix()
Note this question is partially related to my previous question however is more focused on getting the worst case VaR weights:
SOCP Solver Error for fPortoflio using solveRsocp
Perhaps a good start would be to use this code where the Rsocp package has already been used...
https://r-forge.r-project.org/scm/viewvc.php/pkg/fPortfolio/R/solveRsocp.R?view=markup&root=rmetrics&pathrev=3507
EDIT
I think the MATLAB code for the solvesdp function is available from this link:
https://code.google.com/p/vroster/source/browse/trunk/matlab/yalmip/solvesdp.m?r=11
Also a quick question about SOCP optimisations in general...would the result obtained via SOCP optimisation be the same as that achieved using other methods of optimisation? will the only difference be speed and efficiency?
EDIT2
Since it was requested...
rgop <- function(tp, mu, sigma, epsilon){
# INPUTS
# tp - the number of time periods
# mu - the mean vector of asset returns
# sigma - the covariance matrix of asset returns
# epsilon - violation probability
# OUTPUT
# w - robust growth-optimal portfolios
#n is number of assets
n <- length(mu)
# portfolio weights (BUT THIS IS THE OUTPUT)
# for now will assume equal weight
w <- rep(1/n,n)
# mean and standard deviation of portfolio
rp <- sum(w*mu)
sigmap <- as.numeric(sqrt(t(w) %*% sigma %*% w))
# worst-case value-at-risk (theorem 4.1)
wcvar = 1/2*(1 - (1 - rp + sqrt((1-epsilon)/epsilon/tp)*sigmap)^2 - ((tp-1)/epsilon/tp)*sigmap^2);
# optimise...not sure how to carry out this optimisation...
# which is the main thrust of this question...
# could use DEoptim...but would like to understand the SOCP method
}

SOCP is just a fast way of finding the minimum in cases where you know enough about the problem to constrain it in certain technical ways. As you're discovering these constraints can be tricky to formulate, so it is worth asking if you need the speed. Often the answer is yes, but for debugging/exploration purposes brute numerical optimisation using R's optim function can be fruitful.

Related

How to leverage Convex Optimization for Portfolio Optimization in Julia

I'm trying to use Julia (0.5) and Convex.jl (with ECOS solver) to figure out, given a portfolio of 2 stocks, how can I distribute my allocations (in percent) across both stocks such that I maximize my portfolio return and minimize my risk (std dev of returns). I want to maximize what is known as the Sharpe ratio that is a calculation driven from what percentages I have in each of my 2 stocks. So I want to MAXIMIZE the Sharpe ratio and have the solver figure out what is the optimal allocation for the two stocks (I want it to tell me I need x% of stock 1 and 1-x% of stock 2). The only real constraint is that the sum of the percent allocations adds to 100%. I have code below that runs, but does not give me the optimal weights/allocations I'm expecting (which is 36.3% for Supertech & 63.7% for Slowpoke). The solver instead comes back with 50/50.
My intuition is that I either have the objective function modeled incorrectly for the solver, or I need to do more with constraints. I don't have a good grasp on convex optimization so I'm winging it. Also, my objective function uses the variable.value attribute to get the correct output and I suspect I need to be working with the Variable expression object instead.
Question is, is what I'm trying to achieve something the Convex solver is designed for and I just have to model the objective function and constraints better, or do I have to just iterate the weights and brute force it?
Code with comments:
using Convex, ECOS
Supertech = [-.2; .1; .3; .5];
Slowpoke = [.05; .2; -.12; .09];
A = reshape([Supertech; Slowpoke],4,2)
mlen = size(A)[1]
R = vec(mean(A,1))
n=rank(A)
w = Variable(n)
c1 = sum(w) == 1;
λ = .01
w.value = [λ; 1-λ]
sharpe_ratio = sqrt(mlen) * (w.value' * R) / sqrt(sum(vec(w.value' .* w.value) .* vec(cov(A,1,false))))
# sharpe_ratio will be maximized at 1.80519 when w.value = [λ, 1-λ] where λ = .363
p = maximize(sharpe_ratio,c1);
solve!(p, ECOSSolver(verbose = false)); # when verbose=true, says is 'degenerate' because I don't have enough constrains...
println(w.value) # expecting to get [.363; .637] here but I get [0.5; 0.5]

Why is the likelihood/AIC of my poisson regression infinite?

I am trying to evaluate themodel fit of several regressions in R, and I have run into a problem I have had multiple times now: the log-likelihood of my Poisson regression is infinite.
I'm using a non-integer dependent variable (Note: I know what I'm doing in this regard), and I'm wondering if maybe that's the problem. However, I don't get an infinite log-likelihood when running the regression with glm.nb.
Code to reproduce the issue is below.
Edit: the problem appears to go away when I coerce the DV to integer. Any idea how to get log likelihood from Poissons with non-integer DVs?
# Input Data
so_data <- data.frame(dv = c(21.0552722691125, 24.3061351414885, 7.84658638053276,
25.0294679770848, 15.8064731063311, 10.8171744654056, 31.3008088413026,
2.26643928259238, 18.4261153345417, 5.62915828161753, 17.0691184593063,
1.11959635820499, 30.0154935602592, 23.0000809735738, 28.4389825676123,
27.7678405415711, 23.7108405071757, 23.5070651053276, 14.2534787168392,
15.2058525068363, 19.7449094187771, 2.52384709295823, 29.7081691356397,
32.4723790240354, 19.2147002673637, 61.7911384519901, 10.5687170234821,
23.9047421013736, 18.4889651451222, 13.0360878554798, 15.1752866581849,
11.5205948111817, 31.3539840929108, 31.7255952728076, 25.3034625215724,
5.00013988265465, 30.2037887018226, 1.86123112349445, 3.06932041603219,
22.6739418581257, 6.33738321053804, 24.2933951601142, 14.8634827414491,
31.8302947881089, 34.8361908525564, 1.29606416941288, 13.206844629927,
28.843579313401, 25.8024295609021, 14.4414831628722, 18.2109680632694,
14.7092063453463, 10.0738043919183, 28.4124482962025, 27.1004208775326,
1.31350378236957, 14.3009307888745, 1.32555197766214, 2.70896028922312,
3.88043749517381, 3.79492216916016, 19.4507965653633, 32.1689088941444,
2.61278585713499, 41.6955885902228, 2.13466761675063, 30.4207256294235,
24.8231524369244, 20.7605955978196, 17.2182798298094, 2.11563574288652,
12.290778250655, 0.957467139696772, 16.1775287334746))
# Run Model
p_mod <- glm(dv ~ 1, data = so_data, family = poisson(link = 'log'))
# Be Confused
logLik(p_mod)
Elaborating on #ekstroem's comment: the Poisson distribution is only supported over the non-negative integers (0, 1, ...). So, technically speaking, the probability of any non-integer value is zero -- although R does allow for a little bit of fuzz, to allow for round-off/floating-point representation issues:
> dpois(1,lambda=1)
[1] 0.3678794
> dpois(1.1,lambda=1)
[1] 0
Warning message:
In dpois(1.1, lambda = 1) : non-integer x = 1.100000
> dpois(1+1e-7,lambda=1) ## fuzz
[1] 0.3678794
It is theoretically possible to compute something like a Poisson log-likelihood for non-integer values:
my_dpois <- function(x,lambda,log=FALSE) {
LL <- -lambda+x*log(lambda)-lfactorial(x)
if (log) LL else exp(LL)
}
but I would be very careful - some quick tests with integrate suggest it integrates to 1 (after I fixed the bug in it), but I haven't checked more carefully that this is really a well-posed probability distribution. (On the other hand, some reasonable-seeming posts on CrossValidated suggest that it's not insane ...)
You say "I know what I'm doing in this regard"; can you give some more of the context? Some alternative possibilities (although this is steering into CrossValidated territory) -- the best answer depends on where your data really come from (i.e., why you have "count-like" data that are non-integer but you think should be treated as Poisson).
a quasi-Poisson model (family=quasipoisson). (R will still not give you log-likelihood or AIC values in this case, because technically they don't exist -- you're supposed to do inference on the basis of the Wald statistics of the parameters; see e.g. here for more info.)
a Gamma model (probably with a log link)
if the data started out as count data that you've scaled by some measure of effort or exposure), use an appropriate offset model ...
a generalized least-squares model (nlme::gls) with an appropriate heteroscedasticity specification
Poisson log-likelihood involves calculating log(factorial(x)) (https://www.statlect.com/fundamentals-of-statistics/Poisson-distribution-maximum-likelihood). For values larger than 30 it has to be done using Stirling's approximation formula in order to avoid exceeding the limit of computer arithmetic. Sample code in Python:
# define a likelihood function. https://www.statlect.com/fundamentals-of- statistics/Poisson-distribution-maximum-likelihood
def loglikelihood_f(lmba, x):
#Using Stirling formula to avoid calculation of factorial.
#logfactorial(n) = n*ln(n) - n
n = x.size
logfactorial = x*np.log(x+0.001) - x #np.log(factorial(x))
logfactorial[logfactorial == -inf] = 0
result =\
- np.sum(logfactorial) \
- n * lmba \
+ np.log(lmba) * np.sum(x)
return result

Monte carlo integration not working?

I wish to integrate (1/y)*(2/(1+(log(y))^2)) from 0 to 1. Wolfram alpha tells me this should be pi. But when I do monte carlo integration in R, I keep getting 3.00 and 2.99 after trying over 10 times. This is what I have done:
y=runif(10^6)
f=(1/y)*(2/(1+(log(y))^2))
mean(f)
I copied the exact function into wolfram alpha to check that the integral should be pi
I tried to check if my y is properly distributed by checking it's mean and plotting a historgram, and it seems to be ok. Could there be something wrong with my computer?
Edit: Maybe someone else could copy my code and run it themselves, to confirm that it isn't my computer acting up.
Ok, first let's start with simple transformation, log(x) -> x, making integral
I = S 2/(1+x^2) dx, x in [0...infinity]
where S is integration sign.
So function 1/(1+x^2) is falling monotonically and reasonable fast. We need some reasonable PDF to sample points in [0...infinity] interval, such that most of the region where original function is significant is covered. We will use exponential distribution with some free parameter which we will use to optimize sampling.
I = S 2/(1+x^2)*exp(k*x)/k k*exp(-k*x) dx, x in [0...infinity]
So, we have k*e-kx as properly normalized PDF in the range of [0...infinity]. Function to integrate is (2/(1+x^2))*exp(k*x)/k. We know that sampling from exponential is basically -log(U(0,1)), so code to do that is very simple
k <- 0.05
# exponential distribution sampling from uniform vector
Fx <- function(x) {
-log(x) / k
}
# integrand
Fy <- function(x) {
( 2.0 / (1.0 + x*x) )*exp(k*x) / k
}
set.seed(12345)
n <- 10^6L
s <- runif(n)
# one could use rexp() as well instead of Fx
# x <- rexp(n, k)
x <- Fx(s)
f <- Fy(x)
q <- mean(f)
print(q)
Result is equal to 3.145954, for seed 22345 result is equal to 3.135632, for seed 32345 result is equal to 3.146081.
UPDATE
Going back to original function [0...1] is quite simple
UPDATE II
changed per prof.Bolker suggestion

Optimization using package "nloptr"

I am trying to replicate results in R from Excel's "Solver" add-in. I don't know about the inner workings of optimization (mathematically), hence my confusion at most post results as well as the error messages I am receiving. I tried using the optimx package, but apparently that doesn't allow for too much control over the constraints in the optimization, so now I'm trying out the nloptr package.
Basically, what I'm trying to do is replicate an optimum portfolio calculation (financial). Below is a sample of my code:
ret.cov <- cov(as.matrix(ret.p[,1:30]))
wts <- rep(1/portfolioSize, times = portfolioSize)
sharpe <- function(wts) {
mean.p <- sum(colMeans(ret.p[,1:30])*wts)
var.p <- t(wts) %*% (ret.cov %*% (wts))
sd.p <- sqrt(var.p)
SR <- (mean.p - Rf)/sd.p
return(as.numeric(SR))
}
fun.eq <- function(wts) {
sum(wts) == 1
}
optim.p <- nloptr(x0 = wts, eval_f = sharpe, lb = 0, ub = 1, eval_g_eq = fun.eq)
sharpe(as.numeric(optim.p$solution))
Calculates the covariance matrix of 30 stocks and their returns
Initializes the weights of those stocks to optimize (equally weighted to start)
Sets up a function to maximize which calculates the portfolio's Sharpe Ratio
Tries (???) to specify the equality function for nloptr that states that the sum of the wts vector must be equal to 1.
Tries to maximize the function (though I think it's minimizing by default, and I don't know how to change that to maximize instead).
Checks the resulting, maximized Sharpe Ratio
The Sharpe calculation function works fine, when I try it outside of the nloptr function. The issues are various, from needing to specify the proper algorithm to use, to the function not accepting the equality function I supplied.
So, the questions I have are:
How do you change the nloptr to maximize instead of minimize?
How would one write an equality function to specify that the sum of the input vector (weights) must be equal to 1?
What is the proper algorithm to specify using opts = list() here? Excel uses something called "GRG Nonlinear".
Thank you in advance!
Hope it's still relevant...
You don't supply data so I can't run it but I'll try to help.
1) In order to maximize just minimize the -sharpe
2) eval_g_eq needs to be in format of h(x)=0, meaning that you need on fun.eq to change sum(wts) == 1 to sum(wts) - 1.
3) There are a lot of decent options. I use NLOPT_LN_COBYLA

Errors when attempting constrained optimisation using optim()

I have been using the Excel solver to handle the following problem
solve for a b and c in the equation:
y = a*b*c*x/((1 - c*x)(1 - c*x + b*c*x))
subject to the constraints
0 < a < 100
0 < b < 100
0 < c < 100
f(x[1]) < 10
f(x[2]) > 20
f(x[3]) < 40
where I have about 10 (x,y) value pairs. I minimize the sum of abs(y - f(x)). And I can constrain both the coefficients and the range of values for the result of my function at each x.
I tried nls (without trying to impose the constraints) and while Excel provided estimates for almost any starting values I cared to provide, nls almost never returned an answer.
I switched to using optim, but I'm having trouble applying the constraints.
This is where I have gotten so far-
best = function(p,x,y){sum(abs(y - p[1]*p[2]*p[3]*x/((1 - p[3]*x)*(1 - p[3]*x + p[2]*p[3]*x))))}
p = c(1,1,1)
x = c(.1,.5,.9)
y = c(5,26,35)
optim(p,best,x=x,y=y)
I did this to add the first set of constraints-
optim(p,best,x=x,y=y,method="L-BFGS-B",lower=c(0,0,0),upper=c(100,100,100))
I get the error ""ERROR: ABNORMAL_TERMINATION_IN_LNSRCH"
and end up with a higher value of the error ($value). So it seems like I am doing something wrong. I couldn't figure out how to apply my other set of constraints at all.
Could someone provide me a basic idea how to solve this problem that a non-statistician can understand? I looked at a lot of posts and looked in a few R books. The R books stopped at the simplest use of optim.
The absolute value introduces a singularity:
you may want to use a square instead,
especially for gradient-based methods (such as L-BFGS).
The denominator of your function can be zero.
The fact that the parameters appear in products
and that you allow them to be (arbitrarily close to) zero
can also cause problems.
You can try with other optimizers
(complete list on the optimization task view),
until you find one for which the optimization converges.
x0 <- c(.1,.5,.9)
y0 <- c(5,26,35)
p <- c(1,1,1)
lower <- 0*p
upper <- 100 + lower
f <- function(p,x=x0,y=y0) sum(
(
y - p[1]*p[2]*p[3]*x / ( (1 - p[3]*x)*(1 - p[3]*x + p[2]*p[3]*x) )
)^2
)
library(dfoptim)
nmkb(p, f, lower=lower, upper=upper) # Converges
library(Rvmmin)
Rvmmin(p, f, lower=lower, upper=upper) # Does not converge
library(DEoptim)
DEoptim(f, lower, upper) # Does not converge
library(NMOF)
PSopt(f, list(min=lower, max=upper))[c("xbest", "OFvalue")] # Does not really converge
DEopt(f, list(min=lower, max=upper))[c("xbest", "OFvalue")] # Does not really converge
library(minqa)
bobyqa(p, f, lower, upper) # Does not really converge
As a last resort, you can always use a grid search.
library(NMOF)
r <- gridSearch( f,
lapply(seq_along(p), function(i) seq(lower[i],upper[i],length=200))
)

Resources