NumPy(Numerical Python的简称)是高性能科学计算和数据分析的基础包。它是本书所介绍的几乎所有高级工具的构建基础。其部分功能如下
- ndarray, 一个具有矢量算数运算和复杂广播能力的快速且节省空间的多维数组
- 用于对证书数据进行快速运算的标准数学函数(无需编写循环)
- 用于读写磁盘数据的工具以及用于操作内存映射文件的工具
- 线性代数、随机数生成以及傅里叶变换工具
- 用于集成由C、C++、Fortran等语言编写的代码的工具
从生态的角度。由于NumPy提供一个简单易用的API,因此很容易将数据传递给低级语言编写的外部库,外部库也能以NumPy数组的形式将数据返回给Python
NumPy本身并没有提供多么高级的数据分析功能,理解NumPy数组以及面向数组的计算将有助于你更高效地使用诸如Pandas之类的工具
内容提要
- NumPy的ndarray:一种多维数组对象
- 创建ndarray
- ndarray的数据类型
- 数组和标量之间的运算
- 基本的索引和切片
- 一维
- 高维
- 布尔型索引
- 花式索引
- 数组转置和轴对换
- 调用函数:快速的元素级数组函数
- 利用数组进行数据处理
- 将条件逻辑表述为数组运算
- 数学和统计方法
- 用于布尔型数组的方法
- 排序
- 唯一化以及其他的集合逻辑
- 用于数组的文件输入输出
- 线性代数
- 随机数生成
NumPy的ndarray:一种多维数组对象
ndarray是一种通用的同构数据多维容器,也就是说,其中的所有元素必须是相同类型的。每个数组都有一个shape(一个表示各维度大小的元组)和一个dtype(一个用于说明数组数据类型的对象):
In[26]: data.shape
Out[26]: (10,)
In[28]: data.dtype
Out[28]: dtype('int32')
这里的data其实是一个比较特殊的秩一矩阵,这跟一般的矩阵有所不同,这里不详细介绍。
虽然大多数数据分析工作不需要深入理解NumPy,但是精通面向数组的编程和思维方式是成为Python科学计算牛人的一大关键步骤
创建ndarray
最简单的方法是使用array函数,它接受一切序列型的对象(包括其他数组),然后产生一个新的包含传入数据的NumPy数组,如下
In[28]: adata1 = [6,7,8,9,10.5]
In[29]: aarr1 = np.array(data1)
In[32]: arr1
Out[32]: array([ 6. , 7. , 8. , 9. , 10.5])
嵌套序列将会被转化为一个多维数组
In[33]: data2 = [[1,2,3,4],[5,6,7,8]]
In[34]: arr2 = np.array(data2)
In[35]: arr2
Out[35]:
array([[1, 2, 3, 4],
[5, 6, 7, 8]])
除非显式说明,np.array会尝试为新建的这个数据推断出一个较为合适的数据类型,这个类型保存在dtype中,如下
arr1.dtype
Out[37]: dtype('float64')
arr2.dtype
Out[38]: dtype('int32')
除此之外,还可以通过一些函数来创建数组,比如,zeros和ones分别可以创建指定长度或形状的全0或全1数组。empty可以创建一个没有任何具体值的数组
In[41] np.zeros(10)
Out[41]: array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
In[42] np.zeros((3,6))
Out[42]:
array([[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.]])
In[43] np.empty((2,3,2))
Out[43]:
array([[[ 8.67740622e-312, 3.16202013e-322],
[ 0.00000000e+000, 0.00000000e+000],
[ 0.00000000e+000, 7.40907173e-038]],
[[ 5.28802037e+174, 8.76294657e+169],
[ 2.02340708e-052, 7.49431806e-067],
[ 8.39356861e+165, 1.86924407e-051]]])
很多情况下,np.empty返回的都是一些未初始化的垃圾值
此外,eye也可以创建N × × N的单位矩阵
ndarray的数据类型
arr1 = np.array([1,2,3], dtype=np.float64)
arr2 = np.array([1,2,3], dtype=np.int32)
In[46]: arr1.dtype
Out[46]: dtype('float64')
In[47]: arr2.dtype
Out[47]: dtype('int32')
dtype是NumPy如此强大和灵活的原因之一。多数情况下,它们直接映射到相应的机器表示,这使得“读写磁盘上的二进制数据流”以及“集成低级语言代码(如C、Frortran)”等工作变得更加简单
数值型dtype的命名方式相同:一个类型名(如float或int),后面跟一个用于表示各元素位长的数字
- int8, uint8
- int16, uint16
- …
- float16
- float32
- …
- bool
通过ndarray的astype方式显式地转换其type:
arr = np.array([1,2,3,4,5])
arr.dtype
Out[49]: dtype('int32')
float_arr = arr.astype(np.float64)
float_arr.dtype
Out[51]: dtype('float64')
神奇的是,使用astype也可以完成从字符串到浮点数等的转换,就可以在操作文件时很方便地将字符串变成数字,用于下一步处理
numeric_strings = np.array(['1.32','323','1.2'], dtype=np.string_)
numeric_strings
Out[4]:
array([b'1.32', b'323', b'1.2'],
dtype='|S4')
注意,调用astype无论如何都会创建出一个新的数组,即使它跟原来的数组完全一样也是如此
数组和标量之间的运算
数组很重要,因为它使你不用编写循环即可对数据执行批量运算。这通常叫矢量化(Vectorization)
- 大小相同的数组之间的任何算数运算都将应用到元素级
- 同样,数组与标量之间的算数运算也会将那个标量值传播到各个元素(broadcasting)
arr = np.array([[1,2,3],[4,5,6]])
arr
Out[8]:
array([[1, 2, 3],
[4, 5, 6]])
arr*arr
Out[9]:
array([[ 1, 4, 9],
[16, 25, 36]])
1/arr
Out[10]:
array([[ 1. , 0.5 , 0.33333333],
[ 0.25 , 0.2 , 0.16666667]])
arr*0.5
Out[11]:
array([[ 0.5, 1. , 1.5],
[ 2. , 2.5, 3. ]])
基本的索引和切片
1)一维数据
先建立一个ndarray
arr = np.arange(10)
arr
Out[17]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
NumPy的索引功能在表面上看跟Python的列表功能差不多
arr[5]
Out[18]: 5
arr[5:8]
Out[19]: array([5, 6, 7])
arr[5:8]=12
arr
Out[21]: array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
当你将一个标量值赋值给一个切片时(如arr [ 5 : 8 ] = 12),该值会自动传播到整个选区。跟列表最重要的一个区别在于,数组切片时原始数组的视图。这意味着数据不会被复制,视图上的任何修改都会直接反映到源数组上:
arr_slice = arr[