Numpy学习笔记

Numpy学习笔记

在日常工作中,Numpy 被广泛用于处理数值数据,尤其是在数据科学、机器学习和科学计算领域。

NumPy是一个运行速度非常快的数学库,主要用于数组计算。NumPy通常与SciPy(Scientific Python)和 Matplotlib(绘图库)一起使用,这种组合广泛用于替代 MatLab,是一个强大的科学计算环境,有助于我们通过 Python 学习数据科学或者机器学习。
SciPy是一个开源的 Python 算法库和数学工具包。 SciPy 包含的模块有最优化、线性代数、积分、插值特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。
Matplotib 是 Python 编程语言及其数值数学扩展包,NumPy的可视化操作界面。它为利用通用的图形用户界面工具包,如 Tkinter,wxPython,Qt或 GTK+ 向应用程序嵌入式绘图提供了应用程序接口(API)。

1. 导入 Numpy

在使用 Numpy 之前,首先需要导入它:

import numpy as np

2. 创建数组

2.1 从列表或元组创建数组
arr = np.array([1, 2, 3, 4, 5]) # [1 2 3 4 5]
arr = np.array([[1,2],[3,4]])
"""
[[1 2]
 [3 4]]
"""
arr = np.array([1,2,3,4,5],ndmin=2) # [[1 2 3 4 5]]
2.2 创建全零数组
zeros = np.zeros((3, 4))  # 创建一个 3x4 的全零数组
"""
[[0. 0. 0. 0.]
 [0. 0. 0. 0.]
 [0. 0. 0. 0.]]
"""
2.3 创建全一数组
ones = np.ones((2, 3))  # 创建一个 2x3 的全一数组
2.4 创建指定值的数组
full = np.full((2, 3), 7)  # 创建一个 2x3 的数组,所有值为 7
2.5 创建单位矩阵
eye = np.eye(3)  # 创建一个 3x3 的单位矩阵
"""
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
"""
2.6 创建随机数组
random = np.random.random((2, 2))  # 创建一个 2x2 的随机数组,值在[0, 1)之间
"""
[[0.87368863 0.8534936 ]
 [0.08163548 0.17707345]]
"""
arr = np.empty([3,2],dtype=int)
"""
 [[-9223231307677340829 -8832184198205066449]
  [       2806322172944        2806322172976]
  [                  15                   45]]
"""
2.7 创建指定范围的数组
arr_range = np.arange(10, 20, 2)  # 创建一个从 10 到 20,步长为 2 的数组
2.8 创建线性分布的数组
linspace = np.linspace(0, 1, 5)  # 创建一个从 0 到 1 的数组,包含 5 个元素,均匀分布
# [0.   0.25 0.5  0.75 1.  ]
arr = np.logspace(0, 2, num=10)
# [  1.           1.66810054   2.7825594    4.64158883   7.74263683  12.91549665  21.5443469   35.93813664  59.94842503 100.        ]
"""
这里 start 是 0,stop 是 2,表示我们希望生成的数值范围是从 10^0(即 1)到 10^2(即 100),这里的base默认是10
num=10 表示我们希望生成 10 个这样的数值。
"""
2.9 从已有的列表或元组创建数组
list_data = [1, 2, 3, 4, 5]
arr = np.asarray(list_data)
print(arr)
# [1 2 3 4 5]
2.10 NumPy 数组的重要属性
  1. 数组的秩 (Rank) 和轴 (Axis)

    • :数组的维数或维度的数量。例如,一维数组的秩为 1,二维数组的秩为 2,以此类推。
    • :指的是数组的维度(dimensions)。
  2. ndarray 对象的重要属性

    属性说明
    ndarray.ndim数组的秩,即轴的数量或维度的数量。
    ndarray.shape数组的维度。对于矩阵,n 行 m 列。
    ndarray.size数组元素的总个数,相当于 .shape 中 n*m 的值。
    ndarray.dtypendarray 对象的元素类型。
    ndarray.itemsize数组中每个元素的大小,以字节为单位。
    ndarray.flagsndarray 对象的内存信息。
    ndarray.realndarray 元素的实部。
    ndarray.imagndarray 元素的虚部。
    ndarray.data包含实际元素数据的缓冲区。由于一般通过数组的索引读取元素,所以通常不需要使用这个属性。

3. 数组的基本操作

3.1 数组形状
arr.shape  # 获取数组的形状
3.2 调整数组形状
reshaped = arr.reshape((5, 1))  # 将数组重塑为 5x1 的形状
3.3 数组展平
flattened = arr.flatten()  # 将数组展平为一维
3.4 数组转置
transposed = arr.T  # 转置数组,T就是transpose,也可以写成arr.transpose
3.5numpy.swapaxes 函数

