使用numpy构建两个数组的所有组合的数组
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用numpy构建两个数组的所有组合的数组相关的知识,希望对你有一定的参考价值。
我试图在6参数函数的参数空间上运行以研究它的数值行为,然后再尝试做任何复杂的事情,所以我正在寻找一种有效的方法来做到这一点。
给定6-dim 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)
这有效,但它太慢了。我知道参数的空间很大,但这不应该太慢。在这个例子中我只抽取了106(一百万)个点,并且创建数组values
花了超过15秒。
你知道用numpy做这个更有效的方法吗?
如果有必要,我可以修改F
函数获取它的参数的方式。
在较新版本的numpy
(> 1.8.x)中,numpy.meshgrid()
提供了更快的实现:
@pws解决方案
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]])
请注意,最终结果的顺序略有不同。
这是一个纯粹的实现。它是ca.比使用itertools快5倍。
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
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数组,你将不得不接受构造或清理的额外开销,并在每一步重新填充一个。
以下numpy实现应该是约。 2x给定答案的速度:
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
看起来你想要一个网格来评估你的函数,在这种情况下你可以使用numpy.ogrid
(open)或numpy.mgrid
(fleshed out):
import numpy
my_grid = numpy.mgrid[[slice(0,1,0.1)]*6]
你可以做这样的事情
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]])
你可以使用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]]
对于一维阵列(或平坦的python列表)的笛卡尔积的纯粹numpy实现,只需使用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 style”或“column-major”),只需像这样更改order
的reshape()
参数:reshape((-1, N), order='F')
以上是关于使用numpy构建两个数组的所有组合的数组的主要内容,如果未能解决你的问题,请参考以下文章
如何在 python 中明智地组合两个 numpy 数组元素?
如何从一个1d Numpy数组的所有排列组合中删除所有的圆台排列组合?
给定两个 2D numpy 数组 A 和 B,如何有效地将采用两个 1D 数组的函数应用于 A 和 B 行的每个组合?