Вопрос-Ответ

Using NumPy to build an array of all combinations of two arrays

Использование NumPy для построения массива из всех комбинаций двух массивов

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

Моя функция принимает значения с плавающей запятой, заданные в 6-значном массиве NumPy, в качестве входных данных. Изначально я пытался сделать следующее:

Сначала я создал функцию, которая принимает два массива и генерирует массив со всеми комбинациями значений из двух массивов:

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)

Это работает, но это путь слишком медленно. Я знаю, что пространство параметров огромно, но это не должно быть таким медленным. В этом примере я отобрал только 106 (миллион) точек, и только на создание массива ушло более 15 секунд values.

Есть ли более эффективный способ сделать это с помощью NumPy?

Я могу изменить способ, которым функция F принимает свои аргументы, если это необходимо.

Переведено автоматически
Ответ 1

В более новых версиях 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() раньше он был только двумерным, но теперь он может быть многомерным. В данном случае трехмерный:

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]])

Обратите внимание, что порядок конечного результата немного отличается.

Ответ 2

Вот чисто NumPy-реализация. Это примерно в 5 раз быстрее, чем использование itertools.

Python 3:

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
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 in range(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

def cartesian(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 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
Ответ 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)).

2023-10-22 13:42 python arrays numpy