NumPy的前身是Numeric。Numeric最早发布于1995年,如今已经废弃了。由于种种原因,不
管是Numeric还是NumPy,都没能进入Python标准库,不过单独安装NumPy也很方便。
为什么使用numpy
对于同样的数值计算任务,使用NumPy要比直接编写Python代码便捷得多。这是因为NumPy
能够直接对数组和矩阵进行操作,可以省略很多循环语句,其众多的数学函数也会让编写代码的
工作轻松许多。
NumPy的底层算法在设计时就有着优异的性能,并且经受住了时间的考验。
NumPy中数组的存储效率和输入输出性能均远远优于Python中等价的基本数据结构(如嵌套
的list容器)。其能够提升的性能是与数组中元素的数目成比例的。对于大型数组的运算,使用
NumPy的确很有优势。对于TB级的大文件,NumPy使用内存映射文件来处理,以达到最优的数
据读写性能。
不过,NumPy数组的通用性不及Python提供的list容器,这是其不足之处。因此在科
学计算之外的领域,NumPy的优势也就不那么明显了。
NumPy的大部分代码都是用C语言写成的,这使得NumPy比纯Python代码高效得多。NumPy
同样支持C语言的API,并且允许在C源代码上做更多的功能拓展。
numpy有那些功能?
多维数组对象:ndarray,是 NumPy 中最重要的类,提供了高效的数值运算、广播(broadcasting)功能以及灵活的索引方式等功能。
通用函数:ufunc,是一种对ndarray中的数据执行元素级运算的函数,支持矢量化计算,即对数组中的每个元素进行操作,比起纯Python实现的循环计算,运算速度更快。
数据类型和类型转换:NumPy 支持更多的数据类型比 Python 自带的数据类型,如浮点型、整型、布尔型、复数型等,此外,NumPy 还支持用户自定义数据类型。
数学函数库:NumPy 包括了大量的数学函数库,如傅里叶变换、随机数生成、线性代数运算、傅里叶变换、数学常数等。
索引、切片和迭代:NumPy 提供了灵活的索引方式,可以使用整数、切片以及布尔值索引、花式索引、混合索引等方式,方便地对多维数组进行切片和迭代。
广播:NumPy 支持广播(broadcasting),即对不同形状的数组进行算术运算的能力。
输入输出:NumPy 提供了一些文件输入和输出的函数,如读写磁盘上的文本文件和二进制文件。
线性代数:NumPy 提供了线性代数函数库,可以实现向量和矩阵的操作,如求解线性方程组、求逆矩阵、特征值分解、奇异值分解等。
安装
笔者这里使用的JupyterLab
执行
1 | pip install numpy |
完事后可以测试下
1 | from numpy import * |
如何可以正常输出下面的数组应该就安装完成了。
核心概念-ndarray
多维数组,我们后面的学习基本上就是围绕他来。
如何创建一个ndarray?
arange 首先就是我们前面看到的arange函数,这个函数将创建从0到我们传参的序列数组
1
2
3
4arange(20)
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])array 直接列举数组元素
1
2
3array([2,3,5,6])
array([2, 3, 5, 6])zeros 给出指定长度的数组,元素全部是0
1
2
3zeros(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])ones给出指定长度的数组,元素全部是1
1
2
3ones(10)
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])empty生成随机值
1
2
3
4empty(5)
array([4.66227277e-310, 0.00000000e+000, 4.66297182e-310, 4.66297181e-310,
2.37151510e-322])eye 创建矩阵,对角线元素是1,其他是0
1
2
3
4
5
6eye(4)
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]])
多维数组也是一样创建
1 | array([[2,3,4],[4,5,7]]) |
也可以使用reshape将现有的一维数组改变形状,注意这里reshape接受若干参数,这些参数要求乘积等于原数组的长度。
1 | arange(30).reshape(2,3,5) |
这样原来的0-29就被分为了三维的数组
ndarray的数据类型
如何查看ndarray的数据类型呢?ndarray包含dtype变量,比如我们查看前面的eye(4)的dtype
1 | eye(4).dtype |
都有那些dtype呢?
- bool用一位存储的布尔类型(值为TRUE或FALSE)
- inti由所在平台决定其精度的整数(一般为int32或int64)
- int8整数,范围为-128至127
- int16整数,范围为-32768至32767
- int32整数,范围为2^31至2^31-1
- int64整数,范围为-2^63至2^63-1
- uint8无符号整数,范围为0至255
- uint16无符号整数,范围为0至65535
- uint32无符号整数,范围为0至2^32-1
- uint64无符号整数,范围为0至2^64-1
- float16半精度浮点数(16位):其中用1位表示正负号,5位表示指数,10位表示尾数
- float32单精度浮点数(32位):其中用1位表示正负号,8位表示指数,23位表示尾数
- float64或float双精度浮点数(64位):其中用1位表示正负号,11位表示指数,52位表示尾数
- complex64复数,分别用两个32位浮点数表示实部和虚部
- complex128或complex复数,分别用两个64位浮点数表示实部和虚部
实际上我们可以在创建ndarray时指定 数据类型
1 | array([2,3,4],dtype=int16) |
ndarray的内存占用
1 | a=eye(10) |
可以查看单个元素的占用空间。
如果想要查看ndarray占用的总空间,可以:
1 | a= eye(10) |
访问
如何访问我们创建好的ndarray呢?
非常类似python原生
1 | arange(10)[2:8] |
同样的默认参数为数组起始点
1 | arange(10)[:7] |
也可以步长读取数据
1 | arange(10)[:7:2] |
还能使用负数翻转数组
1 | arange(10)[::-1] |
那么多维数组呢?
我们以arange(30).reshape(2,3,5)为例
1 | a=arange(30).reshape(2,3,5) |
这里使用[x,y,z]类似这样的模式,xyz分别是1维2维3维的索引,比如
1 | a[0,1,0] |
比如我们想某个维度全部匹配,这里用:
代替:
1 | a[0,:,0] |
如果有多个冒号,可以用…代替
1 | a[0,...] |
改变数组维度
包括前面提到的reshape操作,numpy提供很多方法供你修改数组的维度。
展开
ravel
我们前面生成的多维数组a可以用这种方式展开1
2
3
4a.ravel()
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29])flatten
和ravel非常类似,只不过flatten会创建一个新的数组,而ravel是原数组的视图(并未修改原数组)。下面这个例子可以证明
1 | b1 = a.ravel() |
由于shape是ndarray的一个元组,所以修改元组的方式也可以修改数组的维度
1 | a.shape=(3,10) |
- transpose 转置
行转列,列转行1
2
3
4
5
6
7
8
9
10
11
12a.transpose()
array([[100, 10, 20],
[ 1, 11, 21],
[ 2, 12, 22],
[ 3, 13, 23],
[ 4, 14, 24],
[ 5, 15, 25],
[ 6, 16, 26],
[ 7, 17, 27],
[ 8, 18, 28],
[ 9, 19, 29]])
组合
有时我们需要将多个ndarray组合为一个新的ndarray
一维合并/水平合并
hstack 要求 两个数组高度相同,做1维合并 ,column_stack类似1
2
3
4
5
6a = arange(9).reshape(3,3)
c = arange(15).reshape(3,5)
hstack((a,c))
array([[ 0, 1, 2, 0, 1, 2, 3, 4],
[ 3, 4, 5, 5, 6, 7, 8, 9],
[ 6, 7, 8, 10, 11, 12, 13, 14]])二维合并/垂直合并
1
2
3
4
5
6
7
8
9
10
11
12a = arange(9).reshape(3,3)
d = arange(15).reshape(5,3)
vstack((a,d))
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]])三维合并/深度合并
dstack做三维合并1
2
3
4
5
6
7
8
9
10
11a3 = arange(30).reshape(2,3,5)
b3 = arange(36).reshape(2,3,6)
dstack((a3,b3))
array([[[ 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5],
[ 5, 6, 7, 8, 9, 6, 7, 8, 9, 10, 11],
[10, 11, 12, 13, 14, 12, 13, 14, 15, 16, 17]],
[[15, 16, 17, 18, 19, 18, 19, 20, 21, 22, 23],
[20, 21, 22, 23, 24, 24, 25, 26, 27, 28, 29],
[25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]]])自由合并
concatenate ,其中参数 axis 指定堆叠轴
,除了堆叠轴外,其他轴必须维度完全相同。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28a5=arange(100).reshape(2,2,5,5)
b5=arange(120).reshape(2,2,5,6)
concatenate((a5,b5),axis=3)
array([[[[ 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5],
[ 5, 6, 7, 8, 9, 6, 7, 8, 9, 10, 11],
[ 10, 11, 12, 13, 14, 12, 13, 14, 15, 16, 17],
[ 15, 16, 17, 18, 19, 18, 19, 20, 21, 22, 23],
[ 20, 21, 22, 23, 24, 24, 25, 26, 27, 28, 29]],
[[ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35],
[ 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41],
[ 35, 36, 37, 38, 39, 42, 43, 44, 45, 46, 47],
[ 40, 41, 42, 43, 44, 48, 49, 50, 51, 52, 53],
[ 45, 46, 47, 48, 49, 54, 55, 56, 57, 58, 59]]],
[[[ 50, 51, 52, 53, 54, 60, 61, 62, 63, 64, 65],
[ 55, 56, 57, 58, 59, 66, 67, 68, 69, 70, 71],
[ 60, 61, 62, 63, 64, 72, 73, 74, 75, 76, 77],
[ 65, 66, 67, 68, 69, 78, 79, 80, 81, 82, 83],
[ 70, 71, 72, 73, 74, 84, 85, 86, 87, 88, 89]],
[[ 75, 76, 77, 78, 79, 90, 91, 92, 93, 94, 95],
[ 80, 81, 82, 83, 84, 96, 97, 98, 99, 100, 101],
[ 85, 86, 87, 88, 89, 102, 103, 104, 105, 106, 107],
[ 90, 91, 92, 93, 94, 108, 109, 110, 111, 112, 113],
[ 95, 96, 97, 98, 99, 114, 115, 116, 117, 118, 119]]]])
分割
将单个ndarray分成多个ndarray,是前面的合并操作的逆操作。
第一维度/水平分割
hsplit传入分割的片数,要求能够被第一维度
元素个数整除。1
2
3
4
5
6
7
8
9
10
11
12
13a=arange(30).reshape(5,6)
hsplit(a,2)
[array([[ 0, 1, 2],
[ 6, 7, 8],
[12, 13, 14],
[18, 19, 20],
[24, 25, 26]]),
array([[ 3, 4, 5],
[ 9, 10, 11],
[15, 16, 17],
[21, 22, 23],
[27, 28, 29]])]第二维度/垂直分割
vsplit1
2
3
4
5
6
7
8
9a=arange(30).reshape(6,5)
vsplit(a,2)
[array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]]),
array([[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]])]第三维度/深度分割
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41a=arange(30).reshape(5,3,2)
dsplit(a,2)
[array([[[ 0],
[ 2],
[ 4]],
[[ 6],
[ 8],
[10]],
[[12],
[14],
[16]],
[[18],
[20],
[22]],
[[24],
[26],
[28]]]),
array([[[ 1],
[ 3],
[ 5]],
[[ 7],
[ 9],
[11]],
[[13],
[15],
[17]],
[[19],
[21],
[23]],
[[25],
[27],
[29]]])]深度分割
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25a=arange(100).reshape(4,5,5)
split(a, 2, axis=0)
[array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]],
[[25, 26, 27, 28, 29],
[30, 31, 32, 33, 34],
[35, 36, 37, 38, 39],
[40, 41, 42, 43, 44],
[45, 46, 47, 48, 49]]]),
array([[[50, 51, 52, 53, 54],
[55, 56, 57, 58, 59],
[60, 61, 62, 63, 64],
[65, 66, 67, 68, 69],
[70, 71, 72, 73, 74]],
[[75, 76, 77, 78, 79],
[80, 81, 82, 83, 84],
[85, 86, 87, 88, 89],
[90, 91, 92, 93, 94],
[95, 96, 97, 98, 99]]])]
读写
numpy主要支持两种格式保存数据:1. npy 2. csv
npy
该文件格式是专门为NumPy数组设计的,可以保留数组的所有信息,包括数据类型、维度、形状、元素等。这使得.npy文件的读写速度非常快,并且保存的数据非常紧凑。同时,由于.npy文件是二进制格式,因此它不易于通过文本编辑器进行查看和编辑。
1 | import numpy as np |
csv
savetext函数则将NumPy数组保存为文本文件,可以通过指定分隔符、精度等参数来控制保存的格式。该函数可以将NumPy数组转换为类似于CSV(逗号分隔值)格式的文本文件,每行表示数组中的一维数据,不同列之间使用指定的分隔符进行分割。由于文本文件的格式是易于读写的,因此savetxt()函数可以用于将NumPy数组保存为可以被其他程序读取和处理的标准格式。
1 | import numpy as np |
统计
平均
- average与mean
numpy.mean()和numpy.average()函数都可以用于计算数组的平均值,但它们有一些不同之处。
numpy.mean(): 这个函数计算给定数组中元素的算术平均值。可以指定轴来计算不同维度上的平均值。默认情况下,计算所有元素的平均值。例如:
1
2
3a = np.array([1, 2, 3, 4, 5])
mean_a = np.mean(a)
print(mean_a) # 输出:3.0numpy.average(): 这个函数也用于计算数组的平均值,但它允许指定每个元素的权重。如果没有指定权重,则函数的行为与numpy.mean()相同。例如:
1 | import numpy as np |
在不指定权重的情况下,这两个函数是等价的。
中位数
将所有数据排序后,如果总数是奇数,则中位数是中间一位;如果是偶数则是中间两位的平均值。
1 | median(array([1,2,3,4,5,1000,100000])) |
方差、标准差
方差和标准差都是衡量数据分散程度的统计量,其中方差是每个数据点与平均值的差的平方的平均值,而标准差是方差的平方根。
1 | std(array([1,2,3,4,5,1000])) |
百分位percentile
将数据排序后,排在某个位置的数
1 | numpy.percentile(a, q, axis=None, interpolation='linear') |
这里axis是要计算的轴,interpolation
是插值方法,用于计算非整数百分位数的值。默认为 linear。
1 | import numpy as np |
histogram
numpy.histogram() 函数用于计算一个数组的直方图。直方图是对数据分布情况的图形表示,横轴表示数据范围的分组区间,纵轴表示每个分组区间内的数据频数或频率。
1 | import numpy as np |