计算机视觉前置知识-Numpy基础

如你所见,这篇文章是计算机视觉的前置基础知识。今年是2024年,计算机视觉包括计算机图形学领域科研的主流工具是Pytorch。耐心看完你就掌握了计算机视觉所需要的 Numpy 基础了!Numpy是Python中科学计算的核心库。它提供了一个高性能的多维数组对象 Array,以及相应的处理工具。(Arrys 和 Lists 分不清?快来看看我的另一篇文章:计算机视觉前置知识-Python基础-CSDN博客

这个专栏我是按照斯坦福李飞飞CS231课程官网的知识结构写的,但不是完全翻译搬运,有纰漏的话,please feel free to tell me!

1 Arrays(数组)介绍 - 高性能的多维数组对象!

这里我们先看官网介绍,再补充解释:

numpy 数组是一个由相同类型的值组成的 grid(网格),并由非负整数 tuple(元组)进行索引。维数是数组的 rank(秩);数组的形状是一个整数 tuple(元组),给出了数组在每个维度上的大小。

我们用嵌套的 Python 列表初始化 numpy arrays,并使用方括号访问元素:

import numpy as np

a = np.array([1, 2, 3])   # Create a rank 1 array
print(type(a))            # Prints "<class 'numpy.ndarray'>"
print(a.shape)            # Prints "(3,)"
print(a[0], a[1], a[2])   # Prints "1 2 3"
a[0] = 5                  # Change an element of the array
print(a)                  # Prints "[5, 2, 3]"

b = np.array([[1,2,3],[4,5,6]])    # Create a rank 2 array
print(b.shape)                     # Prints "(2, 3)"
print(b[0, 0], b[0, 1], b[1, 0])   # Prints "1 2 4"
print(b)                           # Prints "[[1 2 3]
                                   #          [4 5 6]]"

运行结果:

Numpy还提供了许多创建数组的函数,numpy默认生成列表中的值是小数:

import numpy as np

a = np.zeros((2,2))   # Create an array of all zeros
print(a)              # Prints "[[ 0.  0.]
                      #          [ 0.  0.]]"

b = np.ones((1,2))    # Create an array of all ones
print(b)              # Prints "[[ 1.  1.]]"

c = np.full((2,2), 7)  # Create a constant array
print(c)               # Prints "[[ 7.  7.]
                       #          [ 7.  7.]]"

d = np.eye(2)         # Create a 2x2 identity matrix
print(d)              # Prints "[[ 1.  0.]
                      #          [ 0.  1.]]"

e = np.random.random((2,2))  # Create an array filled with random values
print(e)                     # Might print "[[ 0.91940167  0.08143941]
                             #               [ 0.68744134  0.87236687]]"

Numpy提供了大量的数字数据类型,可以用来构造数组。当您创建数组时,Numpy会尝试猜测数据类型,但是构造数组的函数通常还包含一个可选参数(dtype=np.XX)来显式指定数据类型。下面是一个例子:

import numpy as np

x = np.array([1, 2])   # Let numpy choose the datatype
print(x.dtype)         # Prints "int64"

x = np.array([1.0, 2.0])   # Let numpy choose the datatype
print(x.dtype)             # Prints "float64"

x = np.array([1, 2], dtype=np.int64)   # Force a particular datatype
print(x.dtype)                         # Prints "int64"

 以上就是官网的描述,懂了又没懂?接下来我们从 array 的几个属性来说,分别是 ndarray.ndim(数组的维度)、ndarray.shape(数组的形状)ndarray.size(数组的元素总数)ndarray.dtype(数组中元素的数据类型)ndarray.itemsize(数组中每个元素的字节大小)

1.1 ndarray.ndim - 数组的维度

  • 解释:这是数组的维度(或阶数,或 rank(秩))。比如一维数组、二维数组或多维数组。

  • 类比:可以类比为我们看到的对象在不同维度的表现。比如一条直线是一维,二维是一个平面,三维是一个立体的空间。

  • 示例:

    a = np.array([1, 2, 3])
    b = np.array([[1, 2, 3], [4, 5, 6]])
    print(a.ndim)  # 输出 1
    print(b.ndim)  # 输出 2
    

 1.2 ndarray.shape - 数组的形状

  • 解释:返回一个 tuple(元组),表示数组在每个维度的大小。
  • 类比:类似于一个盒子的尺寸。比如一个二维盒子的长和宽,三维盒子还会有高度。
  • 示例:
    import numpy as np
    
    a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
    b = np.array([[[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]],[[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]])
    
    print(a.ndim)   # 输出 2
    print(a.shape)  # 输出 (3, 4)
    print(b.ndim)   # 输出 3
    print(b.shape)  # 输出 (2, 3, 5)

 1.3 axis - 数组的轴

  • :数组的每个维度被称为一个轴(axis)。一维数组只有一个轴,二维数组有两个轴,三维数组有三个轴,依此类推。
  • 类比:想象一张纸作为二维数组。如果你在纸上画行和列,行可以看作一个轴,列可以看作另一个轴。再想象一个三维盒子,每一维都可以被视为一个轴,比如宽度、长度和高度。
  • 举例:
    import numpy as np
    
    a = np.array([1, 2, 3])
    print(a)
    print(a.ndim) # 对于一维数组,唯一的轴是 axis=0。
    
    b = np.array([[1, 2, 3],[4, 5, 6]])
    print(b) 
    print(b.ndim) # 对于二维数组,轴 0(axis=0):沿着行的方向(即垂直方向)。
                              # 轴 1(axis=1):沿着列的方向(即水平方向)。
    print(np.sum(b, axis=0))  # 沿着行方向求和,输出 [5 7 9] --> [1+4, 2+5, 3+6]
    print(np.sum(b, axis=1))  # 沿着列方向求和, 输出 [6 15] --> [1+2+3, 4+5+6]

 1.4 ndarray.size - 数组的元素总数

  • 解释:数组中所有元素的总数,即 shape 中各维度的乘积。

  • 类比:比如一个 3x4 的表格里一共有 12 个格子。

  • 示例:

    import numpy as np
    
    a = np.array([[[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]],[[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]])
    print(a.shape) # 输出 (2, 3, 5)
    print(a.size)  # 输出 6,等于shape的所有值相乘 
    

2 Array indexing(数组函数)- 为科学计算而生!

2.1 Slicing(切片)

与Python list(列表)类似,numpy数组可以被切片。由于数组可能是多维的,因此必须为数组的每个维度指定一个 slice:

import numpy as np

# Create the following rank 2 array with shape (3, 4)
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])

# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
# [[2 3]
#  [6 7]]
b = a[:2, 1:3]

# A slice of an array is a view into the same data, so modifying it
# will modify the original array.
print(a[0, 1])   # Prints "2"
b[0, 0] = 77     # b[0, 0] is the same piece of data as a[0, 1]
print(a[0, 1])   # Prints "77"

2.2 Integer array indexing(整数数组索引)

当我们使用 slicing(切片)对numpy数组进行索引时,生成的将始终是原始数组的子数组。相对的,整数数组索引允许我们不按照顺序、不连续地访问数组中的任意元素。

构造一个2维数组a:

import numpy as np

a = np.array([[1, 2], [3, 4], [5, 6]])
print(a)
# 输出 [[1 2]
      # [3 4]
      # [5 6]]

假设我们想要从 a 中选择 (0, 1)(2, 0) 这两个位置的元素:

# 整数数组索引
result = a[[0, 2], [1, 0]]  # 索引 (0,1) 和 (2,0) 的元素
print(result)
# 输出 [2 5]
整数数组索引切片
用法指定具体的索引位置指定范围  start:end:step
结果形状通常返回一维数组保持子集的形状
选择元素的方式任意选择,可以不连续、不规则连续范围选择
返回结果是原数组的副本是原数组的视图
典型应用场景非连续、灵活选择元素提取连续区域的子数组
效率相对较慢(由于复制元素)更快(不复制数据)

2.3 Boolean array indexing(布尔值数组索引)

布尔数组索引允许我们挑选数组中的任意元素。这种类型的索引通常用于选择满足某些条件的数组元素:

import numpy as np

a = np.array([[1,2], [3, 4], [5, 6]])

bool_idx = (a > 2)   # Find the elements of a that are bigger than 2;
                     # this returns a numpy array of Booleans of the same
                     # shape as a, where each slot of bool_idx tells
                     # whether that element of a is > 2.

print(bool_idx)      # Prints "[[False False]
                     #          [ True  True]
                     #          [ True  True]]"

# We use boolean array indexing to construct a rank 1 array
# consisting of the elements of a corresponding to the True values
# of bool_idx
print(a[bool_idx])  # Prints "[3 4 5 6]"

# We can do all of the above in a single concise statement:
print(a[a > 2])     # Prints "[3 4 5 6]"

3 Array math -  梦回线性代数!

基本数学函数在数组上按元素操作,并且可以作为运算符重载和numpy模块中的函数使用:

import numpy as np

x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)

