方法一:输入仅包含0和1的数组
对于仅包含0和1的输入数组,我们可以将它们的每一行缩减为标量,因此将输入数组转换为1D,并利用广播,如下所示 -
n = x.shape[1]
s = 2**np.arange(n)
x1D = x.dot(s)
y1D = y.dot(s)
Xout = (x1D[:,None] == y1D).astype(float)
方案 #2:通用情况
对于通用情况,我们可以使用 views
-
def view1D(a, b):
a = np.ascontiguousarray(a)
b = np.ascontiguousarray(b)
void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
return a.view(void_dt).ravel(), b.view(void_dt).ravel()
x1D, y1D = view1D(x, y)
Xout = (x1D[:,None] == y1D).astype(float)
运行时测试
In [287]: np.random.seed(0)
...: n = 1000
...: x = rand.binomial(n=1, p=.5, size=(n, 10))
...: y = rand.binomial(n=1, p=.5, size=(n, 10))
In [288]: %%timeit
...: X = np.zeros((n, n))
...: for i in range(n):
...: for j in range(n):
...: X[i, j] = 1 * np.all(x[i] == y[j])
1 loop, best of 3: 4.69 s per loop
In [290]: %%timeit
...: n = x.shape[1]
...: s = 2**np.arange(n)
...: x1D = x.dot(s)
...: y1D = y.dot(s)
...: Xout = (x1D[:,None] == y1D).astype(float)
1000 loops, best of 3: 1.42 ms per loop
In [291]: %%timeit
...: x1D, y1D = view1D(x, y)
...: Xout = (x1D[:,None] == y1D).astype(float)
100 loops, best of 3: 18.5 ms per loop
(x[:, None, :] == y).all(axis=-1)
。但是,这种方法在时间上效率高,但空间效率不高(尽管在这种特定情况下,我们只需要大约10MB的空间)。您主要担心空间效率还是时间效率?实际上,n
会有多大? - Mark DickinsonX = np.zeros((n, n))
创建的默认数据类型是浮点型。您真的想让X
成为一个浮点值数组吗?如果您只关心相等性,您可以将其设置为小整数数组(X = np.zeros((n, n), dtype=np.int8)
)或布尔值数组(X = np.zeros((n, n), dtype=np.bool_)
)。 - Warren Weckessern
最多会是10^6
。 - p-valueX
加载到内存中可能会有麻烦。创建了X
后,你会怎么处理它? - Mark DickinsonX
是一个稀疏矩阵。之后,我需要使用X
执行多个矩阵向量乘积。 - p-value