Python 带替换的条件枚举

Python Conditional Enumeration with Replacement

我有一个名为 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))

我错过了什么?

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

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 中所有索引与 0 to n 中的 i 个元素的组合。因此,使用 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]

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