Извлечение комбинаций из массива numpy, который суммирует до желаемого результата

1

Я хотел бы вернуть массив или индекс того, который содержит, какие комбинации членов в массиве NumPy суммируют к определенному числу.

Например, если я возьму этот массив и захочу найти все комбинации его членов, сумма которых равна 7:

import numpy as np

example = np.arange(4) + 1

example
>>> array([1, 2, 3, 4])

это вернуло бы:

somefunction
>>> [[1,2,4], [3,4]]

или индекс:

>>> [[0,1,2], [2,3]]

Я могу представить себе подход с использованием itertools.combinations, хотя я бы хотел этого избежать, потому что в наборе данных, на котором я пытаюсь это использовать, уже есть ~ 30 000 участников. Он не работает достаточно быстро при рассмотрении каждой длины комбинаций.

Есть ли более быстрый способ сделать это?

Изменение: Для получения дополнительной информации мне не обязательно использовать каждую комбинацию из 30 000 членов. Например, я суммирую целые числа до ~ 1000, поэтому мне нужно <1000 составляющих - в моем случае конечное число составляющих списка, вероятно, будет состоять из 100-400 составляющих.

  • 1
    Вы можете отсортировать массив?
  • 0
    Похоже, проблема смены монет DP.
Показать ещё 5 комментариев
Теги:
numpy

2 ответа

1

Расширенный комментарий, а не ответ. В зависимости от структуры ваших данных перечисление всех комбинаций элементов с заданной суммой может оказаться невозможным. Однако существует эффективный способ подсчета количества комбинаций. Затем вы можете решить, хотите ли вы попробовать перечислить все.

Например, с 10k случайных целых чисел от 0 до 10 я нашел 243905016604941663446994 подмножеств, которые составляют 10 - это 24-значное число. Если бы вы могли перечислить комбинацию каждую наносекунду, это заняло бы более 7 миллионов лет. Число для массива из 30 тысяч случайных чисел, суммирующих до 1000 должно быть значительно больше.

Фрагмент кода для подсчета комбинаций, суммирующих в число.

import numpy as np
import sys

example = np.arange(4) + 1
example_target = 7

# assuming all elemenst of arr are positive integers
def count_combs(arr, sum_):
    arr = np.sort(arr)

    sys.setrecursionlimit(100_000)
    state_dict = {}

    def state(i, j):
        if (i, j) in state_dict:
            return state_dict[(i, j)]
        elif j < 0:
            res = 0
        elif j == 0:
            res = 1
        elif i == 0:
            res = 1 if j == arr[i] else 0
        else:
            res = state(i - 1, j - arr[i]) + state(i - 1, j)
        state_dict[(i, j)] = res
        return res

    return state(arr.shape[0] - 1, sum_)


# print(count_combs(example, example_target))
# prints 2

test_big = np.random.randint(0, 10, size=10000)
test_target = 10


def test():
    print(count_combs(test_big, test_target))


if __name__ == "__main__":
    test()
    # e.g. 258364297793668558120414
  • 1
    Это было очень полезно. Я не верю, что есть хороший ответ на вопрос, спасибо за понимание!
1

Вы можете использовать, если вы не возражаете, itertools.combinations:

print([x for i in range(1,4) for x in itertools.combinations(example,i) if sum(x)==7])

Выход:

[(3, 4), (1, 2, 4)]

Сортировать, если вы хотите заказ, который вы хотите:

print(sorted([x for i in range(1,4) for x in itertools.combinations(example,i) if sum(x)==7]))

Выход:

[(1, 2, 4), (3, 4)]

Как вы говорите, itertools.combinations будет медленным, но на самом деле не существует другого, более эффективного способа, чем itertools.combinations tho.

  • 1
    ОП упомянул, что его исходный массив состоит из 30 тыс. Элементов. Это попытается проверить каждое подмножество, может занять некоторое время :)
  • 1
    Заявлено, это не было оптимальным в вопросе.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню