python之numpy模块
1 NumPy是什么?
NumPy (全称:Numeric Python)是python的第三方模块,主要用于计算、处理一维或多维数组。
Numpy通常与Scipy(Python科学计算库),Matplotlib(Python绘图库),Pandas(Python数据处理)等组合使用,这样可以广泛的代替Matlab的使用。
2 为什么使用NumPy?
Python中没有内置数组(array)类型,只有列表(list),但处理速度很慢,NumPy 旨在提供一个比传统 Python 列表快 50 倍的数组对象。
NumPy与列表的不同点有:
- NumPy中数组数据元素类型必须全部相同,而列表中数据类型不必相同,所以在通用性能方面Numpy数组不及Python列表;
- 在列表(list)中保存的是数据的存放的地址,例如list1=[1,2,3,'a']需要4个指针和四个数据,增加了存储开销和降低了访问效率。而NumPy的数组是为了精确便捷的处理庞大的类似的数据而产生的,存储效率要比列表快很多;
- NumPy数组可以进行四则运算(无需编写循环),它会对数组中的每一个元素对应进行运算;而列表只能使用加号进行拼接,拼接之后会形成一个新的列表;
3 NumPy的基础使用
NumPy 定义了一个 n 维数组对象,简称 ndarray。它也被别名所知 array
,ndarray对象的几个常用属性:
ndarray对象的属性 | 含义 |
---|---|
ndarray.ndim | 维度数量(轴数)0-D(标量)/1-D/2-D/3-D等 |
ndarray.shape | 数组的形状,一个表示各维度长度的元组(元组的长度为ndim) |
ndarray.dtype | 维度空间内数据类型的对象 |
ndarray.size | 元素总个数 |
ndarray.itemsize | 数组中每个元素的字节大小,例如:元素为 float64 类型的数组的 itemsize 为8(=64/8) |
NumPy dtype(数据类型)如下:
序号 | 数据类型 | python定义的的字符代码 | 语言描述 |
---|---|---|---|
1 | bool_ | b | 布尔型数据类型(True 或者 False) |
2 | int_ | 默认整数类型,类似于 C 语言中的 long,取值为 int32 或 int64 | |
3 | intc | 和 C 语言的 int 类型一样,一般是 int32 或 int 64 | |
4 | intp | 用于索引的整数类型(类似于 C 的 ssize_t,通常为 int32 或 int64) | |
5 | int8 | i1 | 代表与1字节相同的8位整数。值的范围是-128到127。 |
6 | int16 | i2 | 代表 2 字节(16位)的整数。范围是-32768至32767。 |
7 | int32 | i4 | 代表 4 字节(32位)整数。范围是-2147483648至2147483647。 |
8 | int64 | i8 | 表示 8 字节(64位)整数。范围是-9223372036854775808至9223372036854775807。 |
9 | uint8 | u1 | 代表1字节(8位)无符号整数。 |
10 | uint16 | u2 | 2 字节(16位)无符号整数。 |
11 | uint32 | u4 | 4 字节(32位)的无符号整数。 |
12 | uint64 | u8 | 8 字节(64位)的无符号整数。 |
13 | float_ | float64 类型的简写。 | |
14 | float16 | f2 | 半精度浮点数,包括:1 个符号位,5 个指数位,10个尾数位。 |
15 | float32 | f4 | 单精度浮点数,包括:1 个符号位,8 个指数位,23个尾数位。 |
16 | float64 | f8 | 双精度浮点数,包括:1 个符号位,11 个指数位,52个尾数位。 |
17 | complex_ | 复数类型,与 complex128 类型相同。 | |
18 | complex64 | c8 | 表示实部和虚部共享 32 位的复数。 |
19 | complex128 | c16 | 表示实部和虚部共享 64 位的复数。 |
20 | str_ | a | 表示字符串类型 |
21 | string_ | 表示字节串类型 |
3.1 创建
有几种方法可以创建数组:
1 使用array()函数创建一个NumPy ndarray对象
从常规的python列表或元组中创建数组:
import os
import numpy as np
# 可以将列表、元组或任何类似数组的对象传递给 array() 方法,然后它将被转换为 ndarray
# 函数原型: numpy.array(object, dtype = None, copy = True, order = None,ndmin = 0)
arr = np.array([1, 2, 3, 4, 5])
# arr = np.array((1, 2, 3, 4, 5))
print(arr)
print(type(arr))
print(arr.ndim)
print(arr.shape)
print(arr.dtype)
print(arr.size)
执行结果为:
[1 2 3 4 5]
<class 'numpy.ndarray'>
1
(5,)
int64
5
如下,使用array()函数创建0、1、2、3 维数组
数组可以拥有任意数量的维。
在创建数组时,可以使用 ndmin 参数定义维数,也可以用dtype显式指定数组的类型。
import numpy as np
a = np.array(42)
b = np.array([1, 2, 3, 4, 5])
c = np.array([[1, 2, 3], [4, 5, 6]])
d = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])
# 打印维度
print(a.ndim)
print(b.ndim)
print(c.ndim)
print(d.ndim)
运行结果为:
0
1
2
3
创建数组时,使用 ndmin参数或dtype参数
import numpy as np
# 使用 `ndmin` 参数定义维数
e = np.array( [1, 2, 3, 4], ndmin=2 )
print("ndim is ", e.ndim, "shape is", e.shape)
# 用dtype显式指定数组的类型
f = np.array( [ [1,2,3,4], [3,4,5,6] ], dtype=complex )
print(f)
运行结果为:
ndim is 2 shape is (1, 4)
# f is:
[[1.+0.j 2.+0.j 3.+0.j 4.+0.j]
[3.+0.j 4.+0.j 5.+0.j 6.+0.j]]
2 使用zeros/ones/empty等函数创建数组
函数 | 作用 |
---|---|
np.zeros | 创建一个由0组成的数组 |
np.ones | 创建一个由1组成的数组 |
np.empty | 函数empty 创建一个数组,其初始内容是随机的,取决于内存的状态 |
np.arange(start, stop, step) | NumPy提供了一个类似于range 的函数 |
np.linspace(start, stop, num) | 与Numpy arange类似,只不过可以生成等间隔的数据,其中num表示个数而非step |
NumPy提供random
模块用来创建随机数组:
函数 | 作用 |
---|---|
np.random.random(size=None) | 用于在区间[0,1) 中生成均匀分布的随机数或随机数数组,数组大小为size。 |
np.random.rand(d0, d1, ..., dn) | rand 函数在区间[0,1) 中生成服从均匀分布的随机数或随机数数组。 |
np.random.randn(d0, d1, ..., dn) | randn 函数可以生成服从正态分布的随机数或随机数数组 |
np.random.randint(low, high=None, size=None, dtype=int) | randint函数可以生成给定上下限范围的随机数,默认的数据类型是np.in t |
例子:
import numpy as np
arr = np.ones((2,3,4), dtype=np.int16) # dtype can also be specified
print(arr)
arr1 = np.arange( 0, 30, 5 )
print(arr1)
arr2 = np.linspace( 0, 30, 5 )
print(arr2)
打印结果为:
# arr的shape为(2,3,4)
[[[1 1 1 1]
[1 1 1 1]
[1 1 1 1]]
[[1 1 1 1]
[1 1 1 1]
[1 1 1 1]]]
# 以下可以对比了解arange与linspace入参的不同
# arr1
[ 0 5 10 15 20 25]
# arr2
[ 0. 7.5 15. 22.5 30. ]
生成随机数组的例子:
import numpy as np
arr1 = np.random.random((2,3))
print(arr1)
# random.rand 与 random.random功能相同,只是传入参数不同,历史原因
arr2 = np.random.rand(2,3)
print(arr2)
arr3 = np.random.randint(2,10,size = [2,3])
print(arr3)
打印结果为:
# arr1
[[0.00944554 0.20582375 0.78710838]
[0.14880526 0.41143975 0.04881135]]
# arr2
[[0.56776322 0.69684011 0.39539963]
[0.46664393 0.7757049 0.02909985]]
# arr3
[[9 3 6]
[6 3 4]]
3.2 改变形状
常见的需求是改变数组形状、扩充数组维度等
1 reshape方法
常用的是reshape与resize,其稍有差别。
import numpy as np
arr = np.floor(10*np.random.random((3,4)))
print(arr.shape)
# 完全展开为1D,默认按行读取,返回的是view,np.flatten返回一份拷贝
arr1 = arr.ravel()
print(arr1)
# reshape改变形状,元素个数要相等才能转换,返回一个新的数组,原数组不受影响
arr2 = arr.reshape(6,2)
print(arr2)
# resize改变形状,元素个数要相等才能转换,返回None,直接操作原数组
arr3 = arr.resize(2, 6)
print(arr3)
print(arr)
执行log为:
# arr
(3, 4)
# arr1 按行展开
[6. 7. 6. 9. 3. 9. 7. 9. 1. 6. 2. 6.]
# arr2 reshape
[[6. 7.]
[6. 9.]
[3. 9.]
[7. 9.]
[1. 6.]
[2. 6.]]
# arr3 resize,返回值为None,直接修改原数组
None
[[6. 7. 6. 9. 3. 9.]
[7. 9. 1. 6. 2. 6.]]
2 扩充数组维度expand_dims
有时候需要扩充数组维度:
1、np.newaxis扩充矩阵维度
2、np.expand_dims扩充矩阵维度
3、np.squeeze删除矩阵中维度大小为1的维度
import numpy as np
x = np.arange(8).reshape(2, 4)
print(x.shape)
print(x)
# 添加第0维,输出shape -> (1, 2, 4)
x1 = x[np.newaxis, :]
print(x1.shape)
print(x1)
# 添加第0维, 输出shape -> (1, 2, 4)
x2 = np.expand_dims(x, axis=0)
print(x2.shape)
print(x2)
# 添加第1维, 输出shape -> (2, 1, 4)
x3 = np.expand_dims(x, axis=1)
print(x3.shape)
print(x3)
# 添加第1维, 输出shape -> (2, 4, 1)
x4 = np.expand_dims(x, axis=2)
print(x4.shape)
print(x4)
# np.squeeze删除矩阵中维度大小为1的维度
x5 = np.squeeze(x4)
print(x5.shape)
print(x5)
输出结果为:
# x
(2, 4)
[[0 1 2 3]
[4 5 6 7]]
# x1 np.newaxis扩充矩阵维度
(1, 2, 4)
[[[0 1 2 3]
[4 5 6 7]]]
# x2 np.expand_dims(x, axis=0)
(1, 2, 4)
[[[0 1 2 3]
[4 5 6 7]]]
# x3 np.expand_dims(x, axis=1)
(2, 1, 4)
[[[0 1 2 3]]
[[4 5 6 7]]]
# x4 np.expand_dims(x, axis=2)
(2, 4, 1)
[[[0]
[1]
[2]
[3]]
[[4]
[5]
[6]
[7]]]
# x5 删除矩阵中维度大小为1的维度
(2, 4)
[[0 1 2 3]
[4 5 6 7]]
3.3 索引与迭代
一维的数组可以进行索引、切片和迭代操作的,就像列表和其他Python序列类型一样。
多维的数组每个轴可以有一个索引,这些索引以逗号分隔的元组给出:
例子:
import numpy as np
b = np.random.randint(2, 100, (5,4))
print(b)
print(b[2,3])
结果为:
[[89 40 10 62]
[72 33 19 88]
[54 74 42 9]
[73 13 86 8]
[52 28 46 34]]
9
NumPy 迭代器对象 numpy.nditer 提供了迭代访问一个或者多个数组元素的方式。
import numpy as np
a = np.arange(6).reshape(2,3)
print(a)
# 行优先(默认)
print("order = row")
for x in np.nditer(a, order='C'):
print (x, end=", " )
print ('\n')
# 列优先
print("order = col")
for x in np.nditer(a, order='F'):
print (x, end=", " )
print ('\n')
# 或者使用python列表方法访问
print("python list item")
for x in a:
for y in x:
print(y, end=", ")
print ('\n')
执行输出为:
# origin
[[0 1 2]
[3 4 5]]
# 行顺序
order = row
0, 1, 2, 3, 4, 5,
# 列顺序
order = col
0, 3, 1, 4, 2, 5,
# python list方法迭代
python list item
0, 1, 2, 3, 4, 5,
3.4 numpy的基本数学运算
见下表,方便查找
运算 | 含义 |
---|---|
算术运算 | 做算术运算时,输入数组必须具有相同的形状,或者符合数组的广播规则,才可以执行运算 |
np.add | 加 |
np.subtract | 减 |
np.multiply | 乘 |
np.divide | 除 |
np.reciprocal | 倒数 |
numpy.power() | 幂函数 |
numpy.mod() | 求余函数,与 numpy.remainder() 的作用相同 |
位运算 | |
np.bitwise_and() | 位与 |
np.bitwise_or() | 位或 |
np.invert() | 按位取反 |
np.left_shift() | 左移 |
np.right_shift() | 右移 |
数学函数 | |
np.sin / np.arcsin | sin函数 |
np.cos / np.arccos | cos函数 |
np.tan / np.arctan | tan函数 |
numpy.around() | 将数值四舍五入到指定的小数位上 |
numpy.floor() | 向下取整 |
numpy.ceil() | 向上取整 |
统计函数 | |
np.amin() | 沿指定的轴,查找数组中元素的最小值,并以数组形式返回; |
np.amax() | 沿指定的轴,查找数组中元素的最大值,并以数组形式返回 |
np.median() | 用于计算 a 数组元素的中位数(中值) |
np.mean() | 该函数表示沿指定的轴,计算数组中元素的算术平均值(即元素之总和除以元素数量) |
np.average() | 加权平均值是将数组中各数值乘以相应的权数,然后再对权重值求总和,最后以权重的总和除以总的单位数(即因子个数) |
np.var() | 方差,在统计学中也称样本方差 |
np.std() | 标准差是方差的算术平方根,用来描述一组数据平均值的分散程度。 |
线性代数 | |
np.dot | 两个数组的点积。 |
np.vdot | 两个向量的点积,与 dot() 函数不同 |
np.inner() | 两个数组的内积。 |
np.matmul() | 两个数组的矩阵积。 |
4 其它
4.1 python将numpy数组保存为bmp格式图片
在ai图片识别时,有时需要将numpy数组保存为bmp格式图片,方便调试,可用如下脚本。
import numpy as np
from PIL import Image
# 创建56x56x3的随机数组作为图像
img_array = np.random.rand(56, 56, 3) * 255
# PIL的Image.fromarray()方法不支持直接从int8类型的numpy数组转换为图像。所以需要转为uint8
img_array = img_array.astype(np.uint8)
# 使用PIL将numpy数组转换为图像
img = Image.fromarray(img_array)
# 保存为BMP格式
img.save('image.bmp')
参考: