Я пытаюсь пробежаться по пространству параметров функции с 6 параметрами, чтобы изучить ее числовое поведение, прежде чем пытаться сделать с ней что-нибудь сложное, поэтому я ищу эффективный способ сделать это.
Моя функция принимает на вход значения с плавающей запятой, заданный 6-тусклым массивом numpy. Первоначально я пытался сделать следующее:
Сначала я создал функцию, которая принимает 2 массива и генерирует массив со всеми комбинациями значений из двух массивов.
from numpy import *
def comb(a,b):
c = []
for i in a:
for j in b:
c.append(r_[i,j])
return c
Затем я reduce()
применил это к m копиям одного и того же массива:
def combs(a,m):
return reduce(comb,[a]*m)
А затем я оцениваю свою функцию так:
values = combs(np.arange(0,1,0.1),6)
for val in values:
print F(val)
Это работает, но слишком медленно. Я знаю, что пространство параметров огромно, но это не должно быть так медленно. В этом примере я отобрал только 10 6 (миллион) точек, и на создание массива ушло более 15 секунд values
.
Знаете ли вы более эффективный способ сделать это с помощью numpy?
При необходимости я могу изменить способ получения F
аргументов функцией .
источник
Ответы:
В более новой версии
numpy
(> 1.8.x)numpy.meshgrid()
обеспечивает более быструю реализацию:решение @ pv
In [113]: %timeit cartesian(([1, 2, 3], [4, 5], [6, 7])) 10000 loops, best of 3: 135 µs per loop In [114]: cartesian(([1, 2, 3], [4, 5], [6, 7])) Out[114]: array([[1, 4, 6], [1, 4, 7], [1, 5, 6], [1, 5, 7], [2, 4, 6], [2, 4, 7], [2, 5, 6], [2, 5, 7], [3, 4, 6], [3, 4, 7], [3, 5, 6], [3, 5, 7]])
numpy.meshgrid()
раньше был только 2D, теперь он поддерживает ND. В этом случае 3D:In [115]: %timeit np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3) 10000 loops, best of 3: 74.1 µs per loop In [116]: np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3) Out[116]: array([[1, 4, 6], [1, 5, 6], [2, 4, 6], [2, 5, 6], [3, 4, 6], [3, 5, 6], [1, 4, 7], [1, 5, 7], [2, 4, 7], [2, 5, 7], [3, 4, 7], [3, 5, 7]])
Обратите внимание, что порядок конечного результата немного отличается.
источник
np.stack(np.meshgrid([1, 2, 3], [4, 5], [6, 7]), -1).reshape(-1, 3)
отдадим правильный приказВот чистая реализация. Это примерно в 5 раз быстрее, чем при использовании itertools.
import numpy as np def cartesian(arrays, out=None): """ Generate a cartesian product of input arrays. Parameters ---------- arrays : list of array-like 1-D arrays to form the cartesian product of. out : ndarray Array to place the cartesian product in. Returns ------- out : ndarray 2-D array of shape (M, len(arrays)) containing cartesian products formed of input arrays. Examples -------- >>> cartesian(([1, 2, 3], [4, 5], [6, 7])) array([[1, 4, 6], [1, 4, 7], [1, 5, 6], [1, 5, 7], [2, 4, 6], [2, 4, 7], [2, 5, 6], [2, 5, 7], [3, 4, 6], [3, 4, 7], [3, 5, 6], [3, 5, 7]]) """ arrays = [np.asarray(x) for x in arrays] dtype = arrays[0].dtype n = np.prod([x.size for x in arrays]) if out is None: 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
источник
from sklearn.utils.extmath import cartesian
TypeError: slice indices must be integers or None or have an __index__ method
брошеноcartesian(arrays[1:], out=out[0:m,1:])
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, вам придется принять дополнительные накладные расходы на создание или очистку и повторное заполнение одного на каждом шаге.
источник
Вы можете сделать что-то вроде этого
import numpy as np def cartesian_coord(*arrays): grid = np.meshgrid(*arrays) coord_list = [entry.ravel() for entry in grid] points = np.vstack(coord_list).T return points a = np.arange(4) # fake data print(cartesian_coord(*6*[a])
который дает
array([[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 2], ..., [3, 3, 3, 3, 3, 1], [3, 3, 3, 3, 3, 2], [3, 3, 3, 3, 3, 3]])
источник
Следующая реализация numpy должна быть прибл. В 2 раза быстрее полученного ответа:
def cartesian2(arrays): arrays = [np.asarray(a) for a in arrays] shape = (len(x) for x in arrays) ix = np.indices(shape, dtype=int) ix = ix.reshape(len(arrays), -1).T for n, arr in enumerate(arrays): ix[:, n] = arrays[n][ix[:, n]] return ix
источник
np.indices((n,...,n)).reshape(k,-1).T
подойдет.Похоже, вы хотите, чтобы сетка оценивала вашу функцию, и в этом случае вы можете использовать
numpy.ogrid
(open) илиnumpy.mgrid
(fleshed out):import numpy my_grid = numpy.mgrid[[slice(0,1,0.1)]*6]
источник
ты можешь использовать
np.array(itertools.product(a, b))
источник
Вот еще один способ, использующий чистый NumPy, без рекурсии, без понимания списка и без явных циклов for. Это примерно на 20% медленнее, чем исходный ответ, и он основан на np.meshgrid.
def cartesian(*arrays): mesh = np.meshgrid(*arrays) # standard numpy meshgrid dim = len(mesh) # number of dimensions elements = mesh[0].size # number of elements, any index will do flat = np.concatenate(mesh).ravel() # flatten the whole meshgrid reshape = np.reshape(flat, (dim, elements)).T # reshape and transpose return reshape
Например,
x = np.arange(3) a = cartesian(x, x, x, x, x) print(a)
дает
[[0 0 0 0 0] [0 0 0 0 1] [0 0 0 0 2] ..., [2 2 2 2 0] [2 2 2 2 1] [2 2 2 2 2]]
источник
Для чистой numpy реализации декартова произведения одномерных массивов (или плоских списков Python) просто используйте
meshgrid()
, прокрутите оси с помощьюtranspose()
и измените форму до желаемого вывода:def cartprod(*arrays): N = len(arrays) return transpose(meshgrid(*arrays, indexing='ij'), roll(arange(N + 1), -1)).reshape(-1, N)
Обратите внимание, что это имеет соглашение о том, что последняя ось меняется быстрее всего («стиль C» или «основная строка»).
In [88]: cartprod([1,2,3], [4,8], [100, 200, 300, 400], [-5, -4]) Out[88]: array([[ 1, 4, 100, -5], [ 1, 4, 100, -4], [ 1, 4, 200, -5], [ 1, 4, 200, -4], [ 1, 4, 300, -5], [ 1, 4, 300, -4], [ 1, 4, 400, -5], [ 1, 4, 400, -4], [ 1, 8, 100, -5], [ 1, 8, 100, -4], [ 1, 8, 200, -5], [ 1, 8, 200, -4], [ 1, 8, 300, -5], [ 1, 8, 300, -4], [ 1, 8, 400, -5], [ 1, 8, 400, -4], [ 2, 4, 100, -5], [ 2, 4, 100, -4], [ 2, 4, 200, -5], [ 2, 4, 200, -4], [ 2, 4, 300, -5], [ 2, 4, 300, -4], [ 2, 4, 400, -5], [ 2, 4, 400, -4], [ 2, 8, 100, -5], [ 2, 8, 100, -4], [ 2, 8, 200, -5], [ 2, 8, 200, -4], [ 2, 8, 300, -5], [ 2, 8, 300, -4], [ 2, 8, 400, -5], [ 2, 8, 400, -4], [ 3, 4, 100, -5], [ 3, 4, 100, -4], [ 3, 4, 200, -5], [ 3, 4, 200, -4], [ 3, 4, 300, -5], [ 3, 4, 300, -4], [ 3, 4, 400, -5], [ 3, 4, 400, -4], [ 3, 8, 100, -5], [ 3, 8, 100, -4], [ 3, 8, 200, -5], [ 3, 8, 200, -4], [ 3, 8, 300, -5], [ 3, 8, 300, -4], [ 3, 8, 400, -5], [ 3, 8, 400, -4]])
Если вы хотите быстрее всего изменить первую ось ("стиль FORTRAN" или "основной столбец"), просто измените
order
параметрreshape()
следующим образом:reshape((-1, N), order='F')
источник
Pandas
merge
предлагает наивное и быстрое решение проблемы:# given the lists x, y, z = [1, 2, 3], [4, 5], [6, 7] # get dfs with same, constant index x = pd.DataFrame({'x': x}, index=np.repeat(0, len(x)) y = pd.DataFrame({'y': y}, index=np.repeat(0, len(y)) z = pd.DataFrame({'z': z}, index=np.repeat(0, len(z)) # get all permutations stored in a new df df = pd.merge(x, pd.merge(y, z, left_index=True, righ_index=True), left_index=True, right_index=True)
источник