Python Numpy:可以使用广播按行替换值吗?

Python Numpy:可以使用广播按行替换值吗?,python,numpy,array-broadcasting,Python,Numpy,Array Broadcasting,我有一个M x N矩阵x和一个1 x N矩阵Y。我想做的是用Y中基于其列的适当值替换x中的任何0项 所以如果 X = np.array([[0, 1, 2], [3, 0, 5]]) 及 期望的最终结果将是[[10,1,2],[3,20,5]] 这可以直接通过生成一个M x N矩阵来实现,其中每一行都是Y,然后使用滤波器阵列: Y = np.ones((X.shape[0], 1)) * Y.reshape(1, -1) X[X==0] = Y[X==0] 但这可以通过numpy的广播功能实

我有一个M x N矩阵x和一个1 x N矩阵Y。我想做的是用Y中基于其列的适当值替换x中的任何0项

所以如果

X = np.array([[0, 1, 2], [3, 0, 5]])

期望的最终结果将是[[10,1,2],[3,20,5]]

这可以直接通过生成一个M x N矩阵来实现,其中每一行都是Y,然后使用滤波器阵列:

Y = np.ones((X.shape[0], 1)) * Y.reshape(1, -1)
X[X==0] = Y[X==0]

但这可以通过numpy的广播功能实现吗?

当然可以。使用以下方法创建
Y
的广播视图,形状为
X
,而不是实际重复
Y


当然。使用以下方法创建
Y
的广播视图,形状为
X
,而不是实际重复
Y


展开
X
,使其更加通用:

In [306]: X = np.array([[0, 1, 2], [3, 0, 5],[0,1,0]])
其中
标识0;第二个数组标识列

In [307]: idx = np.where(X==0)
In [308]: idx
Out[308]: (array([0, 1, 2, 2]), array([0, 1, 0, 2]))


In [309]: Z = X.copy()
In [310]: Z[idx]
Out[310]: array([0, 0, 0, 0])       # flat list of where to put the values
In [311]: Y[idx[1]]
Out[311]: array([10, 20, 10, 30])   # matching list of values by column

In [312]: Z[idx] = Y[idx[1]]
In [313]: Z
Out[313]: 
array([[10,  1,  2],
       [ 3, 20,  5],
       [10,  1, 30]])
不做广播,但相当干净
numpy


广播到
方法相比的次数

In [314]: %%timeit 
     ...: idx = np.where(X==0)
     ...: Z[idx] = Y[idx[1]]
     ...: 
9.28 µs ± 157 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [315]: %%timeit
     ...: exp = np.broadcast_to(Y,X.shape)
     ...: mask=X==0
     ...: Z[mask] = exp[mask]
     ...: 
19.5 µs ± 513 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
更快,尽管样本量很小

另一种使
扩展的方法是使用
重复

In [319]: %%timeit
     ...: exp = np.repeat(Y[None,:],3,0)
     ...: mask=X==0
     ...: Z[mask] = exp[mask]
     ...: 
10.8 µs ± 55.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
其时间接近我的
位置
。原来,
broadcast\u to
相对较慢:

In [321]: %%timeit
     ...: exp = np.broadcast_to(Y,X.shape)
     ...: 
10.5 µs ± 52.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [322]: %%timeit
     ...: exp = np.repeat(Y[None,:],3,0)
     ...: 
3.76 µs ± 11.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

我们必须进行更多的测试,看看这是否仅仅是由于安装成本,或者相对时间是否仍然适用于更大的阵列。

展开
X
,使其更为通用:

In [306]: X = np.array([[0, 1, 2], [3, 0, 5],[0,1,0]])
其中
标识0;第二个数组标识列

In [307]: idx = np.where(X==0)
In [308]: idx
Out[308]: (array([0, 1, 2, 2]), array([0, 1, 0, 2]))


In [309]: Z = X.copy()
In [310]: Z[idx]
Out[310]: array([0, 0, 0, 0])       # flat list of where to put the values
In [311]: Y[idx[1]]
Out[311]: array([10, 20, 10, 30])   # matching list of values by column

In [312]: Z[idx] = Y[idx[1]]
In [313]: Z
Out[313]: 
array([[10,  1,  2],
       [ 3, 20,  5],
       [10,  1, 30]])
不做广播,但相当干净
numpy


广播到
方法相比的次数

In [314]: %%timeit 
     ...: idx = np.where(X==0)
     ...: Z[idx] = Y[idx[1]]
     ...: 
9.28 µs ± 157 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [315]: %%timeit
     ...: exp = np.broadcast_to(Y,X.shape)
     ...: mask=X==0
     ...: Z[mask] = exp[mask]
     ...: 
19.5 µs ± 513 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
更快,尽管样本量很小

另一种使
扩展的方法是使用
重复

In [319]: %%timeit
     ...: exp = np.repeat(Y[None,:],3,0)
     ...: mask=X==0
     ...: Z[mask] = exp[mask]
     ...: 
10.8 µs ± 55.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
其时间接近我的
位置
。原来,
broadcast\u to
相对较慢:

In [321]: %%timeit
     ...: exp = np.broadcast_to(Y,X.shape)
     ...: 
10.5 µs ± 52.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [322]: %%timeit
     ...: exp = np.repeat(Y[None,:],3,0)
     ...: 
3.76 µs ± 11.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
我们必须做更多的测试,看看这是否仅仅是由于安装成本,或者相对时间是否仍然适用于更大的阵列