numpy.swapaxes 函数用于交换一个数组的两个指定轴(维度)。通过交换轴的位置,可以改变数据的排列方式。

3.5.1函数格式
numpy.swapaxes(arr, axis1, axis2)
  • arr:输入的数组,必须是一个 ndarray。
  • axis1:需要交换的第一个轴的整数索引。
  • axis2:需要交换的第二个轴的整数索引。
3.5.2 示例代码
import numpy as np

# 创建一个三维的 ndarray
a = np.arange(8).reshape(2, 2, 2)

print('原数组是:')
print(a)
print('\n')

# 现在交换轴 0(深度方向)到轴 2(宽度方向)
print('调用 swapaxes 函数后的数组:')
print(np.swapaxes(a, 2, 0))
3.5.3. 示例解释
  • 数组的初始状态

    • a 是一个三维数组,形状为 (2, 2, 2),表示它有三个轴:轴 0(深度方向),轴 1(高度方向),和轴 2(宽度方向)。
    • 通过 np.arange(8).reshape(2, 2, 2) 创建的数组 a
      [[[0, 1],
        [2, 3]],
      
       [[4, 5],
        [6, 7]]]
      
  • 交换轴后的结果

    • 使用 np.swapaxes(a, 2, 0) 将轴 0 和轴 2 进行交换。结果数组的形状变为 (2, 2, 2),但轴的顺序发生了改变:

      [[[0, 4],
        [2, 6]],
      
       [[1, 5],
        [3, 7]]]
      
    • 交换轴 0 和轴 2 后,原来的深度方向上的元素被移动到宽度方向,而宽度方向上的元素被移动到深度方向。

3.6 维度的拓展与删除
3.6.1.numpy.expand_dims 函数

功能:

  • numpy.expand_dims 用于通过在指定位置插入一个新的轴来扩展数组的形状。

格式:

numpy.expand_dims(arr, axis)
  • arr:输入的数组。
  • axis:要插入新轴的位置(索引)。

示例:

import numpy as np

x = np.array([[1, 2], [3, 4]])
print('数组 x:')
print(x)
print('\n')

y = np.expand_dims(x, axis=0)
print('数组 y:')
print(y)
print('\n')

print('数组 x 和 y 的形状:')
print(x.shape, y.shape)

"""
数组 x:
[[1 2]
 [3 4]]


数组 y:
[[[1 2]
  [3 4]]]


数组 x 和 y 的形状:
(2, 2) (1, 2, 2)
"""

输出:

  • 原数组 x 是一个形状为 (2, 2) 的二维数组。
  • 使用 expand_dims 在轴 0 处插入一个新轴后,得到的新数组 y 的形状为 (1, 2, 2)
3.6.2. numpy.squeeze 函数

功能:

  • numpy.squeeze 用于从数组的形状中删除单维度条目,即删除形状为 1 的轴。

格式:

numpy.squeeze(arr, axis=None)
  • arr:输入的数组。
  • axis(可选):要删除的轴。如果未指定,则删除所有单维度的轴。

示例:

import numpy as np

x = np.arange(9).reshape(1, 3, 3)
print('数组 x:')
print(x)
print('\n')

y = np.squeeze(x)
print('数组 y:')
print(y)
print('\n')

print('数组 x 和 y 的形状:')
print(x.shape, y.shape)

"""
数组 x:
[[[0 1 2]
  [3 4 5]
  [6 7 8]]]


数组 y:
[[0 1 2]
 [3 4 5]
 [6 7 8]]


数组 x 和 y 的形状:
(1, 3, 3) (3, 3)
"""

输出:

  • 原数组 x 是一个形状为 (1, 3, 3) 的三维数组。
  • 使用 squeeze 删除形状为 1 的轴后,得到的新数组 y 的形状为 (3, 3)
