Думаю, вы могли бы сделать что-то вроде этого - получить комбинации индексов строк, для каждой комбинации строк найти сумму емкости и отфильтровать их на основе условия
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
также должно быть на go выше, чтобы соответствовать всем комбинациям. Диапазон 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]
Может быть, есть лучшее решение для более высоких значений, но это должно работать с образцом данных.