我正在阅读有关numpy bool索引的数据分析的书籍python,它说通过布尔索引从数组中选择数据总是会创建数据的副本,但是为什么我可以更改使用布伦索引的原始数组?有人可以帮助我吗?多谢。这是一个示例:
In [86]: data
Out[86]:
array([[-0.048 , 0.5433, -0.2349, 1.2792],
[-0.268 , 0.5465, 0.0939, -2.0445],
[-0.047 , -2.026 , 0.7719, 0.3103],
[ 2.1452, 0.8799, -0.0523, 0.0672],
[-1.0023, -0.1698, 1.1503, 1.7289],
[ 0.5994, 0.8174, -0.9297, -1.2564]])
In [96]: data[data < 0] = 0
In [97]: data
Out[97]:
array([[ 0. , 0.5433, 0. , 1.2792],
[ 0. , 0.5465, 0.0939, 0. ],
[ 0. , 0. , 0.7719, 0.3103],
[ 2.1452, 0.8799, 0. , 0.0672],
[ 0. , 0. , 1.1503, 1.7289],
[ 0.1913, 0.4544, 0.4519, 0.5535],
[ 0.5994, 0.8174, 0. , 0. ]])
布尔索引返回数据的副本,而不是原始数据的视图,就像一个人获得的slices一样。
>>> b=data[data<0]; b # this is a copy of data
array([-0.048 , -0.2349, -0.268 , -2.0445, -0.047 , -2.026 , -0.0523,
-1.0023, -0.1698, -0.9297, -1.2564])
i可以保留b
和data
。
>>> b[:] = 0; b
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
>>> data
array([[-0.048 , 0.5433, -0.2349, 1.2792],
[-0.268 , 0.5465, 0.0939, -2.0445],
[-0.047 , -2.026 , 0.7719, 0.3103],
[ 2.1452, 0.8799, -0.0523, 0.0672],
[-1.0023, -0.1698, 1.1503, 1.7289],
[ 0.5994, 0.8174, -0.9297, -1.2564]])
现在,要切片:
>>> a = data[0,:]; a # a is not a copy of data
array([-0.048 , 0.5433, -0.2349, 1.2792])
>>> a[:] = 0; a
array([ 0., 0., 0., 0.])
>>> data
array([[ 0. , 0. , 0. , 0. ],
[-0.268 , 0.5465, 0.0939, -2.0445],
[-0.047 , -2.026 , 0.7719, 0.3103],
[ 2.1452, 0.8799, -0.0523, 0.0672],
[-1.0023, -0.1698, 1.1503, 1.7289],
[ 0.5994, 0.8174, -0.9297, -1.2564]])
但是,正如您已经确定的,通过索引数组进行的作业始终对原始数据进行。
>>> data[data<0] = 1; data
array([[ 1. , 0.5433, 1. , 1.2792],
[ 1. , 0.5465, 0.0939, 1. ],
[ 1. , 1. , 0.7719, 0.3103],
[ 2.1452, 0.8799, 1. , 0.0672],
[ 1. , 1. , 1.1503, 1.7289],
[ 0.5994, 0.8174, 1. , 1. ]])
在获取或__getitem__
中,布尔索引确实返回副本。但是,如果使用立即在分配之前,则是__setitem__
情况,并且将更改选定的值:
In [196]: data = np.arange(10)
In [197]: d1 = data[data<5]
In [198]: d1 # a copy
Out[198]: array([0, 1, 2, 3, 4])
In [199]: d1[:] = 0
In [200]: data # not change to the original
Out[200]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
掩盖分配:
In [201]: data[data<5] = 0
In [202]: data
Out[202]: array([0, 0, 0, 0, 0, 5, 6, 7, 8, 9]) # changed data
间接分配什么都不做:
In [204]: data[data<5][:] = 1
In [205]: data
Out[205]: array([0, 0, 0, 0, 0, 5, 6, 7, 8, 9])
将其视为data.__getitem__(mask).__setitem__(slice) = 1
。get项目返回副本,设置项目会更改 - 但不会更改原始。
因此,如果您需要使用LHS的高级索引,请确保立即分配前。而且您不能在LHS上使用2个高级索引步骤。
查看v复制
使用basic
索引,可以使用原始数据库,并且只需更改形状和大步之类的属性即可。例如:
In [85]: x = np.arange(10)
In [86]: x.shape
Out[86]: (10,)
In [87]: x.strides
Out[87]: (4,)
In [88]: y = x[::2]
In [89]: y.shape
Out[89]: (5,)
In [90]: y.strides
Out[90]: (8,)
y
具有与x
相同的数据库(比较x.__array_interface__
字典)。x
使用所有10个Bytes元素; y
使用其他每一个(步步为8个字节而不是4个字节)。
但是,使用高级索引,您无法以形状和大步表达元素选择。
In [98]: z = x[[1,2,6,7,0]]
In [99]: z.shape
Out[99]: (5,)
In [100]: z.strides
Out[100]: (4,)
原始数组中的项目可以按任何顺序和重复选择。没有常规模式。因此需要副本。