1.1.1 Numpy 中的数据格式#
numpy 在数据类型上相比原生 python 更接近于 C,光整数类型就分了 int32,int64 等,浮点数也有 float32,float64 等,在字长和类型上进行了更好地统一,方便 numpy 与 C 的无缝衔接
而我们之所以引入 Numpy,一个很重要的原因就是 Numpy 数组可以很好地模拟向量与矩阵运算。我们可以通过 numpy.array 创建一个数组,例如:
import numpy as np
x = np.array([1, 2, 3, 4, 5])
但是 numpy 数组和原生的 Python 列表有很大的区别,Numpy 数组是同质的,也就是说 Numpy 数组中的所有元素都必须是同一种数据类型,而 Python 列表可以包含不同类型的数据。
定义一个数组的数据类型:
x = np.array([1,2,3],dtye=np.int32)
numpy 数组与其他数据类型之间可以进行快速的数据转换,例如,列表、元组可以转为 numpy.array,而 numpy.array 也可以转为列表、元组等其他数据类型。
# 方法1:直接类型转换
x=list(x)
# 方法2:使用 numpy 的 tolist() 方法
x=x.tolist()
修改 numpy 数组中的数据元素类型,可以使用 astype
方法:
x.astype(np.float32)
快速创建数组的方法有很多,最常用的包括:
- numpy.zeros((m,n)):创建一个 m 行 n 列的全零数组
import numpy as np
# 创建一个2x3的零矩阵
zero_matrix = np.zeros((2, 3))
print(zero_matrix)
# 输出:
# [[0. 0. 0.]
# [0. 0. 0.]]
- numpy.ones((m,n)):创建一个 m 行 n 列的全一数组
import numpy as np
# 创建一个2x3的全1矩阵
ones_matrix = np.ones((2, 3))
print(ones_matrix)
# 输出:
# [[1. 1. 1.]
# [1. 1. 1.]]
注意,这两个方法传进去的参数都是元组!要记得打两次括号!当然,如果只传入一个数字也是可以的,它会默认给你创建一个 n*n 的方阵。
- numpy.full((m,n), fill_value):创建一个 m 行 n 列的全 fill_value 数组
import numpy as np
# 创建一个2x3的数组,所有元素都是42
full_matrix = np.full((2, 3), 42)
print(full_matrix)
# 输出:
# [[42 42 42]
# [42 42 42]]
- numpy.arange(start,stop,step):创建一个从 start 到 stop 的等差数列,步长为 step 的数组,step 默认为 1
import numpy as np
arrange_array = np.arange(0,5)
print(arrange_array)
# 输出:
# [0 1 2 3 4]
arange_array2 = np.arange(0,10,2)
print(arange_array2)
# 输出:
# [0 2 4 6 8]
注意:
arange
函数的参数是左闭右开区间,即包含 start 不包含 stop。 numpy 中的arange
函数与 Python 内置的range
函数类似,但可以返回实打实的向量,而不是一个迭代器。
- numpy.linspace(start, stop, num):创建一个从 start 到 stop 的等差数列,包含 num 个元素
基于元素数量 num 均匀分配
import numpy as np
# 生成从0到10的5个等间隔的数
linspace_array = np.linspace(0, 10, 5)
print(linspace_array)
# 输出:
# [ 0. 2.5 5. 7.5 10. ]
- numpy.diag(array,k=0):创建一个对角矩阵,array 为对角线上的元素,k 为对角线的偏移量(k=0 表示主对角线)
import numpy as np
# 使用一维数组创建对角矩阵
diag_matrix = np.diag([1, 2, 3])
print(diag_matrix)
# 输出:
# [[1 0 0]
# [0 2 0]
# [0 0 3]]
# 使用二维数组提取对角线元素
diag_elements = np.diag(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
print(diag_elements)
# 输出:
# [1 5 9]
- numpy.eye(N, M=None, k=0, dtype=float, order=‘C’):创建一个 N 行 M 列的单位矩阵,k 为对角线的偏移量(k=0 表示主对角线)
import numpy as np
# 创建一个3x3的单位矩阵
eye_matrix = np.eye(3)
print(eye_matrix)
# 输出:
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
# 创建一个3x4的矩阵,其主对角线元素为1,其余为0
eye_matrix_3x4 = np.eye(3, 4)
print(eye_matrix_3x4)
# 输出:
# [[1. 0. 0. 0.]
# [0. 1. 0. 0.]
# [0. 0. 1. 0.]]
# 创建一个3x3的矩阵,其对角线向上偏移一个单位(次对角线为1)
eye_matrix_k1 = np.eye(3, k=1)
print(eye_matrix_k1)
# 输出:
# [[0. 1. 0.]
# [0. 0. 1.]
# [0. 0. 0.]]
# 创建一个3x3的矩阵,其对角线向下偏移一个单位(超对角线为1)
eye_matrix_k_1 = np.eye(3, k=-1)
print(eye_matrix_k_1)
# 输出:
# [[0. 0. 0.]
# [1. 0. 0.]
# [0. 1. 0.]]
1.1.2 Numpy 数组的变换#
数组的转置#
NumPy 提供了非常简便的方法来实现数组的转置,主要通过.T
属性或者 numpy.transpose()
函数。使用.T
属性这是最常用的方法,因为它既简洁又直观。
import numpy as np
# 创建一个3x3的数组
arr = np.array(
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
)
# 使用.T属性进行转置
arr_T = arr.T
print(arr_T)
# 使用numpy.transpose()函数进行转置
arr_transposed = np.transpose(arr)
数组的变形#
在 NumPy 中,改变数组的形状通常是通过 reshape
函数来实现的。reshape
函数允许你在不改变数组数据的情况下,重新排列数组的元素以形成新的形状。这要求新形状的总元素数量与原始数组的总元素数量相同。
numpy.reshape(a,newshape)
a
是要变形的数组,newshape
是新的形状,可以是一个整数元组或整数。如果是整数,则表示新的形状为一维数组,另一维度会根据元素总数自动计算。
import numpy as np
# 创建一个一维数组
arr = np.arange(6) # array([0, 1, 2, 3, 4, 5])
# 使用reshape重塑为2x3的二维数组
arr_reshaped = arr.reshape((2, 3))
print(arr_reshaped)
# 输出:
# [[0 1 2]
# [3 4 5]]
使用-1
作为形状的一部分,NumPy 会自动计算该维度的大小,以确保总元素数量不变。
arr_reshaped = arr.reshape((3, -1))
print(arr_reshaped)
# 输出:
# [[0 1]
# [2 3]
# [4 5]]
当然如果要将多维数组转为一维数组时,np.flatten() 方法可以将多维数组展平为一维数组。
numpy.flatten(a,order='C')
import numpy as np
# 创建一个二维数组
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 使用flatten转换为一维数组
arr_flat = arr.flatten() # 注意:这里也可以直接使用 np.flatten(arr),但使用数组对象的方法更常见
print(arr_flat)
# 输出:
# [1 2 3 4 5 6]
也可以使用reshape(-1)
将多维数组展平为一维数组,这样可能性能更优,因为不要创建额外的副本,在需要确保数组连续性的场景下更为合适。
数组的堆叠#
- numpy.concatenate() 这是最常用的数组拼接函数之一,可以沿着制定轴将多个数组序列连接起来,默认情况下,它沿着第一个轴(axis=0)进行拼接。
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
# 默认沿着第一个轴(axis=0)拼接
c = np.concatenate((a, b), axis=0)
print(c)
# 输出:
# [[1 2]
# [3 4]
# [5 6]]
# 沿着第二个轴(axis=1)拼接
d = np.concatenate((a, b.T), axis=1) # 注意b需要转置以匹配a的形状
print(d)
# 输出:
# [[1 2 5]
# [3 4 6]]
- numpy.stack() stack 函数将一系列数组沿着新的轴进行堆叠,这与 concatenate 不同,stack 会增加一个新的维度
a = np.array([1, 2])
b = np.array([3, 4])
# 沿着新的轴(axis=0)堆叠
c = np.stack((a, b), axis=0)
print(c)
# 输出:
# [[1 2]
# [3 4]]
# 沿着新的轴(axis=1)堆叠
d = np.stack((a, b), axis=1)
print(d)
# 输出:
# [[1 3]
# [2 4]]
e = np.concatenate((a,b), axis=0) # 沿着第0轴连接
print(e)
# 输出:
# [1 2 3 4]
- numpy.hstack() 和 numpy.vstack()
这两个函数是
concatenate
的便捷包装, 分别用于水平和垂直堆叠数组,hstack
沿着水平方向(列)堆叠,而vstack
沿着垂直方向(行)堆叠。
a = np.array([1, 2])
b = np.array([3, 4])
c = np.vstack((a, b))
print(c)
# 输出:
# [[1 2]
# [3 4]]
a = np.array([[1], [2]])
b = np.array([[3], [4]])
c = np.hstack((a, b))
print(c)
# 输出:
# [[1 3]
# [2 4]]
- numpy.column_stack() 和 numpy.row_stack()
这两个函数与
hstack
和vstack
类似,但它们接受一维数组作为输入,并将它们视为列或行。
a = np.array([1, 2])
b = np.array([3, 4])
c = np.column_stack((a, b))
print(c)
# 输出:
# [[1 3]
# [2 4]]
a = np.array([1, 2])
b = np.array([3, 4])
c = np.row_stack((a, b))
print(c)
# 输出:
# [[1 2]
# [3 4]]
注意:row_stack 实际上就是 vstack 的别名。
元素追加和删除#
在 NumPy
中,数组(尤其是 ndarray
对象)通常被设计为固定大小的,这意呀着它们不像 Python 的列表(list
)那样可以方便地追加或删除元素。然而,NumPy
提供了一些方法来间接实现这些操作,但通常这些方法会涉及到创建新的数组,而不是在原地修改原始数组。
元素追加 要在 NumPy 数组中追加元素,你可以使用
numpy.concatenate()
、numpy.append()
或numpy.vstack()
(对于二维数组作为行追加)等函数。不过,需要注意的是,numpy.append()
实际上是一个包装了numpy.concatenate()
的便捷函数,但它通常比直接使用concatenate()
要慢,因为它会创建更多的临时数组。- 使用 numpy.concatenate()
a = np.array([1, 2, 3]) b = np.array([4, 5]) c = np.concatenate((a,b)) print(c) # 输出: # [1 2 3 4 5]
- 使用 numpy.append()
a = np.array([1, 2, 3]) # 追加单个元素 b = np.append(a, 4) print(b) #追加数组 c = np.append(a, [4, 5])
元素删除 在 NumPy 中删除元素通常意味着创建一个新的数组,它包含了除了要删除的元素之外的所有元素。这可以通过布尔索引、切片或
numpy.delete()
函数来实现。- 使用布尔索引
a = np.array([1, 2, 3, 4, 5]) #删除值为3的元素 mask = a != 3 b = a[mask] print(b)
- 使用切片
a = np.array([1, 2, 3, 4, 5]) # 跳过第三个元素 b = np.concatenate((a[:2], a[3:])) print(b) # 输出: [1 2 4 5]
- 使用 numpy.delete()
a = np.array([1, 2, 3, 4, 5]) # 删除索引为2的元素(值为3) b = np.delete(a, 2) print(b) # 输出: [1 2 4 5]
这些操作都会返回新的数组,而不是修改原始数组
1.1.3 数组广播机制#
广播机制是 Numpy 在算数运算中处理不同形状数组的一种方式,它允许在不进行显式复制数据的情况下执行元素级别的操作,从而提高了代码的执行效率和可读性。当两个或多个数组的形状一致时,NumPy 会尝试通过广播机制将它们“扩展”到相同的形状,以便可以进行逐个元素的算数运算。 在 NumPy 中,当两个或多个数组的形状不一致,但满足广播规则时,就会发生数组广播,具体来说,如果两个数组在维度上不匹配时,但满足以下条件之一,就可以通过广播机制进行运算:
- 维度较小的数组会在前面补 1,使得两个数组的维度相同;
- 在某个维度上,如果一个数组的大小为 1,则它会被视为在该维度上重复扩展,已以配另一个数组的大小;
- 如果两个数组在所有维度上都不匹配,并且没有任何一个维度的大小为 1,则无法进行广播。
- 案例一:简单的一位数组广播
import numpy as np
A = np.array([1, 2, 3]) # 形状 (3,)
B = np.array([10, 20, 30, 40]) # 形状 (4,)
# 尝试进行加法运算,但直接相加会报错,因为形状不匹配
# 但如果我们将A视为 (1, 3) 形状的数组,并将B视为 (4, 1) 形状的数组,然后进行逐元素加法,则可以实现广播
# 然而,NumPy不会直接显示地改变数组的形状,而是隐式地进行广播
# 实际上,NumPy不允许直接将形状为 (3,) 和 (4,) 的数组进行广播
# 但如果我们将B的前三个元素与A的元素相加,可以模拟广播的效果(注意:这不是NumPy的默认行为)
# 为了演示广播,我们可以使用形状兼容的数组
C = np.array([10, 20, 30]) # 形状 (3,)
D = A + C # 这里可以广播,因为形状相同
print(D) # 输出: [11 22 33]
# 注意:上面的C和D的示例是为了说明广播的概念,而不是NumPy直接允许的操作
**注意:**上面的示例中,直接使用 A 和 B 进行广播是无效的,因为它们的形状在所有维度上都不匹配,且没有任何一个维度的大小为 1。但为了说明广播的概念,我使用了形状兼容的数组 C 来与 A 进行加法运算。
- 案例二:二维数组与一维数组的广播
import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6]]) # 形状 (2, 3)
B = np.array([10, 20, 30]) # 形状 (3,)
# B会被视为形状为 (1, 3) 的数组,然后在第一个维度上复制以匹配A的形状 (2, 3)
# 现在A和B具有相同的“广播后”形状,可以进行逐元素加法
C = A + B
print(C)
# 输出:
# [[11 22 33]
# [14 25 36]]
在这个例子中,B 数组(形状为 (3,))在第一个维度上被隐式地扩展为 (1, 3),然后在这个维度上复制以匹配 A 数组的形状 (2, 3)。这样,A 和 B 就可以进行逐元素的加法运算了。
通过这两个案例,我们可以看到 NumPy 的广播机制是如何工作的,以及它如何允许我们在不显式改变数组形状的情况下进行高效的数组运算。
1.1.4 随机数生成与抽样#
NumPy 是 Python 中用于科学计算的一个基础库,它提供了大量的数学函数工具,特别是针对数组的操作。在 NumPy 中,生成随机数数组是一个常见的需求,NumPy 提供了多种函数来满足这一需求。以下是 NumPy 中几种常用的随机数数组生成方法及其使用方式:
numpy.random.rand() 功能: 生成指定形状的数组,数组中的元素在区间
[0,1)
内均匀分布 使用示例:# 生成一个具有5个元素的一维数组 arr1 = np.random.rand(5) print(arr1) # 生成一个2行3列的二维数组 arr2 = np.random.rand(2, 3) print(arr2)
numpy.random.randn() 功能: 生成指定形状的数组,数组中的元素服从标准正态分布(均值为 0,标准差为 1) 使用示例:
import numpy as np # 生成一个具有5个元素的一维数组 arr1 = np.random.randn(5) print(arr1) # 生成一个2行3列的二维数组 arr2 = np.random.randn(2, 3) print(arr2)
numpy.random.randint() 功能: 生成指定范围内的随机整数数组,可以指定范围的最小值、最大值和数组的形状 使用示例:
import numpy as np # 生成一个在[1, 10)之间的一维整数数组 arr1 = np.random.randint(1, 10, size=5) print(arr1) # 生成一个在[1, 10)之间2行3列的二维整数数组 arr2 = np.random.randint(1, 10, size=(2, 3)) print(arr2)
numpy.random.uniform() 功能: 生成指定范围内的均匀分布随机数数组,可以指定范围的最小值、最大值和数组的形状 使用示例:
import numpy as np # 生成一个在[1, 5)之间的一维数组 arr1 = np.random.uniform(1, 5, size=5) print(arr1) # 生成一个在[1, 5)之间2行3列的二维数组 arr2 = np.random.uniform(1, 5, size=(2, 3)) print(arr2)
numpy.random.normal() 功能: 生成指定均值和标准差的正态分布随机数数组,可以指定数组的形状 使用示例:
import numpy as np # 生成均值为2,标准差为0.5的一维数组 arr1 = np.random.normal(2, 0.5, size=5) print(arr1) # 生成均值为2,标准差为0.5的2行3列的二维数组 arr2 = np.random.normal(2, 0.5, size=(2, 3)) print(arr2)
numpy.random.random() 功能: 与 numpy.random.rand()类似,生成指定形状的数组,数组中的元素在区间[0, 1)内均匀分布。该函数是 Python 标准库 random 模块的函数的向量化版本。
numpy.random.seed() 功能: 在生成伪随机数时指定种子。指定相同的种子将会产生相同的随机数序列,这在调试代码时非常有用。
使用示例:
import numpy as np np.random.seed(0) arr1 = np.random.rand(3, 3) print(arr1) # 每次运行这段代码时,如果seed相同,生成的随机数序列也将相同
NumPy 提供了丰富的随机数生成函数,可以满足各种生成随机数数组的需求。在实际应用中,可以根据具体需求选择合适的函数,并通过指定参数来生成满足需求的随机数数组。