Python Numpy索引副本



我正在阅读有关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可以保留bdata

>>> 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,)

原始数组中的项目可以按任何顺序和重复选择。没有常规模式。因此需要副本。

最新更新