测试阵列是否可以广播到给定形状的最佳方法是什么?
try
ing的“pythonic”方法对我的情况不起作用,因为其意图是对操作进行惰性评估。
我在问下面如何实施is_broadcastable
:
>>> x = np.ones([2,2,2])
>>> y = np.ones([2,2])
>>> is_broadcastable(x,y)
True
>>> y = np.ones([2,3])
>>> is_broadcastable(x,y)
False
或更好:
>>> is_broadcastable(x.shape, y.shape)
答案 0 :(得分:4)
如果您只是想避免实现具有给定形状的数组,可以使用as_strided:
import numpy as np
from numpy.lib.stride_tricks import as_strided
def is_broadcastable(shp1, shp2):
x = np.array([1])
a = as_strided(x, shape=shp1, strides=[0] * len(shp1))
b = as_strided(x, shape=shp2, strides=[0] * len(shp2))
try:
c = np.broadcast_arrays(a, b)
return True
except ValueError:
return False
is_broadcastable((1000, 1000, 1000), (1000, 1, 1000)) # True
is_broadcastable((1000, 1000, 1000), (3,)) # False
这是内存效率,因为a和b都由单个记录支持
答案 1 :(得分:3)
您可以使用np.broadcast
。例如:
In [47]: x = np.ones([2,2,2])
In [48]: y = np.ones([2,3])
In [49]: try:
....: b = np.broadcast(x, y)
....: print "Result has shape", b.shape
....: except ValueError:
....: print "Not compatible for broadcasting"
....:
Not compatible for broadcasting
In [50]: y = np.ones([2,2])
In [51]: try:
....: b = np.broadcast(x, y)
....: print "Result has shape", b.shape
....: except ValueError:
....: print "Not compatible for broadcasting"
....:
Result has shape (2, 2, 2)
对于懒惰评估的实施,您可能还会发现np.broadcast_arrays
有用。
答案 2 :(得分:2)
我真的认为你们都在考虑这个,为什么不保持简单呢?
def is_broadcastable(shp1, shp2):
for a, b in zip(shp1[::-1], shp2[::-1]):
if a == 1 or b == 1 or a == b:
pass
else:
return False
return True
答案 3 :(得分:0)
要将其概括为任意多种形状,可以按如下所示进行操作:
def is_broadcast_compatible(*shapes):
if len(shapes) < 2:
return True
else:
for dim in zip(*[shape[::-1] for shape in shapes]):
if len(set(dim).union({1})) <= 2:
pass
else:
return False
return True
对应的测试用例如下:
import unittest
class TestBroadcastCompatibility(unittest.TestCase):
def check_true(self, *shapes):
self.assertTrue(is_broadcast_compatible(*shapes), msg=shapes)
def check_false(self, *shapes):
self.assertFalse(is_broadcast_compatible(*shapes), msg=shapes)
def test(self):
self.check_true((1, 2, 3), (1, 2, 3))
self.check_true((3, 1, 3), (3, 3, 3))
self.check_true((1,), (2,), (2,))
self.check_false((1, 2, 3), (1, 2, 2))
self.check_false((1, 2, 3), (1, 2, 3, 4))
self.check_false((1,), (2,), (3,))
答案 4 :(得分:0)
对于要检查任意数量的类似数组的对象(与传递形状相反)的情况,我们可以将np.nditer
用于broadcasting array iteration。
def is_broadcastable(*arrays):
try:
np.nditer(arrays)
return True
except ValueError:
return False
请注意,这仅适用于np.ndarray
或定义__array__
的类(将调用 )。
答案 5 :(得分:0)
numpy.broadcast_shapes
现在从 numpy 1.20 开始可用,因此它可以像这样轻松实现:
import numpy as np
def is_broadcastable(shp1, shp2):
try:
c = np.broadcast_shapes(shp1, shp2)
return True
except ValueError:
return False
在幕后,它使用零长度列表 numpy 数组来调用 broadcast_arrays
,这样做:
np.empty(shp, dtype=[])
这样可以避免分配内存。它类似于 @ChrisB 提出的解决方案,但不依赖于 as_strided
技巧,我觉得这有点令人困惑。