Search code examples
scipyscipy-optimize

Scipy optimize non linear function not optimal


I have a simple non linear objective function as followed. I want to maximize the total number of leads, with the leads function being the leads for one of the df rows and total_leads being the optimization function:

def leads(x, feats):
    a, b, c = feats
    return a * x + b * np.sqrt(x) + c

def total_leads(spend_list, regress_features):
    return -sum([leads(x,y) for x,y in zip(spend_list,regress_features)])

def max_budget(spends, max_spend):
    # Needs to be positive to not violate constraint
    return max_spend - sum(spends)

Here is the code to run the optimization.

reg_feats = [tuple(x) for x in df[list('abc')].values]

max_spend = 280000

min_spend = max_spend * 0.02
# List of (minbound,maxbound) row
bounds = [(min(min_spend,max_spend),max_spend) for max_spend in df['Max_spend']]

x0 = np.mean(bounds, axis=1)

constraints = {'type':'ineq','fun':max_budget,'args':(max_spend,)}

result = minimize(total_leads,x0,args=(reg_feats,),constraints=constraints,method='SLSQP',bounds=bounds,options={'maxiter': 10**5})

df ='   Max_spend   a           b           c
    0   4459    0.001600    -0.050592   0.271046
    1   6798    0.006000    -0.115749   -0.873647
    2   18248   -0.000261   0.155548    -4.936540
    3   7818    0.000571    -0.042275   0.688899
    4   22419   -0.001117   0.581695    -13.277250
    5   3643    0.001767    -0.065073   0.524264
    6   51592   0.008957    -0.563969   6.754103
    7   13179   0.000770    -0.075454   1.544488
    8   16650   0.000256    0.004385    -0.391338
    9   5994    0.007731    0.165316    1.010207
    10  14070   0.019119    -0.442078   3.811875'

When I optimize this function, I get a result which is clearly not optimal. The budget is not fully used and not every variable is at its upper/lower bound. I know this function is a local optimizer, however the global optimizers don't seem to return results in a reasonable amount of time.

I also don't need a global optimum, just looking for a decent local optimum.


Solution

  • It seems that having x0 = np.max(bounds, axis=1) instead of x0 = np.mean(bounds, axis=1) works well in this case.