Using NumPy to build an array of all combinations of two arrays
Использование NumPy для построения массива из всех комбинаций двух массивов
Я пытаюсь пробежаться по пространству параметров шестипараметрической функции, чтобы изучить ее числовое поведение, прежде чем пытаться сделать с ней что-либо сложное, поэтому я ищу эффективный способ сделать это.
Моя функция принимает значения с плавающей запятой, заданные в 6-значном массиве NumPy, в качестве входных данных. Изначально я пытался сделать следующее:
Сначала я создал функцию, которая принимает два массива и генерирует массив со всеми комбинациями значений из двух массивов:
from numpy import *
defcomb(a, b): c = [] for i in a: for j in b: c.append(r_[i,j]) return c
Затем я использовал reduce(), чтобы применить это к m копиям одного и того же массива:
defcombs(a, m): return reduce(comb, [a]*m)
Наконец, я оцениваю свою функцию следующим образом:
values = combs(np.arange(0, 1, 0.1), 6) for val in values: print F(val)
Это работает, но это путь слишком медленно. Я знаю, что пространство параметров огромно, но это не должно быть таким медленным. В этом примере я отобрал только 106 (миллион) точек, и только на создание массива ушло более 15 секунд values.
Есть ли более эффективный способ сделать это с помощью NumPy?
Я могу изменить способ, которым функция F принимает свои аргументы, если это необходимо.
Переведено автоматически
Ответ 1
В более новых версиях NumPy (>1.8.x), numpy.meshgrid() обеспечивает гораздо более быструю реализацию:
arrays = [np.asarray(x) for x in arrays] dtype = arrays[0].dtype
n = np.prod([x.size for x in arrays]) if out isNone: out = np.zeros([n, len(arrays)], dtype=dtype)
#m = n / arrays[0].size m = int(n / arrays[0].size) out[:,0] = np.repeat(arrays[0], m) if arrays[1:]: cartesian(arrays[1:], out=out[0:m, 1:]) for j inrange(1, arrays[0].size): #for j in xrange(1, arrays[0].size): out[j*m:(j+1)*m, 1:] = out[0:m, 1:] return out
Python 2:
import numpy as np
defcartesian(arrays, out=None): arrays = [np.asarray(x) for x in arrays] dtype = arrays[0].dtype
n = np.prod([x.size for x in arrays]) if out isNone: out = np.zeros([n, len(arrays)], dtype=dtype)
m = n / arrays[0].size out[:,0] = np.repeat(arrays[0], m) if arrays[1:]: cartesian(arrays[1:], out=out[0:m, 1:]) for j in xrange(1, arrays[0].size): out[j*m:(j+1)*m, 1:] = out[0:m, 1:] return out
Ответ 3
itertools.combinations - это, как правило, самый быстрый способ получения комбинаций из контейнера Python (если вам действительно нужны комбинации, т. Е. Расположения без повторений и независимо от порядка; похоже, что ваш код этого не делает, но я не могу сказать, потому ли это, что ваш код глючит или потому, что вы используете неправильную терминологию).
Если вам нужно что-то отличное от комбинаций, возможно, вам лучше подойдут другие итераторы в itertools, product или permutations. Например, похоже, что ваш код примерно такой же, как:
for val in itertools.product(np.arange(0, 1, 0.1), repeat=6): print F(val)
Все эти итераторы выдают кортежи, а не списки или массивы NumPy, поэтому, если ваш F придирчив к получению именно массива NumPy, вам придется смириться с дополнительными накладными расходами на построение или очистку и повторное заполнение одного массива на каждом шаге.
Ответ 4
Вы можете использовать np.array(itertools.product(a, b)).