跳转至

Numpy

NumPy (Numerical Python)是Python的一种开源的数值计算扩展。提供多维数组对象,各种派生对象(如掩码数组和矩阵),这种工具可用来存储和处理大型矩阵,比Python自身的嵌套列表 (nestedlist structure)结构要高效的多 (该结构也可以用来表示矩阵 (matrix) ) ,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库,包括数学、逻辑、形状操作、排序、选择、输入输出、离散傅立叶变换、基本线性代数,基本统计运算和随机模拟等等。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

如果已经启动了 Notebook 但尚未安装相关依赖库,例如尚未安装 numpy ,可以在 Notebook 的单元格中输⼊ !pip install numpy 并运⾏该单元格来安装 NumPy,也可以⼀次性安装多个三⽅ 库,需要在单元格中输⼊ %pip install numpy pandas matplotlib 。注意上⾯的代码,我们不仅导⼊ 了NumPy,还将 pandas 和 matplotlib 库⼀并导⼊了。

1.创建数组对象

创建 ndarray 对象有很多种⽅法,下⾯就如何创建⼀维数组、⼆维数组和多维数组进⾏说明。

1.1 ⼀维数组

⽅法⼀:使⽤ array 函数,通过 list 创建数组对象

代码:

array1 = np.array([1, 2, 3, 4, 5])
array1
array([1, 2, 3, 4, 5])

⽅法⼆:使⽤ arange 函数,指定取值范围创建数组对象

代码:

array2 = np.arange(0, 20, 2)
array2
array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])

⽅法三:使⽤ linspace 函数,⽤指定范围均匀间隔的数字创建数组对象

代码:

array3 = np.linspace(-5, 5, 101)
array3
array([-5. , -4.9, -4.8, -4.7, -4.6, -4.5, -4.4, -4.3, -4.2, -4.1, -4. ,
       -3.9, -3.8, -3.7, -3.6, -3.5, -3.4, -3.3, -3.2, -3.1, -3. , -2.9,
       -2.8, -2.7, -2.6, -2.5, -2.4, -2.3, -2.2, -2.1, -2. , -1.9, -1.8,
       -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1. , -0.9, -0.8, -0.7,
       -0.6, -0.5, -0.4, -0.3, -0.2, -0.1,  0. ,  0.1,  0.2,  0.3,  0.4,
        0.5,  0.6,  0.7,  0.8,  0.9,  1. ,  1.1,  1.2,  1.3,  1.4,  1.5,
        1.6,  1.7,  1.8,  1.9,  2. ,  2.1,  2.2,  2.3,  2.4,  2.5,  2.6,
        2.7,  2.8,  2.9,  3. ,  3.1,  3.2,  3.3,  3.4,  3.5,  3.6,  3.7,
        3.8,  3.9,  4. ,  4.1,  4.2,  4.3,  4.4,  4.5,  4.6,  4.7,  4.8,
        4.9,  5. ])

⽅法四:使⽤ numpy.random 模块的函数⽣成随机数创建数组对象

产⽣10个 范围的随机⼩数,代码:

array4 = np.random.rand(10)
array4
array([0.20428427, 0.49608764, 0.08950477, 0.98494363, 0.3974631 ,
       0.45707951, 0.85051009, 0.42975832, 0.81901529, 0.63863295])

产⽣10个[1,100)范围的随机整数,代码:

array5 = np.random.randint(1, 100, 10)
array5
array([59, 58, 32,  5, 64, 52, 95,  8, 86, 68])

产⽣20个 , 的正态分布随机数,代码:

array6 = np.random.normal(50, 10, 20)
array6
array([55.1025396 , 46.27838868, 52.13750212, 50.07276008, 65.16738885,
       38.97636743, 51.2117446 , 54.64068039, 44.26068514, 55.2642847 ,
       41.55681965, 43.1920184 , 61.62927089, 62.0965554 , 52.6403474 ,
       60.94268609, 45.60638455, 47.11781316, 56.38311871, 54.45587635])

1.2 ⼆维数组

⽅法⼀:使⽤ array 函数,通过嵌套的 list 创建数组对象

代码:

array7 = np.array([[1, 2, 3], [4, 5, 6]])
array7
array([[1, 2, 3],
       [4, 5, 6]])

⽅法⼆:使⽤ zeros 、 ones 、 full 函数指定数组的形状创建数组对象

使⽤ zeros 函数,代码:

array8 = np.zeros((3, 4))
array8
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])

使⽤ ones 函数,代码:

array9 = np.ones((3, 4))
array9
array([[1., 1., 1., 1.],
       [1., 1., 1., 1.],
       [1., 1., 1., 1.]])

使⽤ full 函数,代码:

array10 = np.full((3, 4), 10)
array10
array([[10, 10, 10, 10],
       [10, 10, 10, 10],
       [10, 10, 10, 10]])

⽅法三:使⽤eye函数创建单位矩阵

代码:

array11 = np.eye(4)
array11
array([[1., 0., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.]])

⽅法四:通过 reshape 将⼀维数组变成⼆维数组

