介绍
NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:
- 一个强大的N维数组对象 ndarray
- 广播功能函数
- 整合 C/C++/Fortran 代码的工具
- 线性代数、傅里叶变换、随机数生成等功能
另外,NumPy 还会经常与 SciPy(Scientific Python)和 Matplotlib(绘图库)一起使用。
安装
pip安装:
pip install numpy
导入模块
导入之后通常会取个别名:
import numpy as np
数组
数组是一个值网格,所有类型都是相同类型的。和原生的列表(list)比较,列表里的每个元素可以是不同的类型。
原生数组
python也是有数组的:
>>> import array # 导入模块
>>> a1 = array.array('i') # 创建了一个数组,类型是i,就是int
>>> a1.append(1) # 添加一个元素
>>> a1.append(2)
>>> a1
array('i', [1, 2])
>>> len(a1)
2
这部分不是重点,就提一下。
创建数组
从列表生成数组
>>> l1 = [1, 2, 3, 4, 5]
>>> l2 = np.array(l1)
>>> l2
array([1, 2, 3, 4, 5])
>>> type(l1)
<class 'list'>
>>> type(l2)
<class 'numpy.ndarray'>
全0的数组
>>> np.zeros(3)
array([ 0., 0., 0.])
>>> np.zeros(3, dtype=int) # 默认是浮点数,可以指定类型
array([0, 0, 0])
全1的数组
>>> np.ones(3, int)
array([1, 1, 1])
多维数组 生成数组时,第一个参数,是可以指定维度的:
>>> np.ones((2, 4), int)
array([[1, 1, 1, 1],
[1, 1, 1, 1]])
>>> np.ones((3, 3), int)
array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
>>>
创建时填充其他值
>>> np.full((2,3), 'x')
array([['x', 'x', 'x'],
['x', 'x', 'x']],
dtype='<U1')
>>>
按一个数组为模板创建数组 维度和元素类型都是一样的,所以1.23被自动转成了整数:
>>> t1 = np.zeros((3, 2), int) # 3*2 的int类型的数组
>>> np.full_like(t1, 1.23)
array([[1, 1],
[1, 1],
[1, 1]])
>>>
生成单位矩阵
>>> np.eye(3, dtype=int)
array([[1, 0, 0],
[0, 1, 0],
[0, 0, 1]])
>>> np.eye(3, k=1, dtype=int)
array([[0, 1, 0],
[0, 0, 1],
[0, 0, 0]])
>>> np.eye(3, 2, dtype=int)
array([[1, 0],
[0, 1],
[0, 0]])
在次对角线上生成全1的矩阵:
>>> np.eye(3, dtype=int)[::-1]
array([[0, 0, 1],
[0, 1, 0],
[1, 0, 0]])
随机数数组
原生的random库也能生成随机数,不过NumPy库的随机数功能更强大
原生random模块
>>> random.random() # 原生函数没有参数,只能生成1个数
0.3145225040001337
>>> np.random.random(3) # 生成随机数组
array([ 0.5298384 , 0.34748761, 0.52159409])
生成随机数数组
随机整数
>>> np.random.randint(1, 100, 2)
array([99, 77])
指定维度
>>> np.random.random((3, 3))
array([[ 0.72420303, 0.31726755, 0.39925357],
[ 0.57047567, 0.96920481, 0.06743519],
[ 0.76589897, 0.9075956 , 0.22296356]])
>>> np.random.randint(1, 10, (2, 5))
array([[7, 5, 2, 4, 6],
[2, 8, 3, 6, 8]])
取值范围
np.arange 与原生的range差不多,可以指定起始、结束、步长,三个参数:
>>> np.arange(2)
array([0, 1])
>>> np.arange(3)
array([0, 1, 2])
>>> np.arange(1, 9)
array([1, 2, 3, 4, 5, 6, 7, 8])
>>> np.arange(1, 9, 3)
array([1, 4, 7])
>>> np.arange(1.0, 5.0, 0.7)
array([ 1. , 1.7, 2.4, 3.1, 3.8, 4.5])
np.linspace 给定起始和结束的值,自动计算中间的间隔,默认生成50个数:
>>> np.linspace(1, 2)
array([ 1. , 1.02040816, 1.04081633, 1.06122449, 1.08163265,
1.10204082, 1.12244898, 1.14285714, 1.16326531, 1.18367347,
1.20408163, 1.2244898 , 1.24489796, 1.26530612, 1.28571429,
1.30612245, 1.32653061, 1.34693878, 1.36734694, 1.3877551 ,
1.40816327, 1.42857143, 1.44897959, 1.46938776, 1.48979592,
1.51020408, 1.53061224, 1.55102041, 1.57142857, 1.59183673,
1.6122449 , 1.63265306, 1.65306122, 1.67346939, 1.69387755,
1.71428571, 1.73469388, 1.75510204, 1.7755102 , 1.79591837,
1.81632653, 1.83673469, 1.85714286, 1.87755102, 1.89795918,
1.91836735, 1.93877551, 1.95918367, 1.97959184, 2. ])
指定总数:
>>> np.linspace(1, 10, 5, dtype=int)
array([ 1, 3, 5, 7, 10])
不包括结尾的数:
>>> np.linspace(1, 10, 5, endpoint=True, dtype=int)
array([ 1, 3, 5, 7, 10])
>>> np.linspace(1, 10, 5, endpoint=False, dtype=int)
array([1, 2, 4, 6, 8])
显示步长:
>>> np.linspace(1, 10, 5, retstep=True)
(array([ 1. , 3.25, 5.5 , 7.75, 10. ]), 2.25)
下面先设置了输出小数和输出精度,然后计算了将一个圆周切分n份的横坐标(sin值)和纵坐标(cos值),最后再把之前的设置调回默认值:
>>> np.set_printoptions(precision=3, suppress=True)
>>> np.sin(np.linspace(0, np.pi*2, 8, endpoint=False))
array([ 0. , 0.707, 1. , 0.707, 0. , -0.707, -1. , -0.707])
>>> np.cos(np.linspace(0, np.pi*2, 8, endpoint=False))
array([ 1. , 0.707, 0. , -0.707, -1. , -0.707, -0. , 0.707])
>>> np.set_printoptions(edgeitems=3,infstr='inf', linewidth=75, nanstr='nan', precision=8, suppress=False, threshold=1000, formatter=None)
操作数组
访问元素
访问元素可以使用传统的多维数组访问方式来访问:
>>> a2 = np.zeros((3, 3))
>>> a2
array([[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
>>> a2[0][0] = 2 # 传统的访问方式
>>> a2[0, 0] # 看着和上面一样
2.0
不过上面 [0, 0] 这种形式的功能更加强大,因为这样支持数组切片:
>>> a2[1:,1:] = 5
>>> a2
array([[ 2., 0., 0.],
[ 0., 5., 5.],
[ 0., 5., 5.]])
比较一下两个访问形式在多维数组情况时的区别:
>>> a2[1:, 1:]
array([[ 5., 5.],
[ 5., 5.]])
>>> a2[1:][1:]
array([[ 0., 5., 5.]])
传统的方式是一种链式操作,是在前一次切片的基础上再执行切片:
>>> tmp = a2[1:]
>>> tmp[1:]
array([[ 0., 5., 5.]])
>>> a2[1:][1:]
array([[ 0., 5., 5.]])
数组属性
维度 继续使用上面的二维数组:
>>> a2.ndim
2
>>> a2[1].ndim # 取出其中一个值,就是个一维数组了
1
形状
>>> a2.shape
(3, 3)
>>> a2[1:,].shape
(2, 3)
元素总数
>>> a2.size
9
>>> a2[1:, 1:].size
4
元素类型
>>> a2.dtype
dtype('float64')
占用的字节数
>>> a2.itemsize # 每个用上占用的字节数
8
>>> a2.nbytes # 整个数组占用的字节数
72
float64类型,占8字节。类型不同占用的字节数就不一样,另外字符串的情况还更复杂的样子。不过主要用来做数学计算的:
>>> np.array([1, 2, 3]).itemsize
4
>>> np.array(['a']).itemsize
4
>>> np.array(['a', 'ij', 'xyz']).itemsize
12
>>> np.array(['a', 'ij', 'xyz']).nbytes
36
数组操作
变形 变形前后要求元素的总数size要一样:
>>> np.eye(4 ,4)
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])
>>> np.eye(4, 4).reshape(2, 8)
array([[ 1., 0., 0., 0., 0., 1., 0., 0.],
[ 0., 0., 1., 0., 0., 0., 0., 1.]])
排序
>>> sort0 = np.random.randint(0, 10, (3, 3))
>>> sort0
array([[0, 5, 9],
[7, 7, 7],
[7, 3, 6]])
>>> np.sort(sort0) # 默认横向排序
array([[0, 5, 9],
[7, 7, 7],
[3, 6, 7]])
>>> np.sort(sort0, axis=None)
array([0, 3, 5, 6, 7, 7, 7, 7, 9])
>>> np.sort(sort0, axis=0) # 0是纵向排序
array([[0, 3, 6],
[7, 5, 7],
[7, 7, 9]])
拼接
>>> c1 = np.array((1, 2, 3))
>>> c2 = np.array((9, 8, 7))
>>> np.concatenate((c1, c2, c1))
array([1, 2, 3, 9, 8, 7, 1, 2, 3])
axis只有在多维数组拼接时候可以设置为1,拼接的效果也不同:
>>> c3 = [[1, 2], [3, 4]]
>>> c4 = [[5, 6], [7, 8]]
>>> np.concatenate((c3, c4), axis=0)
array([[1, 2],
[3, 4],
[5, 6],
[7, 8]])
>>> np.concatenate((c3, c4), axis=1)
array([[1, 2, 5, 6],
[3, 4, 7, 8]])
统计 简单的求和,和原生数组没差别:
>>> sum(np.arange(1, 101))
5050
以二维数组举例,可以对横向纵向每个维度进行求和:
>>> np.array([i+1 for i in range(9)]).reshape(3, 3)
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
>>> a3 = np.array([i+1 for i in range(9)]).reshape(3, 3)
>>> np.sum(a3)
45
>>> np.sum(a3, axis=0)
array([12, 15, 18])
>>> np.sum(a3, axis=1)
array([ 6, 15, 24])
转置
>>> np.array(([1, 2, 3], [4, 5, 6]))
array([[1, 2, 3],
[4, 5, 6]])
>>> np.transpose(np.array(([1, 2, 3], [4, 5, 6])))
array([[1, 4],
[2, 5],
[3, 6]])
反转 python的反转很方便,所以没有专门的方法:
>>> [1, 2, 3][::-1]
[3, 2, 1]
旋转 配合转置和反转就可以实现:
>>> a4 = np.array([i+1 for i in range(12)]).reshape(3, 4)
>>> a4
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
>>> np.transpose(a4[::-1])
array([[ 9, 5, 1],
[10, 6, 2],
[11, 7, 3],
[12, 8, 4]])
>>> np.transpose(a4[:, ::-1])
array([[ 4, 8, 12],
[ 3, 7, 11],
[ 2, 6, 10],
[ 1, 5, 9]])