Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/359.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在numpy中修改某些数组索引_Python_Numpy - Fatal编程技术网

Python 在numpy中修改某些数组索引

Python 在numpy中修改某些数组索引,python,numpy,Python,Numpy,我有一个形状(5,x,y)的NumPy数组 我只想通过一个等式修改前三个通道中的每个元素 element=(element-a)/b 我希望其他两个频道保持不变。如何索引数组以实现此目的?因为形状是(通道,x,y)您可以使用 x = np.random.rand(5,300,400) a,b = 10,15 x[0:3] = (x[0:3] - a)/b 通常,人们会使用索引来获取只包含相关值的数组切片 >>> desired_shape = (5, 2, 2) # xy =

我有一个形状(5,x,y)的NumPy数组

我只想通过一个等式修改前三个通道中的每个元素

element=(element-a)/b

我希望其他两个频道保持不变。如何索引数组以实现此目的?

因为形状是
(通道,x,y)
您可以使用

x = np.random.rand(5,300,400)
a,b = 10,15
x[0:3] = (x[0:3] - a)/b

通常,人们会使用索引来获取只包含相关值的数组切片

>>> desired_shape = (5, 2, 2) # xy = (2,2) in this example

>>> ary = np.array(range(5 * 2 * 2))
>>> ary.shape = desired_shape
>>> ary
array([[[ 0,  1],
        [ 2,  3]],

       [[ 4,  5],
        [ 6,  7]],

       [[ 8,  9],
        [10, 11]],

       [[12, 13],
        [14, 15]],

       [[16, 17],
        [18, 19]]])

>>> channels_view = ary[:3, ...] # up to 3 in 1st axis, preserve the others
>>> channels_view
array([[[ 0,  1],
        [ 2,  3]],

       [[ 4,  5],
        [ 6,  7]],

       [[ 8,  9],
        [10, 11]]])

>>> ary[:3, ...] = (ary[:3, ...] - a) / b
还可以使用np.view(),这样我们就可以字符串化更多的操作,而无需每次切片数组

>>> view = ary.view()
>>> view = view[:3, ...]
>>> view
array([[[ 0,  1],
        [ 2,  3]],

       [[ 4,  5],
        [ 6,  7]],

       [[ 8,  9],
        [10, 11]]])
对于本例,假设我们现在要将前三个通道中的所有值减半:

>>> view //= 2 # use //= rather than /=, because this is an integer array, and we didn't specify a dtype, so numpy assumes fixed point integers (longs) rather than floats
>>> view
array([[[0, 0],
        [1, 1]],

       [[2, 2],
        [3, 3]],

       [[4, 4],
        [5, 5]]])

>>> ary
array([[[ 0,  0],
        [ 1,  1]],

       [[ 2,  2],
        [ 3,  3]],

       [[ 4,  4],
        [ 5,  5]],

       [[12, 13],
        [14, 15]],

       [[16, 17],
        [18, 19]]])
但是啊哦!事实证明,我们实际上必须将它乘以一个数的几个因子

>>> factors_of_420
[2, 2, 3, 5, 7]
我知道这是一个愚蠢的例子,但假设我们不能提前知道数字是多少。比如,假设我们从TCP服务器或其他什么地方获得了因子

我们可以这样写:

>>> ary
数组([[0,1], [2,3]]

   [[ 4,  5],
    [ 6,  7]],

   [[ 8,  9],
    [10, 11]],

   [[12, 13],
    [14, 15]],

   [[16, 17],
    [18, 19]]])

>>> for fac in factors_of_420:
...     ary[:3, ...] = ary[:3, ...] * fac
... 
>>> ary
array([[[   0,  420],
        [ 840, 1260]],

       [[1680, 2100],
        [2520, 2940]],

       [[3360, 3780],
        [4200, 4620]],

       [[  12,   13],
        [  14,   15]],

       [[  16,   17],
        [  18,   19]]])
但是这有点难看,不是吗?而且,我打赌对列表中的每个因素运行两次切片操作(一次用于设置,一次用于获取)可能会对性能造成一些影响

这就是视图的优势所在。我们只需创建一个视图,并对其进行操作,numpy将操作应用到底层阵列:

我们不需要牺牲任何东西。我们同时制作更好更快的代码

