Appearance

NumPy 学习

byml2024-07-15CV

数据类型

数据类型

  • 布尔型
    • bool_
  • 有符号整型
    • int_:默认的整数类型,一般情况下是int32int64
    • intc:与C语言中的int大小相同,一般情况下是int32int64
    • intp:一般情况下是int32int64
    • int8、int16、int32、int64
  • 无符号整型
    • uint8、uint16、uint32、uint64
  • 浮点型
    • float_float64的简写
    • float16、float32、float64
  • 复数型
    • complex_complex128的简写
    • complex64、complex128:实数和虚数均为双32/64位浮点型

数据类型对象(dtype)

  • dtype(object, align, copy)
    • object:要转换为的数据类型对象
    • align:如果为 true,填充字段使其类似 C 的结构体。
    • copy:复制 dtype 对象,如果为 False,则是对内置数据类型对象的引用

数组(ndarray)

用于存放同类型元素的多维数组,链表实现 创建:array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)

  • object:数组或嵌套的数列
  • dtype:数组的数据类型
  • copy:是否需要复制对象生成
  • order:创建数组的样式(C为行向量,F为列向量,A为任意方向)
  • subok:默认返回一个与基类类型一致的数组
  • ndmin:指定生成数组的最小维度 属性:
  • ndim:秩,即轴的数量或维度的数量
  • shape:数组的维度,对于矩阵,nm
  • size:数组元素的总个数,相当于.shapen×m 的值
  • dtype:对象的元素类型
  • itemsize:对象中每个元素的大小,以字节为单位
  • flags:对象的内存信息
  • real:元素的实部
  • imag:元素的虚部

创建

初始化创建

  • numpy.empty(shape, dtype = float, order = 'C'):创建未初始化的数组
  • numpy.zeros(shape, dtype = float, order = 'C'):创建全 0 数组
  • numpy.ones(shape, dtype = None, order = 'C'):创建全 1 数组

从数组创建

  • numpy.zeros_like(a, dtype=None, order='K', subok=True, shape=None):创建与数组 a 相同大小的全 0 数组
  • numpy.ones_like(a, dtype=None, order='K', subok=True, shape=None):创建与数组 a 相同大小的全 1 数组

从其他对象创建

  • numpy.asarray(a, dtype = None, order = None):从元组、列表等任意形式的 a 创建数组
  • numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0):从 buffer 流式读入创建数组
  • numpy.fromiter(iterable, dtype, count=-1):从 iterable 迭代器读入创建数组

从数列创建

  • numpy.arange(start, stop, step, dtype):从范围创建数组(前闭后开)
  • numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None):从等差数列创建一维数组
  • numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None):从等比数列创建一维数组

索引和切片

整数数组索引

  • 使用一个数组(列表)访问另一个数组
a = numpy.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(a[[1, 2], [1, 2]])
## 效果是分别获取到了位于 (1, 1) 和 (2, 2) 位置上的 5 和 9,故输出为 [5, 9]
  • 用于索引的数组表示的是指定下标,即 [[a1, a2, a3], [b1, b2, b3], [c1, c2, c3]] 获取到的会是 array[array[a1, b1, c1], array[a2, b2, c2], array[a3, b3, c3]]

切片索引

  • 语法:a[<开始>:<结束>:<步长>, <开始>:<结束>:<步长>]
    • 开始默认为 0,结束默认为长度,步长默认为 1
    • 如果 <开始><结束> 中出现负数 x,等价于 size+x,即若 a.shape == (4, 4),则 a[1:-1, 1:-2] == a[1:3, 1:2]
  • 使用省略号代替取某一个维度的全部,如:a.shape == (3, 3)a[0:3:1, 0:1:1] == a[..., 0:1] == a[::, :1]
索引和切片的实现

通过重写 __getitem__(self, item) 方法,item 传入的内容会是 slice 对象或 Ellipsis 对象的元组,据此可以对维度进行拆分。效果如下:

class A:
  def __getitem__(self, item):
      print(item)
a = A()
a[1:2:3, ..., 4:5:6]
## output: (slice(1, 2, 3), Ellipsis, slice(4, 5, 6))

布尔索引

  • 使用布尔运算来获取一个数组中所有满足条件的值
a = numpy.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(a[a > 5])
## 输出:
## [6, 7, 8, 9]

广播

当运算中的 2 个数组的形状不同时,自动触发广播机制,以使得运算可以继续进行。

广播的规则

  • 让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在前面加 1 补齐。
    • [1, 2] + [[1, 2], [3, 4]] 会先转化为 [[1, 2]] + [[1, 2], [3, 4]],反映在 shape 上,就是第一个加数的 shape(2) 变成了 (1, 2),与第二个加数的 (2, 2) 长度相同
  • 输出数组的形状是输入数组形状的各个维度上的最大值。
  • 如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错。
  • 当输入数组的某个维度的长度为 1 时,沿着此维度运算时都用此维度上的第一组值。
    • [[1, 2]] + [[1, 2], [3, 4]] 会转化为 [[1, 2], [1, 2]] + [[1, 2], [3, 4]],将第一行的 [1,2] 进行复用 简单理解,对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:
  • 数组拥有相同形状。
  • 当前维度的值相等。
  • 当前维度的值有一个是 1。 若条件不满足,抛出 ValueError: frames are not aligned
注意

在 numpy 中,默认两个数组相乘是将对应元素相乘,而非矩阵乘法,因此,直接将两个 ndarray 相乘,可能触发广播机制,例如 np.array([1, 2]) * np.array([[1, 2], [3, 4]]) 的结果是 [[1, 2], [1, 2]] * [[1, 2], [3, 4]] = [[1*1, 2*2][1*3, 2*4]] = [[1, 4], [3, 8]]

数组操作

reshape 改变形状

  • numpy.reshape(arr, newshape, order='C')
    • arr:要修改形状的数组
    • newshape:整数或者整数数组,新的形状应当兼容原有形状
    • order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'K' -- 元素在内存中的出现顺序。

flat 迭代

  • numpy.ndarray.flat 是一个数组元素迭代器

flatten 拷贝展开

  • ndarray.flatten(order='C') 返回按顺序展开,并拷贝一份后的数组,不会修改原数组
    • order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'K' -- 元素在内存中的出现顺序。

ravel 展开

  • numpy.ravel(a, order='C') 返回按顺序展开的数组,会修改原数组
    • order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'K' -- 元素在内存中的出现顺序。

翻转

矩阵(numpy.matlib)

矩阵总是二维的,而 ndarray 是一个 n 维数组。 两个对象都是可互换的。

线性代数

  • numpy.dot(a, b, out=None)
    • 对于两个一维的数组,计算的是这两个数组对应下标元素的乘积和(数学上称之为向量点积);
    • 对于二维数组,计算的是两个数组的矩阵乘积;
    • 对于多维数组,它的通用计算公式如下,即结果数组中的每个元素都是:数组a的最后一维上的所有元素与数组b的倒数第二维上的所有元素的乘积和:dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])
    • 参数 out: ndarray, 可选,用来保存dot()的计算结果
  • numpy.vdot(a, b, out=None):两个向量的点积。如果第一个参数是复数,那么它的共轭复数会用于计算。如果参数是多维数组,它会被展开。
  • numpy.inner(a, b, out=None):返回一维数组的向量内积。对于更高的维度,它返回最后一个轴上的和的乘积。