3.7 数组拼接
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
concatenated1 = np.concatenate((arr1, arr2), axis=0)  # 沿着第一个轴拼接
print(concatenated1)
concatenated2 = np.concatenate((arr1, arr2), axis=1)  # 沿着第二个轴拼接
print(concatenated2)
"""
[[1 2]
 [3 4]
 [5 6]
 [7 8]]
"""
"""
[[1 2 5 6]
 [3 4 7 8]]
"""
3.8. 数组堆叠
3.8.1. numpy.stack 函数
  • 功能
    numpy.stack 函数用于沿着新轴连接一系列数组。它可以在指定的轴上创建一个新数组,并将输入的数组堆叠到这个新轴上。

  • 格式

    numpy.stack(arrays, axis=0)
    
    • arrays:相同形状的数组序列。
    • axis:返回数组中的轴,输入数组沿着这个轴堆叠。默认是 0
  • 示例

    import numpy as np
    
    a = np.array([[1, 2], [3, 4]])
    b = np.array([[5, 6], [7, 8]])
    
    print('沿轴 0 堆叠两个数组:')
    print(np.stack((a, b), 0))
    
    print('沿轴 1 堆叠两个数组:')
    print(np.stack((a, b), 1))
    
    """
    沿轴 0 堆叠两个数组:
    [[[1 2]
      [3 4]]
    
     [[5 6]
      [7 8]]]
    沿轴 1 堆叠两个数组:
    [[[1 2]
      [5 6]]
    
     [[3 4]
      [7 8]]]
    """
    

    输出

    • 沿轴 0 (深度)堆叠时,结果是增加了一个新维度,将两个数组沿着该新轴堆叠在一起。
    • 沿轴 1 堆叠时,结果是在现有的第一个轴的基础上增加一个新轴,并在此轴上进行堆叠。
3.8.2. numpy.hstack 函数
  • 功能
    numpy.hstackstack 函数的变体,它通过水平(列方向)堆叠数组来生成新的数组。

  • 格式

    numpy.hstack((a, b))
    
  • 示例

    import numpy as np
    
    a = np.array([[1, 2], [3, 4]])
    b = np.array([[5, 6], [7, 8]])
    
    print('水平堆叠两个数组:')
    print(np.hstack((a, b)))
    
    """
    水平堆叠两个数组:
    [[1 2 5 6]
     [3 4 7 8]]
    """
    

    输出

    • 数组 ab 被沿着列方向(即水平)堆叠在一起,形成一个新的数组。
3.8.3 numpy.vstack 函数
  • 功能
    numpy.vstackstack 函数的另一个变体,它通过垂直(行方向)堆叠数组来生成新的数组。

  • 格式

    numpy.vstack((a, b))
    
  • 示例

    import numpy as np
    
    a = np.array([[1, 2], [3, 4]])
    b = np.array([[5, 6], [7, 8]])
    
    print('垂直堆叠两个数组:')
    print(np.vstack((a, b)))
    
    """
    垂直堆叠两个数组:
    [[1 2]
     [3 4]
     [5 6]
     [7 8]]
    """
    

    输出

    • 数组 ab 被沿着行方向(即垂直)堆叠在一起,形成一个新的数组。
3.9 数组分割
splitted = np.split(arr, 2)  # 将数组沿第一个轴分割为两个子数组
3.10 数组元素的添加与删除
3.10.1numpy.append 函数

功能:

  • numpy.append 函数用于在数组的末尾添加值。追加操作会分配整个新数组,并将原始数组的元素复制到新的数组中。

函数格式:

numpy.append(arr, values, axis=None)
  • arr:输入数组。
  • values:要向 arr 添加的值,需要和 arr 形状相同(除了要添加的轴)。
  • axis:要追加的轴,默认值为 None。如果 axis=None,则 values 将被展开并与 arr 平铺连接,返回一个一维数组。

