I am using pulp
in an attempt to minimize the deviation from a target. In the MRE below, assume that items 1-50 have features A, B, C, D. The optimizer should apportion a "budget" equal to 100%, while attempting to get the average value of feature "A" equal to tgt_a
. It would be fairly easy to just tell pulp
to force a
to be equal to the target, but in real life, it may not be possible to get exactly to the target. In addition, I ultimately want to have the system balance all the various features using a sum of squared deviation method, which makes it even less likely that a perfect solution even exists.
The code below runs fine, but simply minimizes the difference between the actual "A" feature value and the target. I need to square the difference in order to make it useful. However if you add a **2
to the appropriate line of code, you get:
TypeError: unsupported operand type(s) for ** or pow(): 'LpAffineExpression' and 'int'
What I'm looking for is a way to square a_dev
and then set the solver to optimize the variables to minimize that squared difference.
import pandas as pd
import numpy as np
import pulp
def contrib(p, col):
c = df.loc[p, col]
return c
df_data = {'A':np.random.randint(20, 50, 50),
'B':np.random.randint(0, 50, 50),
'C':np.random.randint(20, 50, 50),
'D':np.random.randint(20, 100, 50)}
df = pd.DataFrame(data=df_data)
picks = df.index
#Set up variable
pct = pulp.LpVariable.dicts('Pct', (p for p in picks), 0, 0.05)
#Create problem
ideal = pulp.LpProblem('Sq_dev', pulp.LpMinimize)
tgt_a = 35
a = [pct[p] * contrib(p, 'A') for p in picks]
a_tgt = [pct[p] * tgt_a for p in picks]
a_dev = (pulp.lpSum(a) - pulp.lpSum(a_tgt))
#I need a_dev to be squared in order to be useful!
ideal += a_dev
ideal += pulp.lpSum([pct[p] for p in picks]) == 1
ideal.solve()
for p in picks:
if pct[p].value() > 0:
print(p, pct[p].value())