代码:

array12 = np.array([1, 2, 3, 4, 5, 6]).reshape(2, 3)
array12
array([[1, 2, 3],
       [4, 5, 6]])

提示: reshape 是 ndarray 对象的⼀个⽅法,使⽤ reshape ⽅法时需要确保调形后的数组元素个数与调 形前数组元素个数保持⼀致,否则将会产⽣异常。

⽅法五:通过 numpy.random 模块的函数⽣成随机数创建数组对象

产⽣ 范围的随机⼩数构成的3⾏4列的⼆维数组,代码:

array13 = np.random.rand(3, 4)
array13
array([[0.04778408, 0.58424096, 0.52167333, 0.28053032],
       [0.81798852, 0.39551909, 0.39487919, 0.75145468],
       [0.64650891, 0.67058731, 0.03179258, 0.03581326]])

产⽣ 范围的随机整数构成的3⾏4列的⼆维数组,代码:

array14 = np.random.randint(1, 100, (3, 4))
array14
array([[ 5, 32, 90, 98],
       [93, 51, 63, 28],
       [40, 81, 94, 21]])

1.3 多维数组

使⽤随机的⽅式创建多维数组

代码:

array15 = np.random.randint(1, 100, (3, 4, 5))
array15
array([[[85, 80, 60, 76, 40],
        [24,  8, 36, 95, 10],
        [16, 12, 88, 19, 66],
        [ 9, 48, 51, 11, 13]],

       [[42,  4, 11, 32, 87],
        [76, 33, 19,  9, 57],
        [23,  5, 83, 34, 41],
        [20, 60, 73, 33, 89]],

       [[91, 20, 88, 10, 21],
        [91, 84, 10, 79, 26],
        [36, 68, 39, 90, 52],
        [30, 54, 93, 40, 68]]])

将⼀维⼆维的数组调形为多维数组

⼀维数组调形为多维数组,代码:

array16 = np.arange(1, 25).reshape((2, 3, 4))
array16
array([[[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9, 10, 11, 12]],

       [[13, 14, 15, 16],
        [17, 18, 19, 20],
        [21, 22, 23, 24]]])

⼆维数组调形为多维数组,代码:

array17 = np.random.randint(1, 100, (4, 6)).reshape((4, 3, 2))
array17
array([[[28, 17],
        [13, 42],
        [ 3, 92]],

       [[38, 56],
        [25, 43],
        [ 9, 55]],

       [[ 8, 43],
        [32,  1],
        [14, 60]],

       [[60, 94],
        [56, 42],
        [89, 55]]])

读取图⽚获得对应的三维数组

代码:

