文章目录
0.概述
Numpy(Numerical Python的简称)是高性能科学计算和数据分析的基础包。使用深度学习框架构建神经网络模型时,通常会使用Numpy实现数据预处理和一些模型指标的计算, 深度学习框架中的Tensor数据可以很方便的和ndarray数组进行相互转换。
Numpy具有如下功能:
- ndarray数组:一个具有矢量算术运算和复杂广播能力的多维数组,具有快速且节省空间的特点。
- 对整组数据进行快速运算的标准数学函数(无需编写循环)。
- 线性代数、随机数生成以及傅里叶变换功能。
- 读写磁盘数据、操作内存映射文件。
本质上,Numpy期望用户在执行“向量”操作时,像使用“标量”一样轻松。读者可以先在本机上运行如下代码,感受一下Numpy的便捷。
>>> import numpy as np
>>> a = np.array([1,2,3,4])
>>> b = np.array([10,20,30,40])
>>> c = a + b
>>> print (c)
[11 22 33 44]
1. 基础数据类型:ndarray数组
ndarray数组是Numpy的基础数据结构,可以灵活、高效地处理多个元素的操作。本节主要从如下五部分展开介绍:
- 为什么引入ndarray数组
- 如何创建ndarray数组
- ndarray数组的基本运算
- ndarray数组的切片和索引
- ndarray数组的统计运算
1.1 为什么引入ndarray数组
Python中的list列表也可以非常灵活的处理多个元素的操作,但效率却非常低。与之比较,ndarray数组具有如下特点:
- ndarray数组中所有元素的数据类型相同、数据地址连续,批量操作数组元素时速度更快。而list列表中元素的数据类型可能不同,需要通过寻址方式找到下一个元素。
- ndarray数组支持广播机制,矩阵运算时不需要写for循环。
- Numpy底层使用C语言编写,内置并行计算功能,运行速度高于Python代码。
下面通过几个实际例子体会一下,在完成同一个任务时,使用ndarray数组和list列表的差异。
案例1:实现a+1的计算
# Python原生的list
# 假设有两个list
a = [1, 2, 3, 4, 5]
b = [2, 3, 4, 5, 6]
# 完成如下计算
# 对a的每个元素 + 1
# a = a + 1 不能这么写,会报错
# a[:] = a[:] + 1 也不能这么写,也会报错
for i in range(5):
a[i] = a[i] + 1
a
[2, 3, 4, 5, 6]
# 使用ndarray
import numpy as np
a = np.array([1, 2, 3, 4, 5])
a = a + 1
a
array([2, 3, 4, 5, 6])
案例2:实现c=a+b的计算
# 计算 a和b中对应位置元素的和,是否可以这么写?
a = [1, 2, 3, 4, 5]
b = [2, 3, 4, 5, 6]
c = a + b
# 检查输出发现,不是想要的结果
c
[1, 2, 3, 4, 5, 2, 3, 4, 5, 6]
# 使用for循环,完成两个list对应位置元素相加
c = []
for i in range(5):
c.append(a[i] + b[i])
c
[3, 5, 7, 9, 11]
# 使用numpy中的ndarray完成两个ndarray相加
import numpy as np
a = np.array([1, 2, 3, 4, 5])
b = np.array([2, 3, 4, 5, 6])
c = a + b
c
array([ 3, 5, 7, 9, 11])
通过上面的两个案例可以看出,在不写for循环的情况下,ndarray数组就可以非常方便的完成数学计算。在编写矢量或者矩阵的程序时,可以像编写普通数值一样,使得代码极其简洁。
另外,ndarray数组还提供了广播机制,它会按一定规则自动对数组的维度进行扩展以完成计算。如下面例子所示,1维数组和2维数组进行相加操作,ndarray数组会自动扩展1维数组的维度,然后再对每个位置的元素分别相加。
# 自动广播机制,1维数组和2维数组相加
# 二维数组维度 2x5
# array([[ 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 10]])
d = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
# c是一维数组,维度5
# array([ 4, 6, 8, 10, 12])
c = np.array([ 4, 6, 8, 10, 12])
e = d + c
e
array([[ 5, 8, 11, 14, 17],
[10, 13, 16, 19, 22]])
1.2 创建ndarray数组
创建ndarray数组最简单的方式就是使用array
函数,它接受一切序列型的对象(包括其他数组),然后产生一个新的含有传入数据的numpy数组。下面通过实例体会下array
、arange
、zeros
、ones
四个主要函数的用法。
array
:创建嵌套序列(比如由一组等长列表组成的列表),并转换为一个多维数组。
# 导入numpy
import numpy as np
# 从list创建array
a = [1,2,3,4,5,6] # 创建简单的列表
b = np.array(a) # 将列表转换为数组
b
array([1, 2, 3, 4, 5, 6])
arange
:创建元素从0到10依次递增2的数组。
# 通过np.arange创建
# 通过指定start, stop (不包括stop),interval来产生一个1维的ndarray
a = np.arange(0, 10, 2)
a
array([0, 2, 4, 6, 8])
zeros
:创建指定长度或者形状的全0数组。
# 创建全0的ndarray
a = np.zeros([3,3])
a
array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
ones
:创建指定长度或者形状的全1数组。
# 创建全1的ndarray
a = np.ones([3,3])
a
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
1.3 查看ndarray数组的属性
ndarray的属性包括shape
、dtype
、size
和ndim
等,通过如下代码可以查看ndarray数组的属性。
shape
:数组的形状 ndarray.shape,1维数组(N, ),二维数组(M, N),三维数组(M, N, K)。dtype
:数组的数据类型。size
:数组中包含的元素个数 ndarray.size,其大小等于各个维度的长度的乘积。ndim
:数组的维度大小,ndarray.ndim, 其大小等于ndarray.shape所包含元素的个数。
a = np.ones([3, 3])
print('a, dtype: {}, shape: {}, size: {}, ndim: {}'.format(a.dtype, a.shape, a.size, a.ndim))
a, dtype: float64, shape: (3, 3), size: 9, ndim: 2
import numpy as np
b = np.random.rand(10, 10)
b.shape
(10, 10)
b.size
100
b.ndim
2
b.dtype
dtype('float64')
1.4 改变ndarray数组的数据类型和形状
名称 | 描述 |
---|---|
bool_ | 布尔型数据类型(True 或者 False) |
int_ | 默认的整数类型(类似于 C 语言中的 long,int32 或 int64) |
intc | 与 C 的 int 类型一样,一般是 int32 或 int 64 |
intp | 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64) |
int8 | 字节(-128 to 127) |
int16 | 整数(-32768 to 32767) |
int32 | 整数(-2147483648 to 2147483647) |
int64 | 整数(-9223372036854775808 to 9223372036854775807) |
uint8 | 无符号整数(0 to 255) |
uint16 | 无符号整数(0 to 65535) |
uint32 | 无符号整数(0 to 4294967295) |
uint64 | 无符号整数(0 to 18446744073709551615) |
float_ | float64 类型的简写 |
float16 | 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位 |
float32 | 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位 |
float64 | 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位 |
complex_ | complex128 类型的简写,即 128 位复数 |
complex64 | 复数,表示双 32 位浮点数(实数部分和虚数部分) |
complex128 | 复数,表示双 64 位浮点数(实数部分和虚数部分) |
创建ndarray之后,可以对其数据类型或形状进行修改,代码如下所示。
# 转化数据类型
b = a.astype(np.int64)
print('b, dtype: {}, shape: {}'.format(b.dtype, b.shape))
# 改变形状
c = a.reshape([1, 9])
print('c, dtype: {}, shape: {}'.format(c.dtype, c.shape))
b, dtype: int64, shape: (3, 3)
c, dtype: float64, shape: (1, 9)
1.5 ndarray数组的基本运算
ndarray数组可以像普通的数值型变量一样进行