Scipy minimize - minimum absolute weights but 0 acceptable

82 Views Asked by At

I am trying to optimize a portfolio allocation. I am happy for some weights to be 0 but I do not want to get values that are less than some threshold T. this is on absolute values as negative weights are accepted.

So something like W = [w0, w1, ..., wn] where abs(wi) >= T or 0.

Is that at all possible?

I have not been able to find out. My 2 options at the moment:

  • remove any abs(wi) < T (so I enforce 0) and re-optimize
  • or is there a more appropriate optimiser tool?

Thanks,

looked all around the place. I am starting to implement the remove small weights and re-run method but I feel there should be a better way.

Edit: I will add more code tomorrow but basically I have a really simple A * x = B equation to solve. A is an upper diagonal matrix and B a vector. So if it was not for my constraint on weight, this is a simple matrix inversion and you get a perfect match. This will quite often come up with weights that are too small for our liking, so we want to force the optimiser to set 0s for those weights under a certain threshold. The cost function is a standard quadratic error.

Edit 2: Here is the code:

class TestMinimizer:
    def __init__(self, X, target, min_size=None):
        self.X = X
        self.target = target
        self.min_size = min_size

    def solve(self) -> pd.Series:
        w0 = np.ones_like(self.target)

        solution = minimize(self.objective_function, w0, bounds=None)
        return solution.x

    def objective_function(self, weights):
        error = np.matmul(self.X, weights) - self.target
        return (error**2).sum()

Again, I would like to use the min_size to force individual weight in that weights vector to be more than min_size in absolute values or 0s. So the constraint is not continuous.

Am I making any sense?

1

There are 1 best solutions below

6
On BEST ANSWER

I think you should just be able to do:

    def objective_function(self, weights):
        # set values below min_size theshold to zero
        weights[np.abs(weights) < self.min_size] = 0.0
        error = np.matmul(self.X, weights) - self.target
        return (error**2).sum()