Numerical Python简称,高性能科学计算和数据分析的基础包。几乎所有高级工具的构建基础。部分公能如下:
-
ndarray
:一个具有矢量算数运算和复杂广播能力的快速且节省空间的多维数组; - 用于对整组数据进行快速运算的标准数学函数;
- 用于读写磁盘数据的工具以及用于操作内存映射文件的工具;
- 线性代数、随机数生成以及傅里叶变换功能;
- 用于集成
C
、C++
、Fortran
等语言编写的代码的工具。
np
本身并没有提供很高级的数据分析能力,理解numpy
数组以及面向数组的计算有助于更高效的使用类似pandas
的工具。
对于大部分数据分析应用而言,最关注的功能主要集中在:
- 用于数据整理、子集构造和过滤、转换等快速的矢量化数组运算;
- 常用的数组算法,如排序、唯一化、集合运算等;
- 高效的描述统计和数据聚合/摘要运算;
- 用于异构数据集的合并/连接运算的数据对齐和关系型数据运算;
- 讲条件逻辑表述为数组表达式(而不是带有if-elif-else分支的循环);
- 数据的分组运算(聚合、转换、函数应用等)。
NumPy的ndarray:一种多维数组对象
-
ndarray
对象可以对整块数据执行一些数学运算; - 通用的同构数据多维容器,即其中所有元素必须是相同类型的;
- 每个数组都有一个
shape
(一个表示各维度大小的元组),和一个dtype
(一个用于说明数组数据类型的对象)。
虽然大多数数据分析工作不需要深入理解numpy,但精通面向数组的编程和思维方式很关键。
创建ndarray:
- 使用
array
函数:它接受一切序列型的对象(包括数组),然后产生一个新的含有传入数据的NumPy
数组;嵌套序列(比如由一组等长列表组成的列表)将会被转换为一个多维数组(维度arr.ndim
,各维度arr.shape
);除非显示说明,np.array
会尝试为新建的这个数组推断出一个较为合适的数据类型,基本都是float64
浮点型(保存在arr.dtype
对象中); -
zeros
创建指定长度或形状的全0
数组,ones
创建全1
的数组:np.zeros(10)
np.zeros((3,6))
; -
empty
创建一个没有任何具体值的数组:np.empty((2, 3, 2))
返回一些未初始化的垃圾值而不是0
; -
arange
是Python内置函数range的数组版:np.arange(15)
; -
eye
、identity
:创建一个正方的N * N
矩阵(对角线为1,其余全为0)
ndarray的数据类型:
-
dtype
(data type)是一个特殊的对象,它含有ndarray
将一块内存解释为特定数据类型所需的信息;dtype
是numpy
如此强大和灵活的原因之一,多数情况下它们直接映射到相应的机器表示。 - 可以通过
astype
方法显式地转换其dtype:arr.astype(np.float64)
;调用astype
无论如何都会创建出一个新数组(==一份拷贝==),即使新dtype
和老dtype
相同也是如此;
数组和标量之间的运算:
数组可以使不编写循环即可对数据执行批量运算,者通常叫做矢量化。
大小相等的数组之间的任何算数运算都会将运算应用到元素级,数组与标量的算数运算也会应用到元素;
不同大小的数组之间的运算叫做广播(broadcasting)。
基本的索引和切片:
一维数组:
- 和Python差不多,
arr[5]
arr[5:8]
,当将一个标量赋值给一个切片时arr[5:8] = 12
该值会自动传播到整个选区; - 和列表不同的是,数组切片是原始数组的视图,数据不会被复制,修改直接反映到源数组上;
- 得到副本:
arr[5:8].copy()
;
高维数组:
- 在一个二维数组中,各索引位置上的元素不再是标量而是一维数组,因此可以对各个元素进行递归访问:
arr2d[0][2]和arr2d[0, 2]
等价; - 省略索引会返回一个维度低一点的
ndarray
,数组和标量都可赋值;
切片索引:
- 数组切片是沿着一个轴向选取元素的,可以一次传入多个切片:
arr2d[:2, 1:]
,但这样只能得到相同维数的数组视图; - 将整数索引和切片混合,可以得到低维度的切片:
arr2d[1, :2]
; - 对切片表达式的赋值操作也会扩散到整个选区;
布尔型索引:
-
names == 'Bob'
产生一个布尔型数组,可用于数组索引,且可以跟切片、整数混用,!=
&
|
通过布尔型索引选取数组中的数据,将总是创建数据的副本; - 将
data
中所有负值都设置为0
:data[data < 0] = 0
花式索引(Fancy indexing):
指利用整数数组进行索引。
- 以特定顺序选取行子集,传入一个指定顺序的整数列表或
ndarray
:arr[[4,3,0,6]]
,负数从末尾开始选取; - 一次传入多个索引数组会返回一个一维数组,其中的元素对应各个索引元组:
arr[[1,5,7,2],[0,3,1,2]]
选出的是元素(1,0)
、(5,3)
、(7,1)
、(2,2)
; - 花式索引和切片不一样,它总是将数据复制到新数组中;
数组转置(transpose)和轴对换:
- 转置是重塑的一种特殊形式,返回的是源数据的视图;
- 数组不仅有
transpose
方法,还有一个T
属性:arr.T
,在进行矩阵计算时,经常需要用到该操作; - 对于高维数组,
transpose
需要得到一个由轴编号组成的元组才能对这些轴进行转置:arr.transpose((1,0,2))
; - 还有
swapaxes
方法接受一对轴编号:arr.swapaxes(1,2)
;swapaxes
也是返回源数据的视图;
通用函数:快速的元素级数组函数
通用函数(ufunc
)是一种对ndarray
中的数据执行元素级运算的函数。
- 许多
ufunc
都是简单的元素级变体:如sqrt
和exp
,这些都是一元(unary)ufunc
; - 接受两个数组(如
add
,maximum
),二元ufunc
;
利用数组进行数据处理:
用数组表达式代替循环的做法,称作矢量化。比纯python方式快上一两个数量级。
将条件逻辑表达为数组运算:
numpy.where
函数是三元表达式 x if condition else y
的矢量化版本:
两个值数组xarr
和yarr
,一个布尔数组cond
,想要根据cond
中的值选取xarr
和yarr
的值,True
选xarr
,False
选yarr
,
- 列表推导式写法:
result = [(x if c else y) for x,y,c in zip(xarr,yarr,cond)]
-
numpy
写法:
result = np.where(cond, xarr, yarr)
数学和统计方法:
可以通过数组上的一组数学函数对整个数组或某个轴向的数据进行统计计算。
-
sum
、mean
以及标准差std
等聚合计算(aggregation,通常叫做约简reduction)既可以当做数组的实例方法调用:arr.mean()
,也可以当做顶级numpy
函数使用:np.mean(arr)
;
mean
和sum
这类的函数可以接受一个axis
参数(用于计算该轴向上的统计值),结果是一个少一维的数组:arr.mean(axis=1)
; - 其他如
cumsum
(累计和)和cumprod
(累计积)之类的方法则不聚合,而是产生一个由中间结果组成的数组;
用于布尔型数组的方法:
在以上方法中,布尔值会被强制转换成 1(True)
和 0(False)
。
-
sum
常被用来对布尔型数组中的True
计数:(arr > 0).sum()
;
bools = np.arry([False, False, True, False])
-
any
用于检测数组中是否存在一个或多个True
:bools.any()
; -
all
用于检查数组中所有值是否都是True
:bools.all()
;
以上两个方法也可用于非布尔型数组,所有0
元素都会被当做False
。
排序:
-
sort
方法就地排序:arr.sort()
, - 多维数组可以再任何一个轴向上排序,将轴编号传给
sort
:arr.sort(1)
; -
np.sort
返回的是数组的已排序副本,而就地排序则会修改数组本身。
唯一化以及其他的集合逻辑:
numpy
提供了一些针对一维ndarray
的基本集合运算。
- 最常用的
np.unique()
,用于找出数组中的唯一值并返回已排序的结果:
In [2]: names = np.array(['Bob', 'Joe', 'Will', 'Joe', 'Joe'])
In [3]: np.unique(names)
Out[3]:
array(['Bob', 'Joe', 'Will'],
dtype='<U4')
np.in1d()用于测试一个数组中的值在另一个数组中的成员资格:
In [4]: values = np.array([6, 0, 0, 3, 2, 5, 6])
In [5]: np.in1d(values, [2, 3, 6])
Out[5]: array([ True, False, False, True, True, False, True], dtype=bool)
用于数组的文件输入输出
numpy
能够读写磁盘上的文本数据或二进制数据。
将数组以二进制格式保存到磁盘:
np.save
和np.load
是读写磁盘数组数据的两个主要函数,默认情况下数组是以未压缩的原始二进制格式保存在扩展名为.npy
的文件中的:
In [6]: arr = np.arange(10)
In [7]: np.save('some_array', arr)
In [8]: np.load('some_array.npy')
Out[8]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 通过np.savez可以将多个数组保存到一个压缩文件中,将数组以关键字参数形式传入:
In [9]: np.savez('array_archive.npz', a=arr, b=arr)
# 加载.npz文件时,会得到一个类似字典的对象,对各个数组进行延迟加载:
In [10]: arch = np.load('array_archive.npz')
In [11]: arch['a']
Out[11]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [12]: arch['b']
Out[12]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
存取文本文件:
- 以某种分隔符加载文本文件:
arr = np.loadtxt('array_ex.txt', delimiter=','')
; - 将数组写到以某种分隔符隔开的文本文件中:
np.savetxt(arr, delimiter=',')
.
线性代数:
线性代数(矩阵乘法、矩阵分解、行列式及其他方阵数学)是任何数组库的重要组成部分。
-
nump
y提供了一个用于矩阵乘法(点积)的dot
函数(既是一个数组方法也是numpy
命名空间中的一个函数):
In [13]: x = np.array([[1.,2.,3.],[4.,5.,6.]])
In [14]: y = np.array([[6.,23.],[-1,7],[8,9]])
In [15]: x.dot(y)
Out[15]:
array([[ 28., 64.],
[ 67., 181.]])
In [16]: np.dot(x, y)
Out[16]:
array([[ 28., 64.],
[ 67., 181.]])
numpylinalg中有一组标准的矩阵分解运算以及诸如求逆和行列式之类的东西。
随机数生成:
numpy.random
模块对python内置的random
进行了补充,增加了一些用于高效生成多种概率分布的样本值的函数。
python内置random
模块一次只能生成一个样本值,numpy.random
模块可以产生大量样本值。