numpy 数组切片两次
numpy array sliced twice
我不确定我是否理解为什么这不起作用:
a = np.zeros((10, ))
# first slicing array
pos1 = np.zeros((10, ), dtype=np.bool)
pos1[::2] = True
a[pos1] = 1.
print a
# returns [ 1. 0. 1. 0. 1. 0. 1. 0. 1. 0.]
# second slicing array
pos2 = np.zeros((5, ), dtype=np.bool)
pos2[::2] = True
a[pos1][pos2] = 2.
print a
# still returns [ 1. 0. 1. 0. 1. 0. 1. 0. 1. 0.]
为什么第二次切片没有影响全数组?
我认为 a[pos1]
只是原始数组子部分的 "view" ......我错过了什么吗?
(这个例子只是一个简单的例子,没有任何实际用处,只是为了理解,因为我经常使用这种语法,没想到会是这样的结果)
当我们定义以下三个函数时,请看一下 python 字节码(dis 的输出):
In [187]: def b():
a[pos1][pos2]=2
return a
In [188]: dis.dis(b)
2 0 LOAD_CONST 1 (2)
3 LOAD_GLOBAL 0 (a)
6 LOAD_GLOBAL 1 (pos1)
9 BINARY_SUBSCR
10 LOAD_GLOBAL 2 (pos2)
13 STORE_SUBSCR
3 14 LOAD_GLOBAL 0 (a)
17 RETURN_VALUE
In [189]: b()
Out[189]: array([ 1., 0., 1., 0., 1., 0., 1., 0., 1., 0.])
In [190]: def c():
e=a.copy()
e[pos1][pos2]=2
return e
In [191]: dis.dis(c)
2 0 LOAD_GLOBAL 0 (a)
3 LOAD_ATTR 1 (copy)
6 CALL_FUNCTION 0
9 STORE_FAST 0 (e)
3 12 LOAD_CONST 1 (2)
15 LOAD_FAST 0 (e)
18 LOAD_GLOBAL 2 (pos1)
21 BINARY_SUBSCR
22 LOAD_GLOBAL 3 (pos2)
25 STORE_SUBSCR
4 26 LOAD_FAST 0 (e)
29 RETURN_VALUE
In [191]: c()
Out[191]: array([ 1., 0., 1., 0., 1., 0., 1., 0., 1., 0.])
In [192]: def d():
f=a[pos1]
f[pos2]=2
return f
In [193]: dis.dis(d)
2 0 LOAD_GLOBAL 0 (a)
3 LOAD_GLOBAL 1 (pos1)
6 BINARY_SUBSCR
7 STORE_FAST 0 (f)
3 10 LOAD_CONST 1 (2)
13 LOAD_FAST 0 (f)
16 LOAD_GLOBAL 2 (pos2)
19 STORE_SUBSCR
4 20 LOAD_FAST 0 (f)
23 RETURN_VALUE
In [194]: d()
Out[194]: array([ 2., 1., 2., 1., 2.])
从反汇编代码来看,每次执行a[pos1][pos2]=2
赋值时,确实存储在栈顶,但是返回的是全局(case 1)或局部(case 2)变量反而。
当您拆分操作时(案例 3),解释器似乎突然想起它刚刚将值存储在堆栈中并且不需要重新加载它。
这与最近 Numpy doesn't change value of an array element after masking
中的问题相同
您使用的是布尔掩码,因此 a[pos1]
是副本,而不是切片。
第一组有效,因为它直接调用 __setitem__
:
a[pos1] = 1.
a.__setitem__(pos1) = 1
第二个没有,因为set
适用于a[pos1]
,复制:
a[pos1][pos2] = 2.
a.__getitem__(pos1).__setitem__(pos2)
a[::2][pos2]=3
确实有效,因为 a[::2]
是一个切片 - 即使它产生与 a[pos1]
.
相同的值
检查某物是副本还是视图的一种方法是查看数组的数据指针
a.__array_interface__['data']
a[pos1].__array_interface__['data'] # will be different
a[::2].__array_interface__['data'] # should be the same
我不确定我是否理解为什么这不起作用:
a = np.zeros((10, ))
# first slicing array
pos1 = np.zeros((10, ), dtype=np.bool)
pos1[::2] = True
a[pos1] = 1.
print a
# returns [ 1. 0. 1. 0. 1. 0. 1. 0. 1. 0.]
# second slicing array
pos2 = np.zeros((5, ), dtype=np.bool)
pos2[::2] = True
a[pos1][pos2] = 2.
print a
# still returns [ 1. 0. 1. 0. 1. 0. 1. 0. 1. 0.]
为什么第二次切片没有影响全数组?
我认为 a[pos1]
只是原始数组子部分的 "view" ......我错过了什么吗?
(这个例子只是一个简单的例子,没有任何实际用处,只是为了理解,因为我经常使用这种语法,没想到会是这样的结果)
当我们定义以下三个函数时,请看一下 python 字节码(dis 的输出):
In [187]: def b():
a[pos1][pos2]=2
return a
In [188]: dis.dis(b)
2 0 LOAD_CONST 1 (2)
3 LOAD_GLOBAL 0 (a)
6 LOAD_GLOBAL 1 (pos1)
9 BINARY_SUBSCR
10 LOAD_GLOBAL 2 (pos2)
13 STORE_SUBSCR
3 14 LOAD_GLOBAL 0 (a)
17 RETURN_VALUE
In [189]: b()
Out[189]: array([ 1., 0., 1., 0., 1., 0., 1., 0., 1., 0.])
In [190]: def c():
e=a.copy()
e[pos1][pos2]=2
return e
In [191]: dis.dis(c)
2 0 LOAD_GLOBAL 0 (a)
3 LOAD_ATTR 1 (copy)
6 CALL_FUNCTION 0
9 STORE_FAST 0 (e)
3 12 LOAD_CONST 1 (2)
15 LOAD_FAST 0 (e)
18 LOAD_GLOBAL 2 (pos1)
21 BINARY_SUBSCR
22 LOAD_GLOBAL 3 (pos2)
25 STORE_SUBSCR
4 26 LOAD_FAST 0 (e)
29 RETURN_VALUE
In [191]: c()
Out[191]: array([ 1., 0., 1., 0., 1., 0., 1., 0., 1., 0.])
In [192]: def d():
f=a[pos1]
f[pos2]=2
return f
In [193]: dis.dis(d)
2 0 LOAD_GLOBAL 0 (a)
3 LOAD_GLOBAL 1 (pos1)
6 BINARY_SUBSCR
7 STORE_FAST 0 (f)
3 10 LOAD_CONST 1 (2)
13 LOAD_FAST 0 (f)
16 LOAD_GLOBAL 2 (pos2)
19 STORE_SUBSCR
4 20 LOAD_FAST 0 (f)
23 RETURN_VALUE
In [194]: d()
Out[194]: array([ 2., 1., 2., 1., 2.])
从反汇编代码来看,每次执行a[pos1][pos2]=2
赋值时,确实存储在栈顶,但是返回的是全局(case 1)或局部(case 2)变量反而。
当您拆分操作时(案例 3),解释器似乎突然想起它刚刚将值存储在堆栈中并且不需要重新加载它。
这与最近 Numpy doesn't change value of an array element after masking
中的问题相同您使用的是布尔掩码,因此 a[pos1]
是副本,而不是切片。
第一组有效,因为它直接调用 __setitem__
:
a[pos1] = 1.
a.__setitem__(pos1) = 1
第二个没有,因为set
适用于a[pos1]
,复制:
a[pos1][pos2] = 2.
a.__getitem__(pos1).__setitem__(pos2)
a[::2][pos2]=3
确实有效,因为 a[::2]
是一个切片 - 即使它产生与 a[pos1]
.
检查某物是副本还是视图的一种方法是查看数组的数据指针
a.__array_interface__['data']
a[pos1].__array_interface__['data'] # will be different
a[::2].__array_interface__['data'] # should be the same