Набор всех комбинаций векторов в Python

У меня проблема с созданием того, что можно рассматривать как декартово произведение массива векторов в Python. У меня есть код, который дает все возможные разделы числа n над переменными r и возвращает его в виде массива numpy. Что я хотел бы сделать, так это иметь возможность вызывать этот код произвольное количество раз, а затем создавать набор всех возможных комбинаций массивов.

Итак, чтобы привести пример, я мог бы назвать код раздела и каждый последующий вызов (для переменного набора параметров)

array([[2,0],[1,1],[2,0]])
array([[1,0],[0,1]])
array([[0,0]])

Я ищу, чтобы иметь возможность вернуть набор

array([[2,0],[1,0],[0,0]])
array([[2,0],[0,1],[0,0]])
array([[1,1],[1,0],[0,0]])
.....

либо в виде общего массива, либо возвращая его построчно (из-за очевидных проблем с памятью по мере роста размера разделяемого числа).

Раньше я решал эту проблему с помощью itertools.product и запускал код под PyPy. Однако мне пришлось переключиться с PyPy на стандартный python из-за необходимости Numpy в других частях проекта, и я пытаюсь воспроизвести скорость кода PyPy с помощью Numpy. Мне удалось заставить это работать очень грубо, но код потратил так много времени на переход между типами данных, чтобы попытаться загрузить решение вместе, что это нецелесообразно для реализации.

Мне было интересно, сможет ли кто-нибудь помочь мне, предоставив небольшое руководство относительно того, как я должен продвигаться с этим в Python.

Спасибо


person user2745293    schedule 05.09.2013    source источник
comment
Вы создаете внешний продукт, используя команды numpy? Можете ли вы предоставить код?   -  person Codie CodeMonkey    schedule 05.09.2013
comment
Вы имеете в виду код разбиения, который сгенерировал массив([[2,0],[1,1],[2,0]]) массив([[1,0],[0,1]]) массив([ [0,0]])   -  person user2745293    schedule 05.09.2013


Ответы (1)


Это должно помочь вам начать:

import numpy as np
import itertools as it

def row_product(*arrays):
    lengths = np.array([x.shape[0] for x in arrays])
    positions = np.cumsum(lengths)

    ranges = np.arange(positions[-1])
    ranges = np.split(ranges,positions[:-1])

    total = np.concatenate((arrays),axis=0)

    inds = np.fromiter(it.chain.from_iterable(it.product(*ranges)), np.int)
    inds = inds.reshape(-1, len(arrays))

    return np.take(total, inds, axis=0)

Последние размеры должны быть одинаковыми.

Отображение результатов:

a=np.array([[2,0],[1,1],[2,0]])
b=np.array([[1,0],[0,1]])
c=np.array([[0,0]])

print row_product(a,b,c)

[[[2 0]
  [1 0]
  [0 0]]

 [[2 0]
  [0 1]
  [0 0]]

 [[1 1]
  [1 0]
  [0 0]]

 [[1 1]
  [0 1]
  [0 0]]

 [[2 0]
  [1 0]
  [0 0]]

 [[2 0]
  [0 1]
  [0 0]]]

Это трехмерный массив, в котором уникальные комбинации находятся на двух последних осях. Кажется, это достаточно быстро, 1 миллион уникальных комбинаций занимает около 1/6 секунды.

person Daniel    schedule 05.09.2013
comment
Спасибо тебе за это! Однако у меня возникла одна проблема: как вызвать это для произвольного набора входных аргументов. Например, я пытался вызвать row_product([compositions(i,2) for i in xrange(4)]) или row_product(row_product(a,b),c), но ни один из них не вызывается. Вероятно, это глупый вопрос, но как лучше всего передать n массивов в row_product? - person user2745293; 06.09.2013
comment
Если вы хотите передать контейнер row_product, измените row_product(*arrays) на row_product(arrays) и np.concatenate((arrays),axis=0) на np.concatenate(arrays,axis=0). - person Daniel; 06.09.2013
comment
Большое спасибо за вашу помощь с этим Ophion. Я решал эту проблему (или более крупную проблему, которая в любом случае включает это) в течение нескольких недель, и я очень ценю ваше время на это. - person user2745293; 06.09.2013
comment
Если этот ответ содержит нужную вам информацию, рассмотрите возможность ее принятия. - person Daniel; 06.09.2013