前言:
NumPy(Numerical Python)是Python中用于科学计算的基础库之一,它提供了高性能的多维数组对象以及这些数组的操作。NumPy数组是Python中列表(List)的扩展,但它提供了更加高效的数据结构以及大量的数学函数库。使用NumPy,你可以执行大量的数学和科学计算,而不需要编写复杂的循环。
一、历史进程
1995年:当时Python中存在着一个名为Numerix的库,它作为操作基础数据对象的库而设计,但功能相对较弱,并未在Python社区中引起广泛关注。
2001年:SciPy库诞生,这是一个专为科学计算而设计的库。然而,在SciPy的创建过程中,开发者意识到它缺乏一个高效的基础数据结构操作库来支持其复杂的科学计算功能。
2005年:为了解决这一问题,SciPy的开发者决定结合Numerix的设计思想和SciPy的部分方法,创建一个新的库来专门处理基础数据结构的操作。于是,Travis Oliphant在Numeric(Numerix的后续版本)和另一个同性质的程序库Numarray的基础上,结合了自己的扩展,开发了NumPy。
NumPy自诞生以来就是开放源代码的,并由许多协作者共同维护和发展。它的代码大部分是用C语言编写的,这使得它在执行数值计算时非常高效。NumPy的核心功能包括提供一个强大的N维数组对象ndarray,支持大量的维度数组与矩阵运算,以及一系列数学函数库,这些函数库可以对数组进行各种复杂的数学运算。
科学计算与数据分析:NumPy在数据分析、科学计算、机器学习等领域都有广泛的应用。它是Python中进行数值计算的基础库之一,也是许多其他科学计算库(如SciPy、Pandas等)的基础。
二、安装
安装NumPy最简单的方法就是使用pip
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
from numpy import *
print(eye(3))
'''
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
'''
三、Ndarray对象
NumPy的Ndarray(N-dimensional array,N维数组)对象是NumPy库的核心。它提供了一种高效的方式来存储和操作大型多维数组和矩阵,以及执行数学运算。与Python的内置列表(list)相比,Ndarray提供了更高的性能,因为Ndarray中的元素在内存中是连续存储的,并且它们都是相同类型的。
3.1、主要特点
-
固定类型:
ndarray
中的元素必须都是同一类型的。这意味着一旦创建了数组,就不能在数组中存储不同类型的数据。 -
连续内存:数组的元素在内存中连续存储,这有助于快速访问和计算。
-
维度:
ndarray
可以是任意维度的。例如,一维数组类似于Python的列表,二维数组类似于数学中的矩阵,而更高维度的数组可以用于表示更复杂的数据结构。 -
大小:每个维度的大小(即该维度上的元素数量)在创建数组时确定,并且在数组的生命周期内保持不变。
-
广播:NumPy的广播功能允许不同形状的数组在执行算术运算时自动调整形状,前提是这些形状是“兼容”的。
'''
numpy.array(object, dtype=None, copy=True, order=None, subok=False, ndmin=0)
参数:
dtype:数组元素的数据类型,可选
copy:对象是否需要复制,可选
order:创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
subok:默认返回一个与基类类型一致的数组
ndmin:指定生成数组的最小维度
'''
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
print(arr) # [1 2 3 4 5]
3.2、属性
import numpy as np
arr = np.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]])
'''
[[1 2 3 4]
[1 2 3 4]
[1 2 3 4]]
'''
属性 | 描述 |
---|---|
ndim | 数组的秩(rank),即数组的维度数量或轴的数量。 |
在NumPy中,数组的维数(dimension)通常被称为数组的秩(rank)。数组的秩是其轴(axis)的数量,或者说是构成数组所需要的独立维度数。
- 一维数组(例如,列表的NumPy版本)的秩为1。它只有一个轴,即沿着这个轴可以遍历数组的所有元素。
- 二维数组(例如,矩阵)的秩为2。它有两个轴:第一个轴沿着行方向,第二个轴沿着列方向。
- 三维数组的秩为3,依此类推,更高维的数组有更高的秩。
print(arr.ndim) # 2,2维
属性 | 描述 |
---|---|
shape | 数组的维度,表示数组在每个轴上的大小。对于二维数组(矩阵),表示其行数和列数。 |
size | 数组中元素的总个数 |
data | 实际存储数组元素的缓冲区,一般通过索引访问元素,不直接使用该属性。 |
dtype | 数组中元素的数据类型 |
itemsize | 数组中每个元素的大小,以字节为单位。 |
print(arr.shape) # (3, 4),3行4列
print(arr.size) # 12,3*4=12,12个元素
print(arr.dtype) # 数据类型是int32
print(arr.data) # 实际存储数组元素的缓冲区:<memory at 0x000001CB86730380>
print(arr.itemsize) # 4个字节
属性 | 描述 |
---|---|
flags | 包含有关内存布局的信息,如是否为 C 或 Fortran 连续存储,是否为只读等。 |
print(arr.flags)
'''
内存布局的信息:
C_CONTIGUOUS : True,数据是在一个单一的C风格的连续段中
F_CONTIGUOUS : False,数据是在一个单一的Fortran风格的连续段中
OWNDATA : True,数组拥有它所使用的内存或从另一个对象中借用它
WRITEABLE : True,数据区域可以被写入,将该值设置为 False,则数据为只读
ALIGNED : True,数据和所有元素都适当地对齐到硬件上
WRITEBACKIFCOPY : False,
这个数组是其它数组的一个副本,当这个数组被释放时,原数组的内容将被更新
'''
四、数据类型
4.1、整数类型
名称 | 描述 |
---|---|
np.int8(16、32、64) | 8(16、32、64)位有符号整数 |
np.uint8(16、32、64) | 8(16、32、64)位有符号整数 |
arr_int32 = np.array([1, 2, 3, 4], dtype=np.int32)
print(arr_int32) # [1 2 3 4]
4.2、浮点数类型
名称 | 描述 |
---|---|
np.float16 | 半精度浮点数 |
np.float32 | 单精度浮点数 |
np.float64 | 双精度浮点数 |
arr_float64 = np.array([1.1, 2.2, 3.3, 4.4], dtype=np.float64)
print(arr_float64) # [1.1 2.2 3.3 4.4]
4.3、复数类型
名称 | 描述 |
---|---|
np.complex64 | 由两个32位浮点数表示的复数(实部和虚部) |
np.complex128 | 由两个64位浮点数表示的复数(实部和虚部) |
arr_complex = np.array([1, 2, 3], dtype=complex)
print(arr_complex) # [1.+0.j 2.+0.j 3.+0.j]
4.4、布尔类型
名称 | 描述 |
---|---|
np.bool_ | 布尔类型(True 或 False),在 NumPy 中,布尔类型实际上是使用整数 0 和 1 来表示的 |
arr_bool = np.array([True, False, True, False], dtype=np.bool_)
print(arr_bool) # [ True False True False]
4.5、其他类型
名称 | 描述 |
---|---|
np.object_ | Python 对象类型,可以存储任何 Python 对象 |
np.string_ | 已弃用 |
五、数组创建方法
5.1、numpy.empty(创建一个未初始化的数组)
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选 |
order | 有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序 |
import numpy as np
arr = np.empty([3, 3], dtype=int, order='C')
print(arr)
'''
[[4128860 6029375 3801156]
[7340124 7602297 7274600]
[6029422 6881388 98]]
'''
5.2、numpy.zeros(创建指定大小的数组,数组元素以0来填充)
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选,(默认浮点数) |
order | 有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序 |
import numpy as np
# 默认为浮点数
arr = np.zeros(5)
print(arr) # [0. 0. 0. 0. 0.]
5.3、numpy.ones(创建指定形状的数组,数组元素以1来填充)
参数 | 描述 |
---|---|
shape | 数组形状 |
dtype | 数据类型,可选,(默认浮点数) |
order | 有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序 |
import numpy as np
# 默认为浮点数
arr = np.ones(5)
print(arr) # [1. 1. 1. 1. 1.]
5.4、numpy.zeros_like(创建一个与给定数组具有相同形状的数组,数组元素以0来填充)
参数 | 描述 |
---|---|
a | 要创建相同形状的数组 |
dtype | 数据类型 |
order | 有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序 |
subok | 是否允许返回子类,如果为 True,则返回一个子类对象,否则返回一个与 a 数组具有相同数据类型和存储顺序的数组 |
shape | 创建的数组的形状,如果不指定,则默认为 a 数组的形状 |
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
zeros_arr = np.zeros_like(arr)
print(zeros_arr) # [[0 0 0],[0 0 0],[0 0 0]]
5.5、numpy.ones_like(创建一个与给定数组具有相同形状的数组,数组元素以1来填充)
参数 | 描述 |
---|---|
a | 要创建相同形状的数组 |
dtype | 数据类型 |
order | 有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序 |
subok | 是否允许返回子类,如果为 True,则返回一个子类对象,否则返回一个与 a 数组具有相同数据类型和存储顺序的数组 |
shape | 创建的数组的形状,如果不指定,则默认为 a 数组的形状 |
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
ones_arr = np.ones_like(arr)
print(ones_arr) # [[1 1 1],[1 1 1],[1 1 1]]
5.6、numpy.asarray
参数 | 描述 |
---|---|
a | 任意形式的输入参数,可以是,列表, 列表的元组, 元组, 元组的元组, 元组的列表,多维数组 |
dtype | 数据类型,可选 |
order | 有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序 |
import numpy as np
arr = np.asarray((1, 2, 3))
print(arr) # [1 2 3]
5.7、numpy.arange
参数 | 描述 |
---|---|
start | 起始值,默认为0 |
stop | 终止值(不包含) |
step | 步长,默认为1 |
dtype | 返回ndarray 的数据类型,如果没有提供,则会使用输入数据的类型 |
import numpy as np
arr = np.arange(0, 5, 2)
print(arr) # [0 2 4]
5.8、numpy.linspace(创建一个一维数组,数组是一个等差数列构成)
参数 | 描述 |
---|---|
start | 起始值 |
stop | 终止值,如果endpoint 为true ,该值包含于数列中 |
num | 生成的等步长的样本数量,默认为50 |
endpoint | 值为 true 时,数列中包含stop 值,反之不包含,默认是True |
retstep | 如果为 True 时,生成的数组中会显示间距,反之不显示 |
dtype | 数据类型 |
import numpy as np
arr = np.linspace(1, 11, 5, endpoint=False)
print(arr) # [1. 3. 5. 7. 9.]
5.9、numpy.logspace
参数 | 描述 |
---|---|
start | 起始值为:base的start次幂 |
stop | 终止值为:base的stop次幂,如果endpoint 为true ,该值包含于数列中 |
num | 生成的等步长的样本数量,默认为50 |
endpoint | 值为 true 时,数列中中包含stop 值,反之不包含,默认是True |
base | 对数 log 的底数 |
dtype | 数据类型 |
import numpy as np
arr = np.logspace(0, 3, 4, base=2)
print(arr) # [1. 2. 4. 8.]
六、切片和索引
6.1、切片对象可以通过内置的 slice 函数,并设置 start, stop 及 step 参数进行,从原数组中切割出一个新数组。
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr[slice(0, 1, 1)]) # [[1 2 3]]
print(arr[0:1]) # [[1 2 3]]
'''
切片还可以包括省略号 …,
来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的 ndarray。
'''
print(arr[0, ...]) # [1 2 3],第一行
print(arr[..., 0]) # [2 5 8],第一列
6.2、整数数组索引(花式索引)
使用一个数组来访问另一个数组的元素。这个数组中的每个元素都是目标数组中某个维度上的索引值。例如:[行,列]
import numpy as np
arr = np.array([[1, 2], [3, 4], [5, 6]])
arry = arr[0, 1] # 2
arru = arr[[0, 1, 2], [1, 1, 1]] # [2 4 6]
arr_ = arr[[-1, -2]] # [[5 6] [3 4]]
6.3、布尔索引
可以通过一个布尔数组来索引目标数组。布尔索引通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。
import numpy as np
arr = np.array([[1, 2], [3, 4], [5, 6]])
'''
arr > 3
[[False False]
[False True]
[ True True]]
'''
arr = arr[arr > 3] # [4 5 6]
'''~(取补运算符)来过滤 NaN'''
arr = np.array([[np.nan, 1, 2, np.nan], [1, 12, 2, np.nan]])
'''
arr
[[nan 1. 2. nan]
[ 1. 12. 2. nan]]
~np.isnan(arr)
[[False True True False]
[ True True True False]]
'''
arr = arr[~np.isnan(arr)] # [ 1. 2. 1. 12. 2.]
七、广播(Broadcast)
广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。
广播规则:
-
如果所有输入数组的维度数不相同,形状较小的数组会在前面补1,直到所有数组的形状具有相同的维度数。 这意味着,如果一个数组是标量(可以认为它是0维的),那么它的形状会被视为(1,),如果是一维数组,它的形状会被视为(n,),以此类推。
-
从后往前比较每一维的大小,如果相等,或者其中一个数组在该维度的大小为1,则符合广播规则,可以进行运算。 如果不满足这个条件,则抛出错误,说明数组的形状不兼容,无法进行广播。
-
广播会在所有大小为1的维度上进行,生成一个足够大的数组,以满足所有输入数组的形状要求。
import numpy as np
arra = np.array([[1], [2], [3], [4]]) # 形状为 (4, 1)
arrb = np.array([1, 2, 3, 4]) # 形状为 (4,)
'''
arra
[[1 1 1 1]
[2 2 2 2]
[3 3 3 3]
[4 4 4 4]]
arrb
[[1 2 3 4]
[1 2 3 4]
[1 2 3 4]
[1 2 3 4]]
arrc
[[2 3 4 5]
[3 4 5 6]
[4 5 6 7]
[5 6 7 8]]
'''
arrc = arra + arrb # 形状为 (4,4)
注意:
- 广播通常用于向量化和减少循环的需要,使得代码更加简洁和高效。
- 广播并不改变原始数组的形状或数据,而是生成一个新的数组作为结果。
- 并非所有形状的数组都能进行广播。如果它们的形状不满足广播规则,则会引发错误。
八、数组形状方法
8.1、numpy.reshape
方法 | 描述 |
---|---|
reshape() | 在不改变数据的情况下改变数组的形状 |
'''
numpy.reshape(arr, newshape, order='C')
参数:
arr:要修改形状的数组
newshape:整数或者整数数组,新的形状应当兼容原有形状
order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'k' -- 元素在内存中的出现顺序
'''
import numpy as np
arr = np.arange(8)
arra = arr.reshape(2, 4)
'''
[[0 1 2 3]
[4 5 6 7]]
'''
8.2、numpy.flatten()
方法 | 描述 |
---|---|
flatten() | 将数组展平为一维数组 |
'''
numpy.flatten(arr, order='C')
参数:
arr:要修改形状的数组
order:{‘C’, ‘F’, ‘A’, ‘K’},可选
‘C’ 表示以行优先(C-style)顺序进行展平,
即先沿着最内层(最后一个轴)展平,
然后沿着倒数第二个轴展平,
依此类推,直到最外层。
‘F’ 表示以列优先(Fortran-style)顺序进行展平,
即先沿着最外层展平,
然后沿着倒数第二层展平,
依此类推,直到最内层。
‘A’ 表示如果 a 是 Fortran 数组,
则以列优先顺序展平,
否则以行优先顺序展平。
‘K’ 表示按照在内存中的顺序展平,
但会保持元素在内存中的顺序。
这实际上会保留数组的“C”或“F”展平顺序,
具体取决于它是如何被创建的。
'''
import numpy as np
arr_3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
flat_arr_3d = arr_3d.flatten() # [1 2 3 4 5 6 7 8]
总结:
NumPy 官网:http://www.numpy.org/
NumPy 源代码:https://github.com/numpy/numpy