利用Python进行数据分析之Numpy学习笔记(二)
这一篇文章主要来讲索引,但是先不直接说各种索引的用法,先胡扯会需要知道的,也不是什么重点,但是就是需要知道。没有先后顺序,就是胡扯。
以下所有的英文引用均来自官方介绍Indexing。
ndarrays
can be indexed using the standard Pythonx[obj]
syntax, where x is the array and obj the selection. There are three kinds of indexing available: field access, basic slicing, advanced indexing. Which one occurs depends on obj.
格式 :x[obj]
,其中x是array,obj是选择项,一共有三种索引方式: field access
, basic slicing
, advanced indexing
,这是官方文档的解释,和我们平时说的有些出入。
In Python,
x[(exp1, exp2, ..., expN)]
is equivalent tox[exp1, exp2, ..., expN]
; the latter is just syntactic sugar for the former.
在Python中, x[(exp1, exp2, ..., expN)]
等效于x[exp1, exp2, ..., expN]
,另外在《数据分析》一书中说”x[1][2]
是等效于x[1,2]
的。“
All arrays generated by basic slicing are always views of the original array.
通过切片产生的数组是原始数组的视图。
Basic slicing with more than one non-
:
entry in the slicing tuple, acts like repeated application of slicing using a single non-:
entry, where the non-:
entries are successively taken (with all other non-:
entries replaced by:
). Thus,x[ind1,...,ind2,:]
acts likex[ind1][...,ind2,:]
under basic slicing.Warning:
The above is not true for advanced indexing.
在切片元组中使用多个非:
的基本切片,其行为类似于使用单个非:
重复应用于切片,其中非:
是被连续采用的,并且必须是在前面出现的,经测试:
出现在前面失败。,x[ind1,...,ind2,:]
等效于 x[ind1][...,ind2,:]
You may use slicing to set values in the array, but (unlike lists) you can never grow the array. The size of the value to be set in
x[obj] = value
must be (broadcastable) to the same shape asx[obj]
.
通切片索引赋值,value的shape要和x[obj]的形状一致,如果一定要不同的话,那必须是可广播的,并且赋值后的shape依旧不能变化。
Advanced indexing is triggered when the selection object, obj, is a non-tuple sequence object, an
ndarray
(of data type integer or bool), or a tuple with at least one sequence object or ndarray (of data type integer or bool). There are two types of advanced indexing: integer and Boolean.Advanced indexing always returns a copy of the data (contrast with basic slicing that returns a view).
这一个是高级索引的定义,也就是我们说的花式索引。高级索引的触发条件是x[obj]中的obj是一个非元组的序列对象,或者是一个数据类型是整型或布尔型的ndarray,或者是至少有一个序列对象或数据类型是整型或布尔型的ndarray的元组。
这里的翻译确实绕口,如有翻译错误,请不吝指正。最前面的那个非元组应该就是不能是纯数字的元组E.g.(2,3,4),因为元组也是一个序列对象x[(2,3,4)]就等于x[2,3,4],这就成了基本索引。
Integer array indexing
Integer array indexing allows selection of arbitrary items in the array based on their N-dimensional index. Each integer array represents a number of indexes into that dimension.
整数数组索引允许基于轴随意的选择元素,每一个整数数组代表了一些在特定维度上的索引。
Combining advanced and basic indexing
When there is at least one slice (
:
), ellipsis (...
) ornp.newaxis
in the index (or the array has more dimensions than there are advanced indexes), then the behaviour can be more complicated. It is like concatenating the indexing result for each advanced index element.
当高级索引里面包含基本索引的时候如切片,那么他就像高级索引里的每一个基本索引的串联,就是在上一个索引的基础上索引,递归索引。说句实话括号里的那一句确实不知道在说什么。
下面就有一个例子,确实复杂,完全靠猜。
The easiest way to understand the situation may be to think in terms of the result shape. There are two parts to the indexing operation, the subspace defined by the basic indexing (excluding integers) and the subspace from the advanced indexing part. Two cases of index combination need to be distinguished:
- The advanced indexes are separated by a slice, ellipsis or newaxis. For example
x[arr1, :, arr2]
.- The advanced indexes are all next to each other. For example
x[..., arr1, arr2, :]
but notx[arr1, :, 1]
since1
is an advanced index in this regard.In the first case, the dimensions resulting from the advanced indexing operation come first in the result array, and the subspace dimensions after that. In the second case, the dimensions from the advanced indexing operations are inserted into the result array at the same spot as they were in the initial array (the latter logic is what makes simple advanced indexing behave just like slicing).
Example
Suppose
x.shape
is (10,20,30) andind
is a (2,3,4)-shaped indexingintp
array, thenresult = x[...,ind,:]
has shape (10,2,3,4,30) because the (20,)-shaped subspace has been replaced with a (2,3,4)-shaped broadcasted indexing subspace. If we let i, j, k loop over the (2,3,4)-shaped subspace thenresult[...,i,j,k,:] = x[...,ind[i,j,k],:]
. This example produces the same result asx.take(ind, axis=-2)
.
这个例子虽然说看不太懂吧,但是解释了我以前遇到的奇葩问题:一个3×3的数组经过一个2×2的数组索引后变成了一个2×2×3的数组,并且如果用一个自己构造的同种结构的列表数组,却是无法实现的,结果和两个数组一样。
In [62]: array
Out[62]:
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
In [63]: aa
Out[63]:
array([[1, 0],
[0, 1]])
In [64]: array[aa]
Out[64]:
array([[[4, 5, 6],
[1, 2, 3]],
[[1, 2, 3],
[4, 5, 6]]])
In [65]: array[[1,0],[0,1]]
Out[65]: array([4, 2])
In [66]: array[[[1,0],[0,1]]]
Out[66]: array([4, 2])
这个一定要有个解释的话,应该是这样的:ndarray中的每一个维度中同维度元素都是指向要索引数组同一纬度的,不想列表数组那样,第一个数组指向0轴,第二个指向1轴,不是索引递归,而是同等级的,他们选出的数组也是同等级的。这并不能看成是简单的3替换成2×2。
Boolean array indexing
This advanced indexing occurs when obj is an array object of Boolean type, such as may be returned from comparison operators.
布尔型索引发生的条件是obj是一个布尔型数组,比如可以从比较运算符返回。
其实这个布尔型索引和整数列表的高级索引是相似的。
好了不再瞎扯了,挺累的,现在开始规矩的说各种索引了,全部通过例子呈现,凡是我想到的需要注意的,都写在例子中了。
-
基本索引
In [4]: arr Out[4]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) In [5]: arr[5] Out[5]: 5 In [7]: arr2 Out[7]: array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) In [8]: arr2[1][2] Out[8]: 5 In [9]: arr2[1,2] Out[9]: 5
x[a][b] == x[a,b]
通过索引列表递归索引,维度递归,
a
索引的是最高维0轴元素,b
索引的是次高维1轴元素。 -
切片索引
In [10]: arr Out[10]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) In [11]: arr[2:5] Out[11]: array([2, 3, 4]) In [12]: arr[2::2] Out[12]: array([2, 4, 6, 8]) In [13]: arr2 Out[13]: array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) In [14]: arr2[1:] Out[14]: array([[3, 4, 5], [6, 7, 8]]) In [15]: arr2[1:,1:] Out[15]: array([[4, 5], [7, 8]]) In [16]: arr2[:,:1] Out[16]: array([[0], [3], [6]]) In [55]: arr2 Out[55]: array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) In [56]: temp = arr2[2:] In [57]: temp Out[57]: array([[6, 7, 8]]) In [58]: temp = 9 In [59]: temp Out[59]: 9 In [60]: arr2 Out[60]: array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) # 这里不会发生改变,temp已经指向了新的区域 In [61]: temp = arr2[2:] In [62]: temp Out[62]: array([[6, 7, 8]]) In [63]: temp[:] = 9 In [64]: temp Out[64]: array([[9, 9, 9]]) In [65]: arr2 Out[65]: array([[0, 1, 2], [3, 4, 5], [9, 9, 9]]) # 通过切片,改变temp,arr2数据也同时发生了改变。
切片是在某一轴向进行横向选取,维度选定,这种的选取是同级的元素,这种选择方式似乎还会保留原数据的相对维度信息。比如切片选择一个3×3的数组的第一列,选出来的是(3,1)的数组,而基本索引选出来的是(3,)的。
切片索引和列表索引可以叠在一起使用。
通过第一个基本索引和这切片索引产生的数组是原数组的视图,改变视图即改变原数据。
-
高级索引
-
整数数组索引
In [10]: arr Out[10]: array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]) In [11]: arr[[5,2,1,0]] Out[11]: array([[20, 21, 22, 23], [ 8, 9, 10, 11], [ 4, 5, 6, 7], [ 0, 1, 2, 3]]) In [12]: arr[[5,2,1,0],[2,2,1,2]] #构成索引对 Out[12]: array([22, 10, 5, 2]) In [13]: arr[[[0,0],[5,5]],[[0,3],[0,3]]] #选取四角元素方式一 Out[13]: array([[ 0, 3], [20, 23]]) In [14]: arr[[[0],[5]],[0,3]] #选取四角元素方式二 Out[14]: array([[ 0, 3], [20, 23]])
整数数组索引是通过数组与数组一一对应构成索引对来选取的,每一数组代表不同轴,假如两个数组形状不同,如果这两个数组能够以广播的形式构成索引对,也是可以的。
如果一定要选取一个区域的话可以使用高级索引+切片索引,或者使用np.ix_函数,此函数只允许传入两个一维整数数组。其实np.ix_产生的就是一个元组里面是两个array,看一下array的形状就知道np.ix_的原理了。
-
布尔型数组索引
In [22]: arr Out[22]: array([[ 1.12105851, 0.27287448, 0.07762638, -0.26287726], [ 0.78763995, -0.48796014, 0.3238146 , 0.22576988], [ 0.86004933, 1.79189963, -0.88055021, -0.1065679 ]]) In [23]: arr[np.array([False,True,False])] Out[23]: array([[ 0.78763995, -0.48796014, 0.3238146 , 0.22576988]]) In [24]: arr[arr < 0] Out[24]: array([-0.26287726, -0.48796014, -0.88055021, -0.1065679 ]) In [25]: arr[arr < 0] = 0 #通过布尔型数组设值 In [26]: arr Out[26]: array([[ 1.12105851, 0.27287448, 0.07762638, 0. ], [ 0.78763995, 0. , 0.3238146 , 0.22576988], [ 0.86004933, 1.79189963, 0. , 0. ]])
通过布尔型数组选取数组中的数据,总是创建数据的副本,因为布尔型数组索引也是高级索引的一种。
-
ndarray索引
ndarray做索引在上文已经说明这里不再所赘述。
还是那句话,如有不当之处,理解错误之处,欢迎指正。
-