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  阅读(1383)  评论(0)    收藏  举报