# Elementwise sum; both produce the array
# [[ 6.0  8.0]
#  [10.0 12.0]]
print(x + y)
print(np.add(x, y))

# Elementwise difference; both produce the array
# [[-4.0 -4.0]
#  [-4.0 -4.0]]
print(x - y)
print(np.subtract(x, y))

# Elementwise product; both produce the array
# [[ 5.0 12.0]
#  [21.0 32.0]]
print(x * y) # *是元素乘法,而不是矩阵乘法
print(np.multiply(x, y))

# Elementwise division; both produce the array
# [[ 0.2         0.33333333]
#  [ 0.42857143  0.5       ]]
print(x / y)
print(np.divide(x, y))

# Elementwise square root; produces the array
# [[ 1.          1.41421356]
#  [ 1.73205081  2.        ]]
print(np.sqrt(x))

3.1 ndarray.dot - Dot product(点积)/ Inner Product(内积)

在线性代数中,点积(<x,w>)可能表示 x 中的值根据权重 w 的加权平均,或 x 在 y 坐标系的投影。

import numpy as np

x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])

v = np.array([0,0.1])
w = np.array([1, 2])


print(v.dot(w))
print(np.dot(w, v))
# 都输出 0.2

print(x.dot(v))
print(np.dot(x, v))
# 都输出 [0.2 0.4]

