我有一个带有随机N * M元素的Numpy对象,我也有两个数字A和B.
现在我想访问这个N * M数组中的每个元素并进行更改,即,如果元素> 0,将该元素替换为A(即,元素< -A),并且如果该元素< 0,将该元素替换为B(即元素< -B)。
我知道有一种天真的方法来实现这个方法,即使用for循环访问每个元素,但它非常慢。
我们可以使用更多花哨的代码来实现吗?
答案 0 :(得分:2)
布尔掩码赋值将更改值:
In [493]: arr = np.random.randint(-10,10,(5,7))
In [494]: arr
Out[494]:
array([[ -5, -6, -7, -1, -8, -8, -10],
[ -9, 1, -3, -9, 3, 8, -1],
[ 6, -7, 4, 0, -4, 4, -2],
[ -3, -10, -2, 7, -4, 2, 2],
[ -5, 5, -1, -7, 7, 5, -7]])
In [495]: arr[arr>0] = 100
In [496]: arr[arr<0] = -50
In [497]: arr
Out[497]:
array([[-50, -50, -50, -50, -50, -50, -50],
[-50, 100, -50, -50, 100, 100, -50],
[100, -50, 100, 0, -50, 100, -50],
[-50, -50, -50, 100, -50, 100, 100],
[-50, 100, -50, -50, 100, 100, -50]])
我在
中给出了类似的答案python numpy: iterate for different conditions without using a loop
答案 1 :(得分:1)
IIUC:
narr = np.random.randint(-100,100,(10,5))
array([[ 70, -20, 96, 73, -94],
[ 42, 35, -55, 56, 54],
[ 97, -16, 24, 32, 78],
[ 49, 49, -11, -82, 82],
[-10, 59, -42, -68, -70],
[ 95, 23, 22, 58, -38],
[ -2, -64, 27, -33, -95],
[ 98, 42, 8, -83, 85],
[ 23, 51, -99, -82, -7],
[-28, -11, -44, 95, 93]])
A = 1000
B = -999
使用np.where
:
np.where(narr > 0, A, np.where(narr < 0, B , narr))
输出:
array([[1000, -999, 1000, 1000, -999],
[1000, 1000, -999, 1000, 1000],
[1000, -999, 1000, 1000, 1000],
[1000, 1000, -999, -999, 1000],
[-999, 1000, -999, -999, -999],
[1000, 1000, 1000, 1000, -999],
[-999, -999, 1000, -999, -999],
[1000, 1000, 1000, -999, 1000],
[1000, 1000, -999, -999, -999],
[-999, -999, -999, 1000, 1000]])
答案 2 :(得分:0)
因为您提到您对计算的速度感兴趣,所以我针对您的问题对几种不同的方法进行了速度比较。
test.py:
import numpy as np
A = 100
B = 50
def createArray():
array = np.random.randint(-100,100,(500,500))
return array
def replace(x):
return A if x > 0 else B
def replace_ForLoop():
"""Simple for-loop."""
array = createArray()
for i in range(array.shape[0]):
for j in range(array.shape[1]):
array[i][j] = replace(array[i][j])
def replace_nditer():
"""Use numpy.nditer to iterate over values."""
array = createArray()
for elem in np.nditer(array, op_flags=['readwrite']):
elem[...] = replace(elem)
def replace_masks():
"""Use boolean masks."""
array = createArray()
array[array>0] = A
array[array<0] = B
def replace_vectorize():
"""Use numpy.vectorize"""
array = createArray()
vectorfunc = np.vectorize(replace)
array = vectorfunc(array)
def replace_where():
"""Use numpy.where"""
array = createArray()
array = np.where(array > 0, A, np.where(array < 0, B , array))
注意:使用嵌套for循环,np.nditer
和布尔掩码的变体在原地工作,最后两个不在。
时间比较:
> python -mtimeit -s'import test' 'test.replace_ForLoop()'
10 loops, best of 3: 185 msec per loop
> python -mtimeit -s'import test' 'test.replace_nditer()'
10 loops, best of 3: 294 msec per loop
> python -mtimeit -s'import test' 'test.replace_masks()'
100 loops, best of 3: 5.8 msec per loop
> python -mtimeit -s'import test' 'test.replace_vectorize()'
10 loops, best of 3: 55.3 msec per loop
> python -mtimeit -s'import test' 'test.replace_where()'
100 loops, best of 3: 5.42 msec per loop
使用循环确实很慢。 numpy.nditer
更慢,这对我来说是一个惊喜,因为文档称之为efficient multi-dimensional iterator object to iterate over arrays。 numpy.vectorize
is essentially a for-loop,但仍然能够像天真的实施一样快三倍。
根据hpaulj的回答,Scott Boston提出的np.where
变体比使用布尔掩码略快。但是,它确实需要更多内存,因为它不会在原地进行修改。