NumPy核心概念
NumPy是Python数据科学生态中重要的基础成员,其中有几个概念比较tricky,简单记录之。更佳阅读体验,可移步NumPy核心概念。
N维数组
NumPy最核心的数据类型是N维数组The N-dimensional array (ndarray),可以看成homogenous(同质) items的集合,与只密切相关的两种类型是Data type objects (dtype)和Scalars。
tool-np-ndarray比如典型数组
>>> x = np.array([[5.2, 3.0, 4.5], [9.1, 0.1, 0.3]], np.float32)
>>> x
array([[5.2, 3. , 4.5],
[9.1, 0.1, 0.3]], dtype=float32)
tool-np-nparray
数据类型对象(np.dtype)
数据类型对象是用来描述与数组对应的内存区域如何使用,具体几个方面
- 数据的类型(整数,浮点数或者 Python 对象)
- 数据的大小(例如, 整数使用多少个字节存储)
- 数据的字节顺序(小端法或大端法)
- 在结构化类型的情况下,字段的名称、每个字段的数据类型等
- 如果数据类型是子数组,它的形状和数据类型
可理解为N维数组item的相关元信息,因为item可以存储较复杂类型,元信息很必要。
NumPy数据类型(scalar types)
Python原生的整型和浮点型分别只有一种,在科学计算中显然是不够的,NumPy定义更丰富的数据类型,比如:
bool_
int_/int8/int16/int32/int64
uint8/uint16/uint32/uint64
float_/float16/float32/float64
complex_/complex64/complex128
...
有几点坑
关于bool_,由于Python中BooleanType不允许被继承,所以
The bool_ type is not a subclass of the int_ type (the bool_ is not even a number type). This is different than Python’s default implementation of bool as a sub-class of int.
关于int_
The int_ type does not inherit from the int built-in under Python 3, because type int is no longer a fixed-width integer type.
此外
The default data type in NumPy is float_.
常数
数学中遇到的一些常数,比如
np.Inf/np.NINF
np.e/np.pi
-
np.nan/np.NaN/np.NAN
(aliases) np.newaxis
ufunc
在N维数组上,element-wise操作,涵盖多数常见操作,详细列表见Universal functions (ufunc) 。
A universal function (or ufunc for short) is a function that operates on ndarrays in an element-by-element fashion. It is a “vectorized” wrapper for a function that takes a fixed number of specific inputs and produces a fixed number of specific outputs.
轴
NumPy里axes相关知识点有点tricky。比如二维数组中np.sum()
中指定axis
参数的情况
>>> a = np.array([[0,1], [2, 3]])
>>> np.sum(a, axis=0)
array([2, 4])
>>> np.sum(a, axis=1)
array([1, 5])
其中axis=0
总感觉跟直觉相反,但这样理解更顺一些
The way to understand the "axis" of numpy sum is it collapses the specified axis. So when it collapses the axis 0 (row), it becomes just one row and column-wise sum.
指定某个axis,就是沿着这个axis做相关操作。其中二维数组中两个axis的指向如下图
tool-np-axis-2d对一维数组,情况有点特殊,如下例子
>>> a = np.array([1,2])
>>> b = np.array([3,4])
>>> np.concatenate([a, b], axis=0)
array([1, 2, 3, 4])
并没有和二维数组那样,从上向下地操作,而是水平的,因为一维数组其axis=0
指向如下
>>> a = np.array([1,2])
>>> a.shape
(2,)
从一维数组的shape也能看出axis=0的指向。
广播
广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。比如当一个scalar与N维数组相加时,自动触发广播机制。
广播的原则很简单
- 让所有输入数组都向形状最长的数组看齐,形状中不足的通过在前面加1补齐
- 输出数组的形状是输入数组形状的各个维度上的最大值
- 如果输入数组的某个维度和输出数组的对应维度长度相同或其长度为1时,这个数组能计算出来,否则报错
- 当输入数组的某个维度的长度为1时,沿着此维度运算时用此维度的第一组值
几个数组可以广播到某一个shape,满足以下一个条件即可
- 数组拥有相同形状
- 当前维度的值相等
- 当前维度的值有一个是1
例子
If a.shape is (5,1), b.shape is (1,6), c.shape is (6,) and d.shape is () so that d is a scalar, then a, b, c, and d are all broadcastable to dimension (5,6); and
- a acts like a (5,6) array where a[:,0] is broadcast to the other columns,
- b acts like a (5,6) array where b[0,:] is broadcast to the other rows,
- c acts like a (1,6) array and therefore like a (5,6) array where c[:] is broadcast to every row, and finally,
- d acts like a (5,6) array where the single value is repeated.
如下示意图比较很清晰
tool-np-broadcasting