示例解析:

  1. 无轴添加(默认 axis=None

    • a = np.array([[1, 2, 3], [4, 5, 6]])
    • np.append(a, [7, 8, 9])
    • 输出:
      array([1, 2, 3, 4, 5, 6, 7, 8, 9])
      
    • 解释:将 values 展开并平铺在 arr 之后,返回一个一维数组。
  2. 沿轴 0 添加元素

    • np.append(a, [[7, 8, 9]], axis=0)
    • 输出:
      array([[1, 2, 3],
             [4, 5, 6],
             [7, 8, 9]])
      
    • 解释:在轴 0(行)方向上添加新元素,values 的形状必须匹配 arr 在其他维度的形状。
  3. 沿轴 1 添加元素

    • np.append(a, [[5, 5, 5], [7, 8, 9]], axis=1)
    • 输出:
      array([[1, 2, 3, 5, 5, 5],
             [4, 5, 6, 7, 8, 9]])
      
    • 解释:在轴 1(列)方向上添加新元素,values 的形状必须匹配 arr 在其他维度的形状。
3.10.2 numpy.insert 函数

功能:

numpy.insert 函数用于在指定轴的特定位置插入值。与 append 函数不同的是,insert 函数允许你在数组的任意位置插入值,而不仅仅是在末尾。

函数格式:

numpy.insert(arr, obj, values, axis=None)
  • arr:输入数组。
  • obj:表示索引的整数或整数数组,指定插入位置。如果 axisNone,则 obj 表示插入位置的索引(数组会被平展为一维数组)。
  • values:要插入的值。如果 axis 指定了,values 需要与 arr 在该轴上的形状兼容。
  • axis:要插入的轴。如果没有指定,则将数组展平为一维数组后插入值。

示例解析:

  1. 无轴插入(默认 axis=None

    import numpy as np
    a = np.array([1, 2, 3, 4, 5])
    result = np.insert(a, 2, [99, 100])
    print(result)
    

    输出

    array([  1,   2,  99, 100,   3,   4,   5])
    
    • 解释:在一维数组 a 的索引 2 处插入 [99, 100],结果是新的数组中这些值插入到原始位置上,后面的元素右移。
  2. 沿轴 0 插入元素

    import numpy as np
    a = np.array([[1, 2, 3], [4, 5, 6]])
    result = np.insert(a, 1, [99, 100, 101], axis=0)
    print(result)
    

    输出

    array([[  1,   2,   3],
           [ 99, 100, 101],
           [  4,   5,   6]])
    
    • 解释:在 a 的索引 1 处插入一行 [99, 100, 101],其余的行向下移动。
  3. 沿轴 1 插入元素

    import numpy as np
    a = np.array([[1, 2, 3], [4, 5, 6]])
    result = np.insert(a, 1, [99, 100], axis=1)
    print(result)
    

    输出

    array([[  1,  99,   2,   3],
           [  4, 100,   5,   6]])
    
    • 解释:在 a 的每一行的索引 1 处插入一个元素 [99, 100],其他元素向右移动。

注意事项:

  • 如果 axis 未指定,数组将首先被展平为一维,然后执行插入操作。
  • 插入的位置可以是单个索引,也可以是多个索引的数组,这允许在多个位置插入多个值。
  • 插入操作会生成一个新数组,原数组不会被修改。
3.10.3numpy.delete 函数

功能:

numpy.delete 函数用于删除数组中指定的子数组或元素。与 appendinsert 相反,delete 可以从数组中移除不需要的部分,并返回一个新的数组。

函数格式:

numpy.delete(arr, obj, axis=None)
  • arr:输入数组。
  • obj:要删除的子数组或元素的位置。可以是整数、整数数组或切片。
  • axis:要删除的轴。如果没有指定,数组将展平为一维,然后删除指定位置的元素。

示例解析:

  1. 无轴删除(默认 axis=None

    import numpy as np
    a = np.array([1, 2, 3, 4, 5])
    result = np.delete(a, 2)
    print(result)
    

    输出

    array([1, 2, 4, 5])
    
    • 解释:在一维数组 a 中删除索引 2 处的元素 3,结果是剩下的元素形成一个新的数组。
  2. 沿轴 0 删除元素

    import numpy as np
    a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    result = np.delete(a, 1, axis=0)
    print(result)
    

    输出

    array([[1, 2, 3],
           [7, 8, 9]])
    
    • 解释:在 a 的第二行(索引 1)删除整行,结果数组不再包含这一行。
  3. 沿轴 1 删除元素

    import numpy as np
    a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    result = np.delete(a, 1, axis=1)
    print(result)
    

    输出

    array([[1, 3],
           [4, 6],
           [7, 9]])
    
    • 解释:在 a 的每一行中删除第二列(索引 1),结果数组不再包含这一列。
  4. 使用切片删除

    import numpy as np
    a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    result = np.delete(a, np.s_[::2])
    print(result)
    

    输出

    array([1, 3, 5, 7, 9])
    
    • 解释:使用切片 np.s_[::2],删除数组中所有偶数索引的元素,即删除索引 0, 2, 4, 6, 8 处的元素。

注意事项:

  • 如果未指定 axis 参数,delete 会将数组展平为一维数组,然后执行删除操作。
  • delete 操作会生成一个新的数组,原数组不被修改。
  • obj 可以是单个索引,也可以是多个索引的数组或切片,允许删除多个位置的元素。

4. 索引和切片

4.1 基本索引
element = arr[1, 2]  # 获取第二行第三列的元素
4.2 切片
sliced = arr[0:2, 1:3]  # 获取第一到第二行,第二到第三列的子数组
4.3 布尔索引
bool_idx = arr[arr > 2]  # 获取所有大于 2 的元素
4.4 花式索引
fancy_idx = arr[[0, 1, 2], [0, 1, 0]]  # 获取 (0,0), (1,1), (2,0) 位置的元素
4.5 混合索引
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr[1, [0, 2]])  # 输出:[4 6]

5. NumPy 迭代数组(Iterator)

  • NumPy 迭代器对象 numpy.nditer

    • 提供了一种灵活访问一个或者多个数组元素的方式。可以通过迭代器轻松完成对数组元素的访问和操作。
  • 基本用法

    • 使用 nditer 迭代数组元素时,可以控制迭代的顺序。
  • 代码示例

    import numpy as np
    
    a = np.arange(0, 60, 5)
    a = a.reshape(3, 4)
    
    print('原始数组是:')
    print(a)
    print('\n')
    
    print('以 C 风格顺序排序:')
    for x in np.nditer(a, order='C'):
        print(x, end=", ")
    print('\n')
    
    print('以 F 风格顺序排序:')
    for x in np.nditer(a, order='F'):
        print(x, end=", ")
        
    # 输出:
    """
    原始数组是:
    [[ 0  5 10 15]
     [20 25 30 35]
     [40 45 50 55]]
    
    
    以 C 风格顺序排序:
    0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 
    
    以 F 风格顺序排序:
    0, 20, 40, 5, 25, 45, 10, 30, 50, 15, 35, 55, 
    """
    
  • 迭代顺序

    • C 风格顺序 (order='C'):按行优先顺序迭代,即逐行访问数组元素。
    • Fortran 风格顺序 (order='F'):按列优先顺序迭代,即逐列访问数组元素。

6. 数学运算

6.1 数组元素级运算
arr_sum = arr + 2  # 数组每个元素加 2
arr_mult = arr * 2  # 数组每个元素乘 2
6.2 数组间运算
arr_sum = arr1 + arr2  # 数组相加
arr_mult = arr1 * arr2  # 数组对应元素相乘
6.3 数学函数
arr_sqrt = np.sqrt(arr)  # 计算数组每个元素的平方根
arr_exp = np.exp(arr)  # 计算数组每个元素的指数值
6.4 矩阵乘法
dot_product = np.dot(arr1, arr2)  # 计算两个数组的矩阵乘积

7. 统计分析

7.1 最大值、最小值
max_val = np.max(arr)  # 获取数组中的最大值
min_val = np.min(arr)  # 获取数组中的最小值
7.2 求和、均值、方差
sum_val = np.sum(arr)  # 数组元素求和
mean_val = np.mean(arr)  # 计算数组的均值
var_val = np.var(arr)  # 计算数组的方差
7.3 中位数、标准差
median_val = np.median(arr)  # 计算数组的中位数
std_val = np.std(arr)  # 计算数组的标准差
7.4 轴向操作
sum_axis0 = np.sum(arr, axis=0)  # 按列求和
sum_axis1 = np.sum(arr, axis=1)  # 按行求和

8. 线性代数

8.1 矩阵转置
transposed = np.transpose(arr)  # 转置矩阵
8.2 矩阵逆
inverse = np.linalg.inv(arr)  # 计算矩阵的逆
8.3 矩阵行列式
det = np.linalg.det(arr)  # 计算矩阵的行列式
8.4 特征值与特征向量
eigvals, eigvecs = np.linalg.eig(arr)  # 计算矩阵的特征值和特征向量

9. 随机数生成

9.1 生成均匀分布的随机数
uniform_random = np.random.rand(3, 3)  # 生成一个 3x3 的均匀分布随机数数组
9.2 生成正态分布的随机数
normal_random = np.random.randn(3, 3)  # 生成一个 3x3 的正态分布随机数数组
9.3 随机选择
random_choice = np.random.choice([1, 2, 3, 4, 5], size=3)  # 从数组中随机选择 3 个元素

10. 高级操作

10.1 广播

广播(Broadcasting)是 NumPy 中用于处理不同形状数组之间算术运算的强大机制。广播允许 NumPy 在不复制数据的情况下,对形状不同的数组执行元素级的运算。

10.1.1. 广播的基本规则

广播机制遵循以下规则来确定两个数组能否进行运算:

  1. 如果两个数组的维度数不相同,形状较小的数组会在左边补 1,直到两个数组具有相同的维度数。

  2. 然后,从最后一个维度开始,NumPy 会依次比较每个维度:

    • 如果两个维度相等,继续比较下一个维度。
    • 如果两个维度中有一个是 1,则“扩展”这个维度,使其与另一个维度匹配。
    • 如果两个维度不相等且没有维度为 1,则无法进行广播,抛出错误。

在这里插入图片描述

10.1.2. 广播的实际示例
  • 示例 1:二维数组与一维数组的加法运算

    import numpy as np
    
    A = np.array([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]])
    
    B = np.array([1, 0, 1])
    
    C = A + B
    print(C)
    

    输出:

    [[ 2  2  4]
     [ 5  5  7]
     [ 8  8 10]]
    

    在这个例子中,B 是一个一维数组,形状为 (3,),而 A 是一个二维数组,形状为 (3, 3)。广播机制将 B 的形状扩展为 (3, 3),使得它的每一行都与 A 的对应行进行加法运算。

  • 示例 2:二维数组与标量的乘法运算

    import numpy as np
    
    A = np.array([[1, 2, 3],
                  [4, 5, 6],
                  [7, 8, 9]])
    
    B = 2
    
    C = A * B
    print(C)
    

    输出:

    [[ 2  4  6]
     [ 8 10 12]
     [14 16 18]]
    

    在这个例子中,B 是一个标量,广播机制将 B 看作与 A 形状相同的数组,然后执行逐元素的乘法运算。

10.1.3. 广播的优点
  • 内存效率:广播机制避免了不必要的数据复制,直接对不同形状的数组进行运算,从而节省内存。
  • 简化代码:通过广播,代码更加简洁易懂,减少了手动调整数组形状的麻烦。
10.1.4. 注意事项

尽管广播机制非常方便,但在使用时要小心以下几点:

  • 理解广播过程:确保对广播规则的理解,否则可能会产生意料之外的结果。
  • 检查输出数组的形状:在广播运算后,结果数组的形状可能与预期不同,需注意确认。
10.2 矢量化运算

Numpy 中的大部分操作都是矢量化的,意味着它们可以快速地应用于整个数组,而无需使用显式的循环。

vectorized_mult = arr * 2  # 这个操作会比用 Python 的 for 循环来逐个元素乘以 2 快得多

11. 其他常用函数

11.1 排序
sorted_arr = np.sort(arr)  # 对数组进行排序
11.2 唯一值
unique_vals = np.unique(arr)  # 获取数组中的唯一值
11.3 条件过滤
filtered_arr = arr[arr > 3]  # 获取所有大于 3 的元素

12.字符串函数

函数描述
add()对两个数组的逐个字符串元素进行连接。
multiply()返回元素多重连接后的字符串。
center()居中字符串。
capitalize()将字符串第一个字母转换为大写。
title()将字符串的每个单词的第一个字母转换为大写。
lower()数组元素转换为小写。
upper()数组元素转换为大写。
split()指定分隔符将字符串分割,并返回数组列表。
splitlines()返回元素中的行列表,以换行符分割。
strip()移除元素开头或者结尾的特定字符。
join()通过指定分隔符连接数组中的元素。
replace()使用新字符串替换字符串中的所有子字符串。

13.Matplotlib 与 NumPy 的结合使用

13.1. 简介
  • Matplotlib 是 Python 中一个功能强大的绘图库,用于创建静态、动画和交互式可视化图表。
  • NumPy 是一个用于科学计算的库,提供了支持大规模多维数组和矩阵的操作。
  • 两者结合使用,可以有效地处理和可视化数据,尤其是数值数据的可视化,这在数据分析和科学计算中非常重要。
13.2. 基本绘图操作
  • 使用 NumPy 生成数据,然后通过 Matplotlib 绘制图表,是常见的数据可视化流程。

    示例代码:绘制简单的线性方程图

    import numpy as np
    from matplotlib import pyplot as plt
    
    x = np.arange(1, 11)   # 生成 1 到 10 的数组
    y = 2 * x + 5          # 计算 y 值
    
    plt.title("Matplotlib demo")
    plt.xlabel("x axis caption")
    plt.ylabel("y axis caption")
    plt.plot(x, y)
    plt.show()
    

    在这里插入图片描述

    解释

    • np.arange(1, 11):生成 x 轴数据,从 1 到 10。
    • y = 2 * x + 5:计算 y 轴数据,表示线性方程 y = 2x + 5
    • plt.plot(x, y):绘制折线图。
    • plt.title()plt.xlabel()plt.ylabel():为图表添加标题和轴标签。
    • plt.show():显示图表。
13.3 散点图与格式化字符串
  • Matplotlib 允许通过格式化字符串直接控制图表的样式,比如颜色、标记符号等。
13.3.1. 线型样式
字符描述
'-'实线样式
'--'短横线样式
'-.'点划线样式
':'虚线样式
13.3.2. 标记符号
字符描述
'.'点标记
','像素标记
'o'圆标记
'v'倒三角标记
'^'正三角标记
'<'左三角标记
'>'右三角标记
'1'下箭头标记
'2'上箭头标记
'3'左箭头标记
'4'右箭头标记
's'正方形标记
'p'五边形标记
'*'星形标记
'h'六边形标记1
'H'六边形标记2
'+'加号标记
'x'X 标记
'D'菱形标记
'd'窄菱形标记
`’'`
'_'水平线标记
13.3.3 颜色
字符描述
'b'蓝色
'g'绿色
'r'红色
'c'青色
'm'品红色
'y'黄色
'k'黑色
'w'白色

这个表格总结了 Matplotlib 中常用的绘图格式化字符,包括线型样式、标记符号和颜色。这些字符可以在绘制图形时指定图形的样式,帮助更好地展示数据。

13.3.4 示例代码

使用格式化字符串绘制散点图

plt.plot(x, y, marker='o',color = 'g')   # 使用绿色圆圈标记
plt.show()

解释

  • marker='og':表示标记类型为绿色圆圈。

在这里插入图片描述

13.4. 绘制条形图
  • Matplotlib 的 bar() 函数用于绘制条形图,可以为不同数据集创建对比条形图。

    示例代码:绘制条形图

    from matplotlib import pyplot as plt
    
    x = [5, 8, 10]
    y = [12, 16, 6]
    x2 = [6, 9, 11]
    y2 = [6, 15, 7]
    
    plt.bar(x, y, align='center')
    plt.bar(x2, y2, color='g', align='center')
    plt.title('Bar graph')
    plt.ylabel('Y axis')
    plt.xlabel('X axis')
    plt.show()
    

    解释

    • plt.bar(x, y):绘制第一个条形图。
    • plt.bar(x2, y2, color='g'):绘制第二个条形图,并设置颜色为绿色。

在这里插入图片描述

13.5. 绘制直方图
  • 直方图是展示数据分布的常用图表类型,hist() 函数用于创建直方图。

    示例代码:绘制直方图

    from matplotlib import pyplot as plt
    import numpy as np
    
    a = np.array([22, 87, 5, 43, 56, 73, 55, 54, 11, 20, 51, 5, 79, 31, 27])
    plt.hist(a, bins=[0, 20, 40, 60, 80, 100])
    plt.title("Histogram")
    plt.show()
    """
    0-20区间有3个数,因此纵轴为3
    """
    

    解释

    • bins:指定直方图的分箱(数据范围区间),如 [0, 20, 40, 60, 80, 100]

在这里插入图片描述

13.6. 多子图绘制
  • Matplotlib 提供了 subplot()subplots() 方法,用于在一个图表中绘制多个子图。

    示例代码:使用 subplots() 绘制多个子图

    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.linspace(0, 2 * np.pi, 400)
    y = np.sin(x**2)
    
    fig, ax = plt.subplots(2, 2, subplot_kw=dict(projection='polar'))
    ax[0, 0].plot(x, y)
    ax[1, 1].scatter(x, y)
    plt.show()
    

    解释

    • plt.subplots(2, 2):生成一个 2x2 的子图网格。
    • subplot_kw=dict(projection='polar'):这是一个关键字参数,用于指定子图的投影类型。这里设置为 'polar',表示所有子图都使用极坐标系。
    • np.linspace(0, 2 * np.pi, 100) 生成从 0 到 2 * π 之间的 100 个均匀分布的点。这些点用于 x 轴数据。
    • ax[0, 0].plot(x, y)ax[1, 1].scatter(x, y):分别在不同的子图中绘制折线图和散点图。

    在这里插入图片描述

总结

  • MatplotlibNumPy 的结合使用,使得数据可视化变得非常高效,特别是在科学计算和数据分析领域。
  • 通过简单的 NumPy 数组操作和 Matplotlib 的多功能图表绘制,可以快速生成各种有用的图表,如折线图、散点图、条形图、直方图和多子图。
  • 灵活使用 plot()bar()hist()subplot() 等函数,可以满足不同的数据展示需求。

14. 副本与视图

在 NumPy 中,副本(copy)视图(view) 是处理数组时的两个重要概念。理解它们有助于高效地操作数组数据,避免意外的修改或内存浪费。

14.1. 副本(Copy)
  • 定义:当你对一个 NumPy 数组进行操作并创建一个副本时,你会得到一个新的数组对象,它与原数组有独立的内存空间。修改副本中的数据不会影响原数组,反之亦然。
  • 特点
    • 副本拥有自己独立的内存空间。
    • 修改副本不会影响原数组。
    • 常用的创建副本的方法包括 np.copy() 函数,或者通过一些操作(如切片、赋值)自动创建。

示例

import numpy as np

a = np.array([1, 2, 3, 4])
b = a.copy()  # 创建副本
b[0] = 99

print("原数组 a:", a)  # 输出 [1, 2, 3, 4]
print("副本数组 b:", b)  # 输出 [99, 2, 3, 4]
  • 在这个例子中,ba 的副本。修改 b 不会影响 a
14.2. 视图(View)
  • 定义:视图是对原数组的一个不同的表示,它共享相同的数据内存。换句话说,视图是原数组的一个引用。修改视图中的数据会直接影响到原数组,反之亦然。
  • 特点
    • 视图与原数组共享相同的内存空间。
    • 修改视图会影响到原数组。
    • 视图通常通过数组的切片、某些函数(如 reshape()ravel())等方式创建。
import numpy as np

a = np.array([1, 2, 3, 4])
b = a.view()  # 创建视图
b[0] = 99

print("原数组 a:", a)  # 输出 [99, 2, 3, 4]
print("视图数组 b:", b)  # 输出 [99, 2, 3, 4]
  • 在这个例子中,ba 的视图。修改 b 会影响 a,因为它们共享相同的数据内存。
14.3. 深拷贝与浅拷贝
  • 浅拷贝(Shallow Copy):浅拷贝创建一个新的对象,但在对象中的元素还是引用原对象中的元素。因此,浅拷贝的某些操作会影响原对象。
  • 深拷贝(Deep Copy):深拷贝创建一个全新的对象,并递归地复制所有的子对象,不再引用原对象中的元素。深拷贝完全独立,不会影响原对象。
14.4. 什么时候使用副本和视图?
  • 副本

    • 在需要独立的数据时,使用副本。例如,当你不希望原数组因修改而受到影响时。
    • 在处理大数据时,请注意副本会占用更多的内存。
  • 视图

    • 当你需要一个数组的不同表示(如改变形状)而不需要独立的内存空间时,使用视图。
    • 视图是高效的,因为它们避免了不必要的数据复制。
14.5. 检查数组是副本还是视图
  • 你可以通过 base 属性来检查数组是否是另一个数组的视图。如果 base 属性是 None,则表示该数组是独立的(即副本);如果 base 指向另一个数组,则该数组是视图。
示例
import numpy as np

a = np.array([1, 2, 3, 4])
b = a.view() # 视图
c = a.copy() # 副本

print(b.base is a)  # 输出 True,表示 b 是 a 的视图
print(c.base is a)  # 输出 False,表示 c 是 a 的副本
14.6. 示例1
import numpy as np

a = np.arange(6)
print("数组 a:")
print(a)

print("调用id()函数:")
print(id(a))
print("a赋值给b")
b = a
print(b)
print("b拥有相同的id")
print(id(b))
print("修改 b 的形状:")
b.shape = 3,2
print("修改后的数组 b:")
print(b)
print("a的形状也被修改了")
print(a)

输出:

数组 a:
[0 1 2 3 4 5]
调用id()函数:
2670858791024
a赋值给b
[0 1 2 3 4 5]
b拥有相同的id
2670858791024
修改 b 的形状:
修改后的数组 b:
[[0 1]
 [2 3]
 [4 5]]
a的形状也被修改了
[[0 1]
 [2 3]
 [4 5]]

总结:简单的赋值不会创建数组对象的副本。相反,它使用原始数组的相同id()来访问它。

14.7 示例2
import numpy as np

arr = np.arange(12)
print('我们的数组:')
print(arr)

print('创建切片:')
a = arr[3:]
b = arr[3:]

a[1] = 123
b[2] = 234

print(arr)
print(id(a), id(b), id(arr[3:]))

"""
我们的数组:
[ 0  1  2  3  4  5  6  7  8  9 10 11]
创建切片:
[  0   1   2   3 123 234   6   7   8   9  10  11]
2670858631760 2670858516016 2670858791024
"""
  1. arr = np.arange(12)
  • 创建数组np.arange(12) 生成一个包含从 0 到 11 的一维数组 arr,即:

    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
    
  1. 创建切片视图
  • a = arr[3:]b = arr[3:]
    • 这两行代码分别创建了数组 arr 的切片 abarr[3:] 表示从 arr 的索引 3 开始到数组末尾的部分,即 [3, 4, 5, 6, 7, 8, 9, 10, 11]
    • 在 NumPy 中,切片创建的是原数组的视图,而不是副本。这意味着 abarr 共享相同的内存空间,修改 ab 的内容会直接影响到 arr
  1. 修改视图 ab 的内容
  • a[1] = 123

    • 修改 a 中索引为 1 的元素(对应 arr 中索引为 4 的元素)。因此,arr 中的第 4 个元素会被修改为 123。
  • b[2] = 234

    • 修改 b 中索引为 2 的元素(对应 arr 中索引为 5 的元素)。因此,arr 中的第 5 个元素会被修改为 234。
  1. 打印数组 arr 的结果
  • print(arr)
    • 打印 arr 的内容,此时数组 arr 已被修改为:
      [  0   1   2   3 123 234   6   7   8   9  10  11]
      
    • 可以看到,a[1]b[2] 的修改直接影响了原始数组 arr
  1. 检查内存地址
  • print(id(a), id(b), id(arr[3:]))
    • id() 函数返回对象的唯一标识(通常是内存地址)。
    • 打印 ab 和重新创建的 arr[3:] 的内存地址。结果表明,abarr[3:] 占用不同的内存区域,但它们都是原数组 arr 的视图,即都指向arr这个数组。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值