<p>可以将布尔索引与高级numpy数组索引一起使用:</p>
<pre><code>array3 = array1.astype(float) # this copies the array by default.
array3[array1 != 0] = array2[array1[array1 != 0]-1, 2]
</code></pre>
<p>结果是:</p>
<pre><code>array([[ 0, 62., 62., 88.],
[ 0, 73., 64., 95.],
[ 0, 59., 67., 65.]])
</code></pre>
<h2>解释</h2>
<p>首先创建一个布尔数组,该数组指示存在非零项的位置:</p>
<pre><code>>>> non_zero_mask = array1 != 0
array([[False, True, True, True],
[False, True, True, True],
[False, True, True, True]], dtype=bool)
</code></pre>
<p>这将用于查找应替换的元素。你知道吗</p>
<p>然后需要找到这些元素的值:</p>
<pre><code>>>> non_zero_values = array1[non_zero_mask]
array([7, 4, 1, 8, 5, 2, 9, 6, 3])
</code></pre>
<p>因为您的<code>array2</code>是有序的,并且从值1开始,所以我们需要减去1来找到替换值的适当行。如果您的<code>array2</code>没有排序,您可能需要对其进行排序或在两者之间执行另一个索引:</p>
<pre><code>>>> replacement_rows = array2[non_zero_values-1]
array([[ 7., 7., 62.],
[ 4., 4., 62.],
[ 1., 1., 88.],
[ 8., 8., 73.],
[ 5., 5., 64.],
[ 2., 2., 95.],
[ 9., 9., 59.],
[ 6., 6., 67.],
[ 3., 3., 65.]])
>>> replacement_values = array2[non_zero_values-1, 2] # third element of that row!
array([ 62., 62., 88., 73., 64., 95., 59., 67., 65.])
</code></pre>
<p>然后将这些值赋给原始数组或新数组:</p>
<pre><code>array3[non_zero_mask] = replacement_values
</code></pre>
<p>这种方法依赖于<code>array2</code>的排序,因此如果有更复杂的条件,它将中断。但这要么需要找到值和索引之间的关系并插入它,而不是我做的简单的<code>-1</code>,要么需要做另一个中间的<code>np.where</code>/布尔索引。你知道吗</p>
<h2>扩展</h2>
<p>如果没有已排序的<code>array2</code>而无法对其排序,则可以执行以下操作:</p>
<pre><code>>>> array3 = array1.astype(float)
>>> array3[array1 != 0] = array2[np.where(array2[:, 0][None, :] == array1[array1 != 0][:, None])[1], 2]
>>> array3
array([[ 0., 62., 62., 88.],
[ 0., 73., 64., 95.],
[ 0., 59., 67., 65.]])
</code></pre>
<p>因为这样可以互相广播数组,所以您将创建一个大小为<code>array1.size * array1.size</code>的数组。所以这可能不是很有效,但仍然完全矢量化。你知道吗</p>
<h2>麻木(如果你想要速度)</h2>
<p><a href="/questions/tagged/numba" class="post-tag" title="show questions tagged 'numba'" rel="tag">numba</a>是伟大的,如果你想加快事情会很慢,因为没有原生的numpy或scipy版本。如果您有anaconda或conda,那么它已经安装,因此可能是一个可行的选择:</p>
<pre><code>import numba as nb
import numpy as np
@nb.njit
def nb_replace_values(array, old_new_array):
res = np.zeros(array.shape, dtype=np.float64)
rows = array.shape[0]
columns = array.shape[1]
rows_replace_array = old_new_array.shape[0]
for row in range(rows):
for column in range(columns):
val = array[row, column]
# only replace values that are not zero
if val != 0:
# Find the value to replace the element with
for ind_replace in range(rows_replace_array):
if old_new_array[ind_replace, 0] == val:
# Match found. Replace and break the innermost loop
res[row, column] = old_new_array[ind_replace, 2]
break
return res
nb_replace_values(array1, array2)
array([[ 0., 62., 62., 88.],
[ 0., 73., 64., 95.],
[ 0., 59., 67., 65.]])
</code></pre>
<p>特别是对于大型阵列,这显然是最快和内存效率最高的解决方案,因为没有创建临时阵列。第一次调用会慢很多,因为函数需要动态编译。你知道吗</p>
<h2>时间安排:</h2>
<pre><code>%timeit nb_replace_values(array1, array2)
</code></pre>
<blockquote>
<p>100000 loops, best of 3: 6.23 µs per loop</p>
</blockquote>
<pre><code>%%timeit
array3 = array1.astype(float)
array3[array1 != 0] = array2[np.where(array2[:, 0][None, :] == array1[array1 != 0][:, None])[1], 2]
</code></pre>
<blockquote>
<p>10000 loops, best of 3: 74.8 µs per loop</p>
</blockquote>
<pre><code># Solution provided by @PDRX
%%timeit
array3 = array1.astype(float)
for i in array2[:,0]:
i_arr1,j_arr1 = np.where(array1 == i)
i_arr2 = np.where(array2[:,0] == i)
array3[i_arr1,j_arr1] = array2[i_arr2,2]
</code></pre>
<blockquote>
<p>1000 loops, best of 3: 689 µs per loop</p>
</blockquote>