Python / Pandas получает все возможные комбинации с одним ограничением - PullRequest
0 голосов
/ 17 сентября 2018

Цель - у меня всего 50 записей, и мне нужно найти все возможные комбинации 6 игроков с зарплатой <= 50 000 и> = 48 000.

Код ниже будет работать, если я использую только около 20записи, но я продолжаю сталкиваться с ошибками памяти при попытке применить его ко всем 50 записям.Я ищу способ оптимизировать мой код, чтобы он принимал только комбинации менее 50 Кб без циклов, как я, если это возможно.

Пример данных (в настоящее время насчитывается 50 записей) -

    ID          Salary
0   11282489    11000
1   11282517    10800
2   11282479    10700
3   11282521    10200
4   11282483    10100
5   11282481    10000

Текущий код -

comb = combinations(data['ID'], 6) 
comb_list = list(comb)
df_list = []
for i in comb_list:
    i = list(i)
    if data.loc[data['ID'].isin(i)]['Salary'].sum() <= 50000 and data.loc[data['ID'].isin(i)]['Salary'].sum() >= 48000:
        df_list.append(data.loc[data['ID'].isin(i)])

    counter +=1

«Comb_list» в настоящее время заканчивается около 15M комбинаций, что является основной проблемой.Есть ли лучший способ применить фильтр зарплаты, чем я сейчас?

Спасибо!

1 Ответ

0 голосов
/ 17 сентября 2018

Вы, конечно, можете избежать цикла.

Найдите все комбинации, сопоставьте их идентификаторы с зарплатой, а затем рассчитайте сумму для каждой комбинации.Затем просто поднабор тех комбинаций, где зарплата составляет от 48 000 до 50 000

Настройка

import pandas as pd
import numpy as np
from itertools import combinations

np.random.seed(123)
df = pd.DataFrame({'ID': np.arange(1,51,1),
                   'Salary': np.random.randint(7000,12000,50)})
# ID to Salary dictionary
d = df.set_index('ID').Salary.to_dict()

Код

n = 6  # length of combination tuples

# Create df of people and their salary
df2 = pd.DataFrame(list(combinations(df.ID, n)), 
                   columns=['p'+str(i) for i in np.arange(1,n+1,1)])
df2 = pd.concat([df2, df2.replace(d).add_suffix('_salary')], axis=1)

# Subset to those within the range you care about
df2[df2[[col for col in df2.columns if '_salary' in col]].sum(1).between(48000,50000)]

Вывод

        p1  p2  p3  p4  p5  p6  p1_salary  p2_salary  p3_salary  p4_salary  p5_salary  p6_salary
48465    1   2   6  10  19  32      10582      10454       7096       7111       7039       7588
48481    1   2   6  10  19  48      10582      10454       7096       7111       7039       7371
209845   1   3   5   6   9  10      10582       8346       8593       7096       7942       7111
209854   1   3   5   6   9  19      10582       8346       8593       7096       7942       7039
209883   1   3   5   6   9  48      10582       8346       8593       7096       7942       7371
...

(Есть 188 531 таких комбинаций).Должны быть еще более эффективные решения.

...