【数据分析】第三章 numpy(1)
NumPy不仅是大量Python数学和科学计算包的基石,连我们后续将要详细学习的pandas库也正是基于NumPy构建的。相较于Python标准库内置的工具,NumPy为数据分析方面的大多数计算提供了更强大、更高效的支持。
3.1 NumPy 简史
NumPy的诞生源于Python语言发展初期对数值计算日益增长的需求,尤其是在科学计算领域的广泛应用。
-
1995年: Jim Hugunin开发了Numeric,这是Python在科学计算领域的首次尝试。
-
随后: 又诞生了Numarray包。Numeric和Numarray都专注于数组计算,但各有侧重。开发者们常常需要根据不同的使用场景来选择更高效的包,这种不明确的选择性促使了将两者整合为一个统一库的想法。
-
2006年: Travis Oliphant着手开发NumPy库,并于2006年发布了它的第一个版本(v1.0)。
自此,NumPy成为了Python科学计算领域一个至关重要的扩展包。如今,它在处理多维数组和大型数组方面应用最为广泛。此外,NumPy还提供了大量高效的函数,能够对数组进行操作,并实现高级数学运算。
目前,NumPy是一个开源项目,采用BSD许可证,并在全球众多开发者的共同支持下持续发展,其潜力正被不断发掘。
3.2 NumPy 安装
通常情况下,大多数Python发行版(如Anaconda)都会将NumPy作为基础包预装。然而,如果你的环境中NumPy未被预装,你可以根据自己的操作系统类型进行手动安装:
-
Linux系统 (Ubuntu 和 Debian):
sudo apt-get install python3-numpy
(注意:对于Python 3,包名通常是
python3-numpy
。) -
Linux 系统 (Fedora):
sudo dnf install numpy scipy
(注意:
yum
在较新的Fedora版本中已被dnf
取代,且通常与scipy
一同安装。) -
使用Anaconda发行版的Windows/macOS/Linux 系统:
conda install numpy
当NumPy成功安装到你的系统后,你可以在Python交互式会话或脚本中通过以下代码导入NumPy模块:
>>> import numpy as np
我们通常使用np
作为NumPy的别名,这是一种约定俗成的做法,方便我们后续的代码编写。
3.3 ndarray: NumPy库的心脏
整个NumPy库的核心是它的ndarray(N-dimensional array,N维数组)对象。ndarray
是一种由同质元素组成的多维数组,其元素数量在创建时即已确定。所谓“同质”,指的是数组中的所有元素都具有相同的类型和大小。事实上,数据类型由另一个NumPy对象——dtype(data-type,数据类型)来指定;每个ndarray
对象只允许拥有一种dtype
类型。
数组的维度和元素数量由数组的型(shape)来确定。数组的型由N个正整数组成的元组来指定,元组的每个元素对应每一维的大小。数组的各个维度统称为轴(axes),轴的数量则被称为秩(rank)。
NumPy数组的另一个重要特性是其固定大小。这意味着一旦数组创建并指定了大小,其大小就不会再发生改变。这与Python的内置列表有所不同,Python列表的大小是可变的。
定义ndarray
最简单的方式是使用array()
函数,并将Python列表作为参数传入,列表中的元素将成为ndarray
的元素。
>>> a = np.array([1, 2, 3])
>>> a
array([1, 2, 3])
检测新创建的对象是否是ndarray
非常简单,只需将新声明的变量传递给type()
函数即可。
>>> type(a)
<class 'numpy.ndarray'>
调用变量的dtype
属性,即可获知新建的ndarray
属于哪种数据类型。
>>> a.dtype
dtype('int64')
# 在64位系统中,默认整数类型通常是int64
我们刚创建的这个数组只有一个轴,因此它的秩为1,型为(3,)
。这些值的获取方法如下:轴数量使用ndim
属性,数组长度使用size
属性,而数组的型则用shape
属性。
>>> a.ndim
1
>>> a.size
3
>>> a.shape
(3,)
你刚刚看到的这个数组是最简单的一维数组。但是,数组可以非常容易地扩展成多维。例如,我们可以定义一个2x2的二维数组:
>>> b = np.array([[1.3, 2.4], [0.3, 4.1]])
>>> b.dtype
dtype('float64')
>>> b.ndim
2
>>> b.size
4
>>> b.shape
(2, 2)
这个数组有两条轴,所以秩为2,每条轴的长度都是2。
ndarray
对象还拥有另一个重要的属性叫做itemsize
。它定义了数组中每个元素的长度(以字节为单位)。data
属性则表示包含数组实际元素的缓冲区。data
属性在实际操作中用得并不多,因为要获取数组中的元素,我们通常会使用接下来几节将学到的索引方法。
>>> b.itemsize
8 # 因为float64占用8个字节
>>> b.data
<memory at 0x...> # 这里的地址会根据你运行时的内存地址而变化,表示一个内存视图
3.3.1 创建数组
数组的创建方法有多种,最常用且最简单的方式就是前面我们已经见过的,使用array()
函数,其参数可以是单层或嵌套的Python列表。
>>> C = np.array([[1, 2, 3], [4, 5, 6]])
>>> C
array([[1, 2, 3],[4, 5, 6]])
除了列表,array()
函数还可以接收嵌套元组或元组列表作为参数。
>>> d = np.array(((1, 2, 3), (4, 5, 6)))
>>> d
array([[1, 2, 3],[4, 5, 6]])
此外,参数也可以是由元组或列表混合组成的列表,其效果是相同的。
>>> e = np.array([(1, 2, 3), [4, 5, 6], (7, 8, 9)])
>>> e
array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
3.3.2 数据类型
到目前为止,我们只使用过简单的整型和浮点型数据类型。实际上,NumPy数组能够包含多种复杂的数据类型(参见表3-1)。例如,可以使用字符串类型:
>>> g = np.array([['a', 'b'], ['c', 'd']])
>>> g
array([['a', 'b'],['c', 'd']], dtype='<U1') # '<U1' 表示Unicode字符串,长度为1
>>> g.dtype
dtype('<U1')
&g