python中的分配包装器

问题描述 投票:1回答:1

我是python新手,有一个简单LP问题的输出。

As shown

在这个问题中,几个PART's组成一个House,几个House组成一个society。有房子和社会层面的交付目标。如果在任何一个级别上没有达到交付目标,那么差的部分将被替换(替换=Y)为交付50个单位的部分。

解决方案是最优化的,但是,我们没有能力替换,所以,我想优先替换。

例如:我有能力进行3次替换,而解决方案给出了7次替换。

我们能否根据优先级对解决方案进行后处理,以获得3个替换。

给定=3个替换maxpriority=S3(社会3),H2,H1,S2。

我的输出是在U,R和A处进行替换,其他的保持原样,这在python中可以做到吗,还是说在python中做不到(这样的话,我可以用excel宏)。

编辑

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)
python pandas linear-programming
1个回答
1
投票

在pandas中,解决方案是直接的。你只需要把给定优先级的右列切开,然后排序就可以了。大部分代码只是包装器的锅炉板。

包装器

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]

给定一个数据帧 df (见下图)你可以将包装器作为。

    wrapper = ReplacementConstraint(df, max_replacements=3, priority=['S3', 'H2', 'H1', 'S2'])
    wrapper.calculate()
    print(wrapper.result)

该解决方案看起来像:

   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

原始数据

数据框数据的输入花了我大部分时间。下次请考虑发文字而不是图片。我把它贴在这里,所以如果别人想贴另一个解决方案,她不需要再打一次。此外,通过发布数据框架,我的解决方案是 重现性.

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)

可能的改进

  • 包装器不检查目标值。我认为由于第一次优化,这将是不相关的。
  • 由此产生的数据框架并没有修正交付的值。这没什么大不了的。我只是想提供一个最小的例子。你可以根据自己的需要改进包装器。

0
投票

这可以通过使用 join, combine_firstsort:

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)

结果:

   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
© www.soinside.com 2019 - 2024. All rights reserved.