更改Numpy对象中的每个元素

时间:2017-07-06 17:10:59

标签: numpy

我有一个带有随机N * M元素的Numpy对象,我也有两个数字A和B.

现在我想访问这个N * M数组中的每个元素并进行更改,即,如果元素> 0,将该元素替换为A(即,元素< -A),并且如果该元素< 0,将该元素替换为B(即元素< -B)。

我知道有一种天真的方法来实现这个方法,即使用for循环访问每个元素,但它非常慢。

我们可以使用更多花哨的代码来实现吗?

3 个答案:

答案 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 arraysnumpy.vectorize is essentially a for-loop,但仍然能够像天真的实施一样快三倍。 根据hpaulj的回答,Scott Boston提出的np.where变体比使用布尔掩码略快。但是,它确实需要更多内存,因为它不会在原地进行修改。