首页 > 解决方案 > 带替换的 Python 条件枚举

问题描述

我有一个名为fleet_df的数据框,如下所示:

Vehicle_ID     Capacity
001            5
002            6
003            10

我还有一个变量total_demand

total_demand = 55

我想要的是枚举所有更换车辆的组合,只要 Total_Capacity 的总和大于或等于 total_volume 且小于或等于 total_volume 的两倍。

示例输出:

Scenario     Vehicle_IDs                           Total_Capacity
1            001, 001, 001, 003, 003, 003, 003     55
2            003, 003, 003, 003, 003, 003, 003     70
...

我认为这样的事情会起作用,但到目前为止还没有运气:

enumerate(i for i in fleet_df['Capacity'].values.tolist() if (total_demand <= i) and (i <= total_demand * 2))

我错过了什么?

标签: pythonpandasconditional-statementsenumeration

解决方案


我认为你也许可以做这样的事情 - 获取行索引的组合,为每个行组合找到容量总和并根据条件过滤它们

fleet_df = pd.DataFrame({'Vehicle_ID': ['001', '002', '003'],
                         'Capacity': [5, 6, 10]})
# Set the index as 'Vehicle_ID'
fleet_df.set_index(['Vehicle_ID'], inplace=True)
total_demand = 55
n = 10
final_df = pd.DataFrame([])

for i in range(1, n):
    comb_indices = list(comb for comb in itertools.combinations_with_replacement(fleet_df.index, r=i))
    comb_rows = pd.DataFrame([fleet_df.loc[comb, 'Capacity'].sum() for comb in comb_indices],
                             index=comb_indices, columns=['Total Capacity'])
    final_df = final_df.append(comb_rows[(comb_rows['Total Capacity'] >= total_demand) & (comb_rows['Total Capacity'] <= 2*total_demand)])


final_df = final_df.rename_axis('Vehicle_IDs').reset_index().rename_axis('Scenarios')
print(final_df)

解释:

线

list(comb for comb in itertools.combinations_with_replacement(fleet_df.index, r=i))

将为您提供所有索引的组合,fleet_df其中的i元素来自0 to n. 因此,与i=2您将comb_indices拥有

[('001', '001'), ('001', '002'), ('001', '003'), ('002', '002'), ('002', '003'), ('003', '003')]

comb_rows接下来,使用与组合中的索引匹配的行创建一个临时数据框comb_indices

comb_rows = pd.DataFrame([fleet_df.loc[comb, 'Capacity'].sum() for comb in comb_indices], index=comb_indices, columns=['Total Capacity'])

最后,将总容量满足所需总需求的匹配行追加到final_df

comb_rows[(comb_rows['Total Capacity'] >= total_demand) & (comb_rows['Total Capacity'] <= 2*total_demand)]

一旦你有final_df你想要的重命名索引。

这里的值n是每个组合中元素的数量。当n增加时,我不知道这将是一个有效的解决方案。并且n取决于值total_demand控制的重复可能有无限的可能性total_demand。由于total_demand价值增加的方式超过车辆的单个容量,价值也n应该更高,以满足所有组合。的范围n可以限定total_demand/max(capacity)(2*total demand)/min(capacity)。我认为您应该在其中获得所有匹配的组合。所以,在这种情况下,你的范围n将是

min_comb = int(total_demand/max(fleet_df['Capacity'].to_list()))
max_comb = int((2*total_demand)/min(fleet_df['Capacity'].to_list()))
for i in range(min_comb, max_comb+1):
    ...
    ...

最后结果:

                                             Vehicle_IDs  Total Capacity
Scenarios                                                               
0                         (001, 003, 003, 003, 003, 003)              55
1                         (002, 003, 003, 003, 003, 003)              56
2                         (003, 003, 003, 003, 003, 003)              60
3                    (001, 001, 001, 003, 003, 003, 003)              55
4                    (001, 001, 002, 003, 003, 003, 003)              56
...                                                  ...             ...
71         (002, 002, 002, 002, 003, 003, 003, 003, 003)              74
72         (002, 002, 002, 003, 003, 003, 003, 003, 003)              78
73         (002, 002, 003, 003, 003, 003, 003, 003, 003)              82
74         (002, 003, 003, 003, 003, 003, 003, 003, 003)              86
75         (003, 003, 003, 003, 003, 003, 003, 003, 003)              90
...                                                      ...         ...
828        (001, 001, 001, 001, 001, 001, 001, 001, 001, ...         107
829        (001, 001, 001, 001, 001, 001, 001, 001, 001, ...         108
830        (001, 001, 001, 001, 001, 001, 001, 001, 001, ...         109
831        (001, 001, 001, 001, 001, 001, 001, 001, 001, ...         110
832        (001, 001, 001, 001, 001, 001, 001, 001, 001, ...         110

[833 rows x 2 columns]

对于更高的值可能有更好的解决方案,但这应该适用于样本数据集。


推荐阅读