>>> ary
array([[[ 0,  1],
        [ 2,  3]],

       [[ 4,  5],
        [ 6,  7]],

       [[ 8,  9],
        [10, 11]],

       [[12, 13],
        [14, 15]],

       [[16, 17],
        [18, 19]]])

>>> view = ary.view()[:3, ...] # make our pre-sliced view, yum!
>>> view
array([[[ 0,  1],
        [ 2,  3]],

       [[ 4,  5],
        [ 6,  7]],

       [[ 8,  9],
        [10, 11]]])

>>> for fac in factors_of_420:
...     view *= fac # use the *= (in place) operator, because 'view =' sets view to something else and does not apply to ary
...
>>> view
array([[[   0,  420],
        [ 840, 1260]],

       [[1680, 2100],
        [2520, 2940]],

       [[3360, 3780],
        [4200, 4620]]])
>>> ary
array([[[   0,  420],
        [ 840, 1260]],

       [[1680, 2100],
        [2520, 2940]],

       [[3360, 3780],
        [4200, 4620]],

       [[  12,   13],
        [  14,   15]],

       [[  16,   17],
        [  18,   19]]])
让我们看看时机告诉我们什么

>>> class WeirdSliceMultiplier:
...     def __init__(self):
...         self.factors = [2, 2, 3, 5, 7]
...     def setup(self):
...         self.ary = np.reshape(range(5 * 2 * 2), (5, 2, 2))
...     def setup_with_view(self):
...         self.setup()
...         self.view = self.ary.view()[:3, ...]
...     def multiply_every_slice(self):
...         for fac in self.factors:
...             self.ary[:3, ...] = self.ary[:3, ...] * fac
...     def multiply_view(self):
...         for fac in self.factors:
...             self.view *= fac

>>> timeit.timeit(multiplier.multiply_every_slice, multiplier.setup, number=50000) # 'slice for every factor' version
0.9404756519943476

>>> timeit.timeit(multiplier.multiply_view, multiplier.setup_with_view, number=50000) # 'slice view ahead of time' version
0.8748960520024411
请注意,在第二次调用时,它在设置中设置了
视图
(准确地说,在
设置中设置了带视图的设置
),而不是正在计时的实际函数。这是因为设置视图不会计算到最终时间,因为它应该在时间之前,并且我们只计算乘法的实际运算,而不是任何其他应用于视图但可能在之前或之后串接的运算

编辑:此外,正如@MadPhysicast在@mujiga的回答中指出的那样,我们实际上可能更喜欢使用内插运算符。事实上,我们已经在
乘法视图
函数中使用了内插运算符,因此对两者都使用内插运算符是一个更公平的比较:

>>> class WeirdSliceMultiplier:
...     def __init__(self):
...         self.factors = [2, 2, 3, 5, 7]
...     def setup(self):
...         self.ary = np.reshape(range(5 * 2 * 2), (5, 2, 2))
...     def setup_with_view(self):
...         self.setup()
...         self.view = self.ary.view()[:3, ...]
...     def multiply_every_slice_inplace(self):
...         for fac in self.factors:
...             self.ary[:3, ...] *= fac
...     def multiply_view(self):
...         for fac in self.factors:
...             self.view *= fac
...
>>> multiplier = WeirdSliceMultiplier()

>>> timeit.timeit(multiplier.multiply_every_slice_inplace, multiplier.setup, number=50000) # 'slice for every factor' version, but with inplace operators
1.0672136489883997
>>> timeit.timeit(multiplier.multiply_view, multiplier.setup_with_view, number=50000) # 'slice view ahead of time' version again for comparison
0.9300520950055216
使用_view执行设置_所需时间的奇怪变化,可能与CPU负载平均值或其他有关,可以使用标准化因子修复:

>>> old_viewslice_time = 0.8748960520024411
>>> new_viewslice_time = 0.9300520950055216
>>> norm_fac = old_viewslice_time / new_viewslice_time
>>> norm_fac
0.9406957488733435
>>> new_viewslice_time * norm_fac # should be very similar to old_viewslice_time
0.8748960520024411

>>> new_everyslice_inplace_time = 1.0672136489883997
>>> new_everyslice_inplace_time * norm_fac
1.003923342742996

我想你可以通过阅读numpy上的基本索引文档找到答案。
x[0:3]=a;x[0:3]/=b;
更节省空间。