print(x.dot(y))
print(np.dot(x, y))
# 都输出 [[19 22]
      # [43 50]]

3.2 ndarray.sum - 元素和

Numpy为在数组上执行计算提供了许多有用的函数;其中最有用的一个是sum:

import numpy as np

x = np.array([[1,2],[3,4]])

print(np.sum(x))  # Compute sum of all elements; prints "10"
print(np.sum(x, axis=0))  # Compute sum of each column; prints "[4 6]"
print(np.sum(x, axis=1))  # Compute sum of each row; prints "[3 7]"

3.3 ndarray.T - Transpose(转置)

除了使用数组计算数学函数外,我们还经常需要重塑或以其他方式操作数组中的数据。这类运算最简单的例子是矩阵的转置;要转置矩阵,只需使用数组对象的T属性:

import numpy as np

x = np.array([[1,2], [3,4]])
print(x)    # Prints "[[1 2]
            #          [3 4]]"
print(x.T)  # Prints "[[1 3]
            #          [2 4]]"

# Note that taking the transpose of a rank 1 array does nothing:
v = np.array([1,2,3])
print(v)    # Prints "[1 2 3]"
print(v.T)  # Prints "[1 2 3]"

3.4 Broadcasting - 广播机制

广播是一种强大的机制,它允许numpy在执行算术运算时处理不同形状的数组。通常用在哪里呢?我们有一个较小的数组和一个较大的数组,我们希望多次使用较小的数组来对较大的数组执行一些操作。

例如,假设我们想给矩阵的每一行加上一个常数向量。我们可以:

import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
vv = np.tile(v, (4, 1))   # 沿着轴0复制了4份,沿着轴1复制了1份
print(vv)                 # Prints "[[1 0 1]
                          #          [1 0 1]
                          #          [1 0 1]
                          #          [1 0 1]]"
y = x + vv  # Add x and vv elementwise
print(y)  # Prints "[[ 2  2  4
          #          [ 5  5  7]
          #          [ 8  8 10]
          #          [11 11 13]]"

好消息,Numpy广播允许我们在不实际创建多个v副本的情况下执行此计算,考虑使用广播的这个版本:

import numpy as np

# We will add the vector v to each row of the matrix x,
# storing the result in the matrix y
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = x + v  # Add v to each row of x using broadcasting
print(y)  # Prints "[[ 2  2  4]
          #          [ 5  5  7]
          #          [ 8  8 10]
          #          [11 11 13]]"

你学废了吗?代码有些是直接搬运官网的所以没有翻译(实在是干不动了),之后如果有小伙伴需要我再来填坑!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值