Python Условное перечисление с заменой - PullRequest
0 голосов
/ 17 июня 2020

У меня есть фрейм данных под названием 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))

Что мне не хватает?

1 Ответ

1 голос
/ 18 июня 2020

Думаю, вы могли бы сделать что-то вроде этого - получить комбинации индексов строк, для каждой комбинации строк найти сумму емкости и отфильтровать их на основе условия

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]

Может быть, есть лучшее решение для более высоких значений, но это должно работать с образцом данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...