任意维数组中任意维坐标的笛卡尔积
Cartesian product of arbitrary-dimensional coordinates in arbitrary-dimensional arrays
这与Numpy: cartesian product of x and y array points into single array of 2D points
有点关系
我正在寻找一种简洁的方法来创建具有任意维度的两个数组的笛卡尔积。
示例:
类似相关话题,我要
x = numpy.array([1,2,3]) #ndim 1
y = numpy.array([4,5]) #ndim 1
cartesian_product(x,y) == numpy.array([[[1, 4],
[2, 4],
[3, 4]],
[[1, 5],
[2, 5],
[3, 5]]]) #ndim "2" = ndim x + ndim y
结果数组是二维的,因为 [1, 4]、[2, 4] 等是坐标,因此不是真正的维度。概括地说,最好将 x/y 写成 [[1], [2], [3]].
以上等于
numpy.dstack(numpy.meshgrid(x,y))
不过我也想要
x2 = numpy.array([[1,1], [2,2], [3,3]]) #ndim "1", since [1, 1] is a coordinate
cartesian_product(x2,y) == numpy.array([[[1, 1, 4],
[2, 2, 4],
[3, 3, 4]],
[[1, 1, 5],
[2, 2, 5],
[3, 3, 5]]]) #ndim 2 = ndim x2 + ndim y
y2 = numpy.array([[10, 11], [20, 21]]) #ndim 1
(cartesian_product(x2, y2) ==
numpy.array([[[1, 1, 10, 11],
[2, 2, 10, 11],
[3, 3, 10, 11]],
[[1, 1, 20, 21],
[2, 2, 20, 21],
[3, 3, 20, 21]]])) #ndim x2 + ndim y2
x3 = numpy.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) #ndim 2
(cartesian_product(x3, y) ==
numpy.array([[[[1, 2, 4], [3, 4, 4]], [[5, 6, 4], [7, 8, 4]]],
[[[1, 2, 5], [3, 4, 5]], [[5, 6, 5], [7, 8, 5]]]]) #ndim 3
可视化我正在尝试做的事情:
正如我所说,[[0, 0], [0, 1], [1, 1], [1, 0]] 应该被解释为一维坐标列表,它对应于一条线。如果我然后用 [1, 2, 3, 4] 做笛卡尔积,我会在 z 方向上拉伸这条线,变成一个表面(即二维)。但是现在数组当然是3维的了。
我想我可以用循环来解决这个问题,但是有什么方法可以用 numpy/scipy 工具来实现吗?
一种内存高效的方式是广播赋值:
def cartesian_product(x, y):
if x.ndim < 2:
x = np.atleast_2d(x).T
if y.ndim < 2:
y = np.atleast_2d(y).T
sx, sy = x.shape, y.shape
sz = sy[:-1] + sx[:-1] + (sy[-1] + sx[-1],)
z = np.empty(sz, np.result_type(x, y))
# Broadcasted assignment
z[...,:sx[-1]] = x
z[...,sx[-1]:] = y.reshape(sy[:-1] + (x.ndim-1)*(1,) + (sy[-1],))
return z
如果您需要有关广播的详细信息,this page已涵盖。
这与Numpy: cartesian product of x and y array points into single array of 2D points
有点关系我正在寻找一种简洁的方法来创建具有任意维度的两个数组的笛卡尔积。
示例:
类似相关话题,我要
x = numpy.array([1,2,3]) #ndim 1
y = numpy.array([4,5]) #ndim 1
cartesian_product(x,y) == numpy.array([[[1, 4],
[2, 4],
[3, 4]],
[[1, 5],
[2, 5],
[3, 5]]]) #ndim "2" = ndim x + ndim y
结果数组是二维的,因为 [1, 4]、[2, 4] 等是坐标,因此不是真正的维度。概括地说,最好将 x/y 写成 [[1], [2], [3]].
以上等于
numpy.dstack(numpy.meshgrid(x,y))
不过我也想要
x2 = numpy.array([[1,1], [2,2], [3,3]]) #ndim "1", since [1, 1] is a coordinate
cartesian_product(x2,y) == numpy.array([[[1, 1, 4],
[2, 2, 4],
[3, 3, 4]],
[[1, 1, 5],
[2, 2, 5],
[3, 3, 5]]]) #ndim 2 = ndim x2 + ndim y
y2 = numpy.array([[10, 11], [20, 21]]) #ndim 1
(cartesian_product(x2, y2) ==
numpy.array([[[1, 1, 10, 11],
[2, 2, 10, 11],
[3, 3, 10, 11]],
[[1, 1, 20, 21],
[2, 2, 20, 21],
[3, 3, 20, 21]]])) #ndim x2 + ndim y2
x3 = numpy.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) #ndim 2
(cartesian_product(x3, y) ==
numpy.array([[[[1, 2, 4], [3, 4, 4]], [[5, 6, 4], [7, 8, 4]]],
[[[1, 2, 5], [3, 4, 5]], [[5, 6, 5], [7, 8, 5]]]]) #ndim 3
可视化我正在尝试做的事情: 正如我所说,[[0, 0], [0, 1], [1, 1], [1, 0]] 应该被解释为一维坐标列表,它对应于一条线。如果我然后用 [1, 2, 3, 4] 做笛卡尔积,我会在 z 方向上拉伸这条线,变成一个表面(即二维)。但是现在数组当然是3维的了。
我想我可以用循环来解决这个问题,但是有什么方法可以用 numpy/scipy 工具来实现吗?
一种内存高效的方式是广播赋值:
def cartesian_product(x, y):
if x.ndim < 2:
x = np.atleast_2d(x).T
if y.ndim < 2:
y = np.atleast_2d(y).T
sx, sy = x.shape, y.shape
sz = sy[:-1] + sx[:-1] + (sy[-1] + sx[-1],)
z = np.empty(sz, np.result_type(x, y))
# Broadcasted assignment
z[...,:sx[-1]] = x
z[...,sx[-1]:] = y.reshape(sy[:-1] + (x.ndim-1)*(1,) + (sy[-1],))
return z
如果您需要有关广播的详细信息,this page已涵盖。