python之numpy模块

1 NumPy是什么?

NumPy (全称:Numeric Python)是python的第三方模块,主要用于计算、处理一维或多维数组。

Numpy通常与Scipy(Python科学计算库),Matplotlib(Python绘图库),Pandas(Python数据处理)等组合使用,这样可以广泛的代替Matlab的使用。

image-20230630182746638

2 为什么使用NumPy?

Python中没有内置数组(array)类型,只有列表(list),但处理速度很慢,NumPy 旨在提供一个比传统 Python 列表快 50 倍的数组对象。

NumPy与列表的不同点有:

  1. NumPy中数组数据元素类型必须全部相同,而列表中数据类型不必相同,所以在通用性能方面Numpy数组不及Python列表;
  2. 在列表(list)中保存的是数据的存放的地址,例如list1=[1,2,3,'a']需要4个指针和四个数据,增加了存储开销和降低了访问效率。而NumPy的数组是为了精确便捷的处理庞大的类似的数据而产生的,存储效率要比列表快很多;
  3. 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.int

例子:

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,其稍有差别。

image-20230702161002457

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')

参考:

  1. NumPy
  2. 快速入门教程 | NumPy
  3. w3school
posted @ 2023-07-02 22:24  sureZ_ok  阅读(854)  评论(0编辑  收藏  举报