array18 = plt.imread('image/logo.png')
array18
array([[[1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        ...,
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.]],

       [[1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        ...,
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.]],

       [[1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        ...,
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.]],

       ...,

       [[1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        ...,
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.]],

       [[1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        ...,
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.]],

       [[1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        ...,
        [1., 1., 1., 0.],
        [1., 1., 1., 0.],
        [1., 1., 1., 0.]]], dtype=float32)

说明:上⾯的代码读取了当前路径下名为 guido.jpg 的图⽚⽂件,计算机系统中的图⽚通常由若⼲⾏若⼲列的像素点构成,⽽每个像素点⼜是由红绿蓝三原⾊构成的,所以能够⽤三维数组来表示。读取图⽚⽤到了 matplotlib 库的 imread 函数。

2. 数组对象的属性

2.1. size 属性:数组元素个数

代码:

array19 = np.arange(1, 100, 2)
array20 = np.random.rand(3, 4)
print(array19.size, array20.size)
50 12

2.2 shape 属性:数组的形状

代码:

print(array19.shape, array20.shape)
(50,) (3, 4)

2.3 dtype 属性:数组元素的数据类型

代码:

print(array19.dtype, array20.dtype)
int32 float64

ndarray 对象元素的数据类型可以参考如下所示的表格。

2.4 ndim 属性:数组的维度

代码:

print(array19.ndim, array20.ndim)
1 2

2.5. itemsize 属性:数组单个元素占⽤内存空间的字节数

代码:

array21 = np.arange(1, 100, 2, dtype=np.int8)
print(array19.itemsize, array20.itemsize, array21.itemsize)
4 8 1

说明:在使⽤ arange 创建数组对象时,通过 dtype 参数指定元素的数据类型。可以看出, np.int8 代 表的是8位有符号整数,只占⽤1个字节的内存空间,取值范围是 。

2.6. nbytes 属性:数组所有元素占⽤内存空间的字节数

代码:

print(array19.nbytes, array20.nbytes, array21.nbytes)
200 96 50

2.7. flat 属性:数组(⼀维化之后)元素的迭代器

from typing import Iterable
print(isinstance(array20.flat, np.ndarray), isinstance(array20.flat, Iterable))
False True

2.8. base 属性:数组的基对象(如果数组共享了其他数组的内存空间)

代码:

array22 = array19[:]
print(array22.base is array19, array22.base is array21)
True False

说明:上⾯的代码⽤到了数组的切⽚操作,它类似于 Python 中 list 类型的切⽚,但在细节上⼜不完全相同,下⾯会专⻔讲解这个知识点。通过上⾯的代码可以发现, ndarray 切⽚后得到的新的数组对象跟原来的数组对象共享了内存中的数据,因此 array22 的 base 属性就是 array19 对应的数组对象。

3. 数组的索引和切片

和 Python 中的列表类似, NumPy 的 ndarray 对象可以进⾏索引和切⽚操作,通过索引可以获取或修改数组中的元素,通过切⽚可以取出数组的⼀部分。

3.1. 索引运算(普通索引)

⼀维数组,代码:

array23 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
print(array23[0], array23[array23.size - 1])
print(array23[-array23.size], array23[-1])
1 9
1 9

⼆维数组,代码:

array24 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
array24
print(array24[2])
print(array24[0][0], array24[-1][-1])
print(array24[1][1], array24[1, 1])
[7 8 9]
1 9
5 5
array24[1][1] = 10
print(array24)
array24[1] = [10, 11, 12]
print(array24)
[[ 1  2  3]
 [ 4 10  6]
 [ 7  8  9]]
[[ 1  2  3]
 [10 11 12]
 [ 7  8  9]]

3.2. 切片运算(切片索引)

切⽚是形如 [开始索引:结束索引:步⻓] 的语法,通过指定开始索引(默认值⽆穷⼩)、 结束索引(默认值⽆穷⼤)和步⻓(默认值1),从数组中取出指定部分的元素并构成新的数组。因为开始索引、结束索引和步⻓都有默认值,所以它们都可以省略,如果不指定步⻓,第⼆个冒号也可以省略。⼀维数组的切⽚运算跟 Python中的 list 类型的切⽚⾮常类似,此处不再赘述,⼆维数组的切⽚可以参考下⾯的代码,相信⾮常容易理解。

代码:

print(array24[:2, 1:])
[[ 2  3]
 [11 12]]

关于数组的索引和切⽚运算,⼤家可以通过下⾯的两张图来增强印象。

3.3. 花式索引(fancy index)

花式索引(Fancy indexing)是指利⽤整数数组进⾏索引,这⾥所说的整数数组可以是 NumPy 的 ndarray,也可以是 Python 中 list、 tuple 等可迭代类型,可以使⽤正向或负向索引。

⼀维数组的花式索引,代码:

array25 = np.array([50, 30, 15, 20, 40])
array25[[0, 1, -1]]
array([50, 30, 40])

⼆维数组的花式索引,代码:

array26 = np.array([[30, 20, 10], [40, 60, 50], [10, 90, 80]])
# 取⼆维数组的第1⾏和第3⾏
array26[[0, 2]]
array([[30, 20, 10],
       [10, 90, 80]])
# 取⼆维数组第1⾏第2列,第3⾏第3列的两个元素
array26[[0, 2], [1, 2]]
array([20, 80])

3.4. 布尔索引

布尔索引就是通过布尔类型的数组对数组元素进⾏索引,布尔类型的数组可以⼿动构造,也可以通过关系运算来产⽣布尔类型的数组。

array27 = np.arange(1, 10)
array27[[True, False, True, True, False, False, False, False, True]]
array([1, 3, 4, 9])
array27 >= 5
array([False, False, False, False,  True,  True,  True,  True,  True])

4.数组对象的方法

4.1 统计方法

统计⽅法主要包括: sum() 、 mean() 、 std() 、 var() 、 min() 、 max() 、 argmin() 、 argmax() 、 cumsum()等,分别⽤于对数组中的元素求和、求平均、求标准差、求⽅差、找最⼤、找最⼩、求累积和等,请参考下⾯的代码。

array28 = np.array([1, 2, 3, 4, 5, 5, 4, 3, 2, 1])
print(array28.sum())
print(array28.mean())
print(array28.max())
print(array28.min())
print(array28.std())
print(array28.var())
print(array28.cumsum())
30
3.0
5
1
1.4142135623730951
2.0
[ 1  3  6 10 15 20 24 27 29 30]

4.2 其他⽅法

all() / any() ⽅法:判断数组是否所有元素都是 True / 判断数组是否有为 True 的元素。

astype() ⽅法:拷⻉数组,并将数组中的元素转换为指定的类型。

dump() ⽅法:保存数组到⽂件中,可以通过 NumPy 中的 load() 函数从保存的⽂件中加载数据创建数组。

fill() ⽅法:向数组中填充指定的元素。

flatten() ⽅法:将多维数组扁平化为⼀维数组。

nonzero() ⽅法:返回⾮0元素的索引。

round() ⽅法:对数组中的元素做四舍五⼊操作。

sort() ⽅法:对数组进⾏就地排序。

swapaxes() 和 transpose() ⽅法:交换数组指定的轴。

tolist() ⽅法:将数组转成Python中的 list。

array33 = np.array([35, 96, 12, 78, 66, 54, 40, 82])
array33.sort()
array33
array([12, 35, 40, 54, 66, 78, 82, 96])