Search code examples
rleast-squares

Weighted nonnegative least squares in R


I would like to perform weighted nonnegative least squares in R (i.e. with the constraint that all fitted coefficients are >=0). The nnls function in the nnls package appears not to support weights. Am I correct that I can simulate weights though within the nnls function by multiplying both the covariate matrix X and the dependent variable y by the square root of the weights vector, as seems to be indicated here? Or is there better approaches to do this?


Solution

  • 1) nnls Yes, it is equivalent since weighted least squares minimizes:

    sum( w * (Y - X %*% beta)^2 )
    = sum_i( (sqrt(w[i]) * X[i, ] %*% beta - sqrt(w[i]) * Y[i])^2 )
    

    subject to constraints where sum_i means sum over i. Thus sqrt(w[i]) multiplies the ith row of X and the ith element of Y which is equivalent to using sqrt(w) * X and sqrt(w) * Y. (Note that these are also equal to diag(sqrt(w)) %*% X and c(diag(sqrt(w)) %*% Y) respectively.)

    2) CVXR The CVXR package can do weighted non-negative least squares directly. There is an example of performing non-negative least squares in its vignette.

    vignette("cvxr_intro")
    

    Just change the objective in the code there to add weights:

    objective <- Minimize(sum((w *(Y - X %*% betaHat)^2)))
    

    3) nls nls which comes with R can do non-negative weighted least squares if you use the port algorithm with lower bounds of all 0. (In the code below we have started at zero and normally it is not a good idea to start on the boundary but given the linearity here it really doesn't matter.)

    zeros <- numeric(ncol(X))
    nls(Y ~ X %*% b, start = list(b = zeros), weights = w, lower = zeros, alg = "port")
    

    Run all three approaches to double check the answers.