Reputation: 105
I am new in python and have output of simple LP problem.
In this problem, several PART's make a House and several house make a society. There are house and society level target on delivery. If the delivery is not met at any level, poor Part is replaced (replaced = Y) with part delivering 50 units.
Solution is optimized but, we don't have the capacity to replace. So, I want to prioritize replacement.
Ex: I have capacity to do 3 replacement and solution is giving 7 replacement.
Can we postprocess the solution to get the 3 replacement based on priority.
given = 3 replacement max priority = S3 (society 3), H2, H1, S2.
My output would be replacement at U, R and A, leaving other as it is? is it possible to do in python? or this can't be done in python (In that case, I can use an excel macro).
Edit
Raw data:
data = [
{'Part': 'A', 'House': 'H1', 'Society': 'S1', 'Present_Delivery': 10, 'Replaced': 'Y'},
{'Part': 'B', 'House': 'H1', 'Society': 'S1', 'Present_Delivery': 30, 'Replaced': ''},
{'Part': 'C', 'House': 'H1', 'Society': 'S1', 'Present_Delivery': 40, 'Replaced': ''},
{'Part': 'D', 'House': 'H1', 'Society': 'S1', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'E', 'House': 'H2', 'Society': 'S1', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'F', 'House': 'H2', 'Society': 'S1', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'G', 'House': 'H2', 'Society': 'S1', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'H', 'House': 'H2', 'Society': 'S1', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'I', 'House': 'H3', 'Society': 'S2', 'Present_Delivery': 30, 'Replaced': 'Y'},
{'Part': 'J', 'House': 'H3', 'Society': 'S2', 'Present_Delivery': 40, 'Replaced': ''},
{'Part': 'K', 'House': 'H3', 'Society': 'S2', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'L', 'House': 'H4', 'Society': 'S2', 'Present_Delivery': 30, 'Replaced': 'Y'},
{'Part': 'M', 'House': 'H4', 'Society': 'S2', 'Present_Delivery': 30, 'Replaced': 'Y'},
{'Part': 'N', 'House': 'H4', 'Society': 'S2', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'O', 'House': 'H5', 'Society': 'S2', 'Present_Delivery': 20, 'Replaced': 'Y'},
{'Part': 'P', 'House': 'H5', 'Society': 'S2', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'Q', 'House': 'H5', 'Society': 'S2', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'R', 'House': 'H6', 'Society': 'S3', 'Present_Delivery': 20, 'Replaced': 'Y'},
{'Part': 'S', 'House': 'H6', 'Society': 'S3', 'Present_Delivery': 40, 'Replaced': ''},
{'Part': 'T', 'House': 'H6', 'Society': 'S3', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'U', 'House': 'H7', 'Society': 'S3', 'Present_Delivery': 15, 'Replaced': 'Y'},
{'Part': 'V', 'House': 'H7', 'Society': 'S3', 'Present_Delivery': 40, 'Replaced': ''},
{'Part': 'W', 'House': 'H7', 'Society': 'S3', 'Present_Delivery': 50, 'Replaced': ''},
]
house_targets = {'H1': 140,
'H2': 160,
'H3': 120,
'H4': 110,
'H5': 120,
'H6': 115,
'H7': 105,
}
society_targets = {'S1': 330,
'S2': 500,
'S3': 250}
df = pd.DataFrame(data)
for house, target in house_targets.items():
df.loc[df['House'] == house, 'House_Target'] = target
for society, target in society_targets.items():
df.loc[df['Society'] == society, 'Society_Target'] = target
replacement_value = 50
df.loc[df['Replaced'] == 'Y', 'replacement_value'] = replacement_value - df['Present_Delivery']
df['replacement_value'].fillna(0, inplace=True)
Upvotes: 2
Views: 309
Reputation: 1909
This can be implemented using join
, combine_first
and sort
:
priority = ["S3", "H2", "H1", "S2"]
priority = pd.Series(range(len(priority)), index=priority, name="priority")
df["priority"] = df.join(priority, on="Society").priority.combine_first(df.join(priority, on="House").priority)
result = df[df.replacement_value > 0] .sort_values("priority").head(3)
print(result)
Result:
Part House Society Present_Delivery Replaced House_Target Society_Target replacement_value priority
17 R H6 S3 20 Y 115.0 250.0 30.0 0.0
20 U H7 S3 15 Y 105.0 250.0 35.0 0.0
0 A H1 S1 10 Y 140.0 330.0 40.0 2.0
Upvotes: 0
Reputation: 3939
In pandas the solution is straight forward. You just need to slice the right column with the given priority and sort it. Most of the code is just boiler plate for the wrapper.
import pandas as pd
class ReplacementConstraint:
def __init__(self, df: pd.DataFrame, *, max_replacements: int, priority: list):
assert isinstance(df, pd.DataFrame)
self.df = df
self.max_replacements = max_replacements
self.priority = priority
self.result = pd.DataFrame()
@staticmethod
def parse_priority(prio_str):
"""Mapping priority String to column"""
col_map = {'H': 'House',
'S': 'Society'}
return col_map[prio_str[0]]
def calculate(self):
"""Sort slices of dataframe with respect to priorities and append to self.result"""
for prio in self.priority:
col = self.parse_priority(prio)
mask = (self.df['Replaced'] == 'Y') & (self.df[col] == prio)
result_tmp = self.df[mask].sort_values('replacement_value', ascending=False)
self.result = pd.concat([self.result, result_tmp])
self.result = self.result.iloc[:self.max_replacements]
Given a dataframe df
(see below) you can use the wrapper as:
wrapper = ReplacementConstraint(df, max_replacements=3, priority=['S3', 'H2', 'H1', 'S2'])
wrapper.calculate()
print(wrapper.result)
The solution looks like:
Part House Society ... House_Target Society_Target replacement_value
20 U H7 S3 ... 105.0 250.0 35.0
17 R H6 S3 ... 115.0 250.0 30.0
0 A H1 S1 ... 140.0 330.0 40.0
The typing of the dataframe data took most of my time. Please consider posting text not an image the next time. I post it here so if someone else wants to post another solution, she doesn't need to type it again. Also, by posting the dataframe my solution is reproducible.
data = [
{'Part': 'A', 'House': 'H1', 'Society': 'S1', 'Present_Delivery': 10, 'Replaced': 'Y'},
{'Part': 'B', 'House': 'H1', 'Society': 'S1', 'Present_Delivery': 30, 'Replaced': ''},
{'Part': 'C', 'House': 'H1', 'Society': 'S1', 'Present_Delivery': 40, 'Replaced': ''},
{'Part': 'D', 'House': 'H1', 'Society': 'S1', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'E', 'House': 'H2', 'Society': 'S1', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'F', 'House': 'H2', 'Society': 'S1', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'G', 'House': 'H2', 'Society': 'S1', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'H', 'House': 'H2', 'Society': 'S1', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'I', 'House': 'H3', 'Society': 'S2', 'Present_Delivery': 30, 'Replaced': 'Y'},
{'Part': 'J', 'House': 'H3', 'Society': 'S2', 'Present_Delivery': 40, 'Replaced': ''},
{'Part': 'K', 'House': 'H3', 'Society': 'S2', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'L', 'House': 'H4', 'Society': 'S2', 'Present_Delivery': 30, 'Replaced': 'Y'},
{'Part': 'M', 'House': 'H4', 'Society': 'S2', 'Present_Delivery': 30, 'Replaced': 'Y'},
{'Part': 'N', 'House': 'H4', 'Society': 'S2', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'O', 'House': 'H5', 'Society': 'S2', 'Present_Delivery': 20, 'Replaced': 'Y'},
{'Part': 'P', 'House': 'H5', 'Society': 'S2', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'Q', 'House': 'H5', 'Society': 'S2', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'R', 'House': 'H6', 'Society': 'S3', 'Present_Delivery': 20, 'Replaced': 'Y'},
{'Part': 'S', 'House': 'H6', 'Society': 'S3', 'Present_Delivery': 40, 'Replaced': ''},
{'Part': 'T', 'House': 'H6', 'Society': 'S3', 'Present_Delivery': 50, 'Replaced': ''},
{'Part': 'U', 'House': 'H7', 'Society': 'S3', 'Present_Delivery': 15, 'Replaced': 'Y'},
{'Part': 'V', 'House': 'H7', 'Society': 'S3', 'Present_Delivery': 40, 'Replaced': ''},
{'Part': 'W', 'House': 'H7', 'Society': 'S3', 'Present_Delivery': 50, 'Replaced': ''},
]
house_targets = {'H1': 140,
'H2': 160,
'H3': 120,
'H4': 110,
'H5': 120,
'H6': 115,
'H7': 105,
}
society_targets = {'S1': 330,
'S2': 500,
'S3': 250}
df = pd.DataFrame(data)
for house, target in house_targets.items():
df.loc[df['House'] == house, 'House_Target'] = target
for society, target in society_targets.items():
df.loc[df['Society'] == society, 'Society_Target'] = target
replacement_value = 50
df.loc[df['Replaced'] == 'Y', 'replacement_value'] = replacement_value - df['Present_Delivery']
df['replacement_value'].fillna(0, inplace=True)
Upvotes: 1