Python 在numpy中修改某些数组索引
我有一个形状(5,x,y)的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 =
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;
更节省空间。