学习 NumPy:核心概念与 PyPI 安装教程 – wiki基地


深入浅出 NumPy:核心概念详解与 PyPI 安装全攻略

引言:开启科学计算的大门

在现代科学研究、数据分析、机器学习以及人工智能领域,Python 已经成为最受欢迎的编程语言之一。而 Python 之所以能在这些领域大放异彩,很大程度上得益于其强大且丰富的第三方库生态系统。在众多库中,NumPy(Numerical Python 的缩写)无疑是基石中的基石。

NumPy 提供了一个高性能的多维数组对象以及用于处理这些数组的工具。它是许多其他科学计算库(如 SciPy, Matplotlib, scikit-learn, TensorFlow, PyTorch 等)的基础。可以说,离开了 NumPy,Python 在数值计算方面的效率将大打折扣,很多复杂的数据处理和分析任务也将难以实现。

本文旨在为初学者和希望系统性回顾 NumPy 基础知识的读者,提供一个全面的指南。我们将首先详细讲解如何通过 Python 的包管理工具 PyPI(Python Package Index)安装 NumPy,然后深入剖析 NumPy 最核心的概念——多维数组(ndarray)及其重要属性,并详细介绍数组的创建、索引、切片、操作以及 NumPy 的广播机制等关键知识点。通过本文的学习,您将能够建立起扎实的 NumPy 基础,为进一步探索更高级的科学计算和数据分析领域打下坚实的基础。

第一部分:NumPy 的安装——通过 PyPI

在开始学习 NumPy 的核心概念之前,我们首先需要将它安装到您的 Python 环境中。PyPI 是 Python 官方的第三方库仓库,而 pip 是 Python 默认的包管理器,通过 pip 从 PyPI 安装库是最常见、最便捷的方式。

1. 前提条件

在安装 NumPy 之前,请确保您的系统已经满足以下条件:

  • 安装了 Python: NumPy 支持 Python 3.7 及以上版本。您可以从 Python 官方网站 (https://www.python.org/downloads/) 下载并安装最新版本的 Python。安装时请勾选 “Add Python to PATH” 选项,以便在命令行中直接使用 pythonpip 命令。
  • 安装了 pip: 从 Python 3.4 开始,pip 默认随 Python 一同安装。如果您的 Python 版本较旧或 pip 出现问题,可以按照 Python 官方文档的方法进行安装或升级 pip

2. 强烈推荐:使用虚拟环境(Virtual Environment)

在安装任何第三方库时,都强烈推荐使用虚拟环境。虚拟环境可以在您的系统中创建一个独立的 Python 环境,使得项目所需的库与系统全局的 Python 环境隔离开来。这样做的好处包括:

  • 避免库版本冲突: 不同项目可能依赖同一库的不同版本,虚拟环境可以为每个项目维护独立的依赖关系,避免冲突。
  • 环境纯净: 您可以只在虚拟环境中安装当前项目必需的库,保持环境整洁。
  • 易于管理: 复制、备份或删除项目环境变得非常简单。

创建和激活虚拟环境的方法取决于您使用的工具。Python 3.3+ 自带 venv 模块,是创建虚拟环境的标准方式。

使用 venv 创建虚拟环境(推荐):

  1. 打开命令行或终端:
    • Windows: 命令提示符 (cmd) 或 PowerShell
    • macOS/Linux: 终端
  2. 进入您的项目目录: 例如 cd path/to/your/project
  3. 创建虚拟环境: 执行命令 python -m venv myenv。这会在当前目录下创建一个名为 myenv 的文件夹(您可以替换 myenv 为任何您喜欢的名称)。
  4. 激活虚拟环境:
    • Windows: .\myenv\Scripts\activate
    • macOS/Linux: source myenv/bin/activate
      激活成功后,您的命令行提示符前面会显示虚拟环境的名称(例如 (myenv)),表示您当前的操作都在这个独立的 Python 环境中进行。

现在您已经进入了虚拟环境,接下来就可以放心地安装 NumPy 了。

3. 使用 pip 安装 NumPy

在激活了虚拟环境后,安装 NumPy 就非常简单了。只需执行以下命令:

bash
pip install numpy

这条命令会连接到 PyPI,下载最新版本的 NumPy 包及其所有依赖(如果 NumPy 有依赖其他库的话),并将其安装到当前激活的虚拟环境中。

如果您需要安装特定版本的 NumPy,可以使用以下命令:

bash
pip install numpy==1.26.4 # 替换为您需要的版本号

安装过程可能需要一些时间,具体取决于您的网络速度。安装完成后,pip 会显示安装成功的消息。

4. 验证安装

安装完成后,您可以简单地在 Python 环境中导入 NumPy 来验证是否安装成功。

  1. 进入 Python 交互式环境: 在命令行中输入 pythonpython3(取决于您的系统配置),确保您仍在激活的虚拟环境中。
  2. 导入 NumPy 并查看版本:

    python
    import numpy as np
    print(np.__version__)

    如果能够成功导入 NumPy 并打印出其版本号(例如 1.26.4 或更高版本),说明 NumPy 已经成功安装并可以在您的虚拟环境中使用。

  3. 尝试一个简单的 NumPy 操作:

    python
    import numpy as np
    arr = np.array([1, 2, 3, 4, 5])
    print(arr)
    print(arr.shape)

    如果这段代码能够顺利执行并打印出数组和其形状,恭喜您,NumPy 环境已准备就绪,您可以开始探索它的强大功能了!

5. 安装故障排除

在安装过程中,您可能会遇到一些问题。以下是一些常见的故障及其解决方法:

  • 网络问题: 如果下载速度很慢或连接超时,可能是网络问题。您可以尝试更换网络环境,或者使用国内的 PyPI 镜像源来加速下载。例如,使用豆瓣源:
    bash
    pip install numpy -i https://pypi.doubanio.com/simple/ --trusted-host pypi.doubanio.com

    或者清华源:
    bash
    pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple/ --trusted-host pypi.tuna.tsinghua.edu.cn
  • pip 版本过旧: 有时旧版本的 pip 可能无法正确安装最新的库。您可以升级 pip:
    bash
    python -m pip install --upgrade pip
  • 权限问题: 在某些系统上,直接安装到系统全局 Python 环境可能需要管理员权限。这就是为什么强烈推荐使用虚拟环境的原因,在虚拟环境中通常没有权限问题。如果您坚持不使用虚拟环境并在全局环境安装遇到权限问题,可以尝试使用 sudo (macOS/Linux) 或以管理员身份运行命令提示符 (Windows),但这通常不是推荐的做法。
  • 编译器或构建工具缺失: 在某些情况下,安装某些需要编译的 Python 库(NumPy 通常预编译好了轮子文件 .whl,但在特殊情况下或安装旧版本时可能需要)可能依赖于 C 或 Fortran 编译器。如果您在 Windows 上遇到编译错误,可能需要安装 Microsoft Visual C++ Build Tools。在 Linux 上,可能需要安装 build-essential 或类似的开发工具包。但是,对于大多数现代 Python 版本和 NumPy 版本,通过 pip 安装应该会自动下载预编译好的二进制包,通常不会遇到这个问题。

通过以上步骤,您应该能够成功安装 NumPy 并为其后续学习做好准备。

第二部分:NumPy 的核心概念——多维数组(ndarray)及其操作

安装好 NumPy 后,我们就可以深入学习它的核心——ndarray 对象以及如何有效地使用它。

1. ndarray:NumPy 的基石

ndarray (n-dimensional array) 是 NumPy 中最重要的数据结构。它表示一个由具有相同数据类型的元素组成的多维同质数组。与 Python 原生的列表(list)相比,ndarray 具有以下显著优势:

  • 速度快: NumPy 的操作是向量化的,并且许多底层代码是用 C 或 Fortran 编写的,这使得它在处理大型数组时比 Python 列表快得多。
  • 内存效率高: ndarray 中的元素都是相同类型的,存储更紧凑。此外,NumPy 可以直接对整块内存进行操作,而 Python 列表存储的是对象的引用,开销更大。
  • 功能丰富: NumPy 提供了大量的数学函数和操作,可以轻松地对整个数组或数组的子集进行计算。

简而言之,当进行数值计算时,尽可能地使用 NumPy 数组而不是 Python 列表。

2. ndarray 的重要属性

每个 ndarray 对象都有一些重要的属性,可以帮助我们了解数组的结构和内容:

  • .shape 一个元组,表示数组在每个维度上的大小。例如,一个形状为 (3, 4) 的二维数组有 3 行和 4 列。一个一维数组的形状可能像 (5,)
  • .ndim 一个整数,表示数组的维度数量(轴的数量)。
  • .size 一个整数,表示数组中元素的总数量,等于 .shape 元组中所有元素的乘积。
  • .dtype 一个对象,表示数组中元素的数据类型。所有元素都必须具有相同的数据类型。NumPy 提供了多种数据类型,如 int64 (64位整数), float64 (64位浮点数), bool (布尔值), complex128 (128位复数) 等。
  • .itemsize 一个整数,表示数组中每个元素占用的字节数。例如,float64itemsize 通常是 8。
  • .data 一个缓冲区对象,指向数组元素所在的内存地址。通常我们不需要直接操作它。

示例:

“`python
import numpy as np

创建一个二维数组

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

print(arr)

输出:

[[1 2 3]

[4 5 6]]

print(“形状:”, arr.shape) # 输出: 形状: (2, 3)
print(“维度:”, arr.ndim) # 输出: 维度: 2
print(“元素总数:”, arr.size) # 输出: 元素总数: 6
print(“元素类型:”, arr.dtype) # 输出: 元素类型: int64 (或根据系统可能是 int32)
print(“单个元素字节数:”, arr.itemsize) # 输出: 单个元素字节数: 8 (如果 dtype 是 int64)
“`

3. 创建 ndarray

有多种方法可以创建 ndarray

  • 从 Python 列表或元组创建: 使用 np.array() 函数。

    “`python
    list_data = [1, 2, 3]
    arr1d = np.array(list_data)
    print(arr1d) # [1 2 3]

    list_of_lists = [[1, 2], [3, 4]]
    arr2d = np.array(list_of_lists)
    print(arr2d)

    [[1 2]

    [3 4]]

    可以指定数据类型

    arr_float = np.array([1.0, 2.5, 3.1], dtype=np.float32)
    print(arr_float) # [1. 2.5 3.1]
    print(arr_float.dtype) # float32
    “`

  • 使用 NumPy 的内置函数: NumPy 提供了许多用于创建特定类型数组的函数。

    • np.zeros(shape, dtype=float):创建一个指定形状和类型的全零数组。
    • np.ones(shape, dtype=float):创建一个指定形状和类型的全一数组。
    • np.empty(shape, dtype=float):创建一个指定形状和类型的空数组,其元素值是随机的(取决于内存中的内容)。
    • np.arange(start, stop, step, dtype=None):创建一个给定间隔内的均匀间隔值数组(类似 Python 的 range)。stop 值不包含在内。
    • np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None):创建一个指定间隔内包含指定数量元素的均匀间隔值数组。stop 值默认包含在内。
    • np.full(shape, fill_value, dtype=None):创建一个指定形状和类型的全填充数组。
    • np.eye(N, M=None, k=0, dtype=float):创建一个对角线为 1,其余元素为 0 的二维数组(单位矩阵)。N 是行数,M 是列数,k 是对角线索引(0 为主对角线)。

    示例:

    “`python
    zeros_arr = np.zeros((2, 3))
    print(“全零数组:\n”, zeros_arr)

    [[0. 0. 0.]

    [0. 0. 0.]]

    ones_arr = np.ones((4,))
    print(“全一数组:\n”, ones_arr)

    [1. 1. 1. 1.]

    empty_arr = np.empty((2, 2))
    print(“空数组:\n”, empty_arr) # 值不确定,每次运行可能不同

    range_arr = np.arange(0, 10, 2)
    print(“arange数组:”, range_arr) # [0 2 4 6 8]

    linspace_arr = np.linspace(0, 1, 5)
    print(“linspace数组:”, linspace_arr) # [0. 0.25 0.5 0.75 1. ]

    full_arr = np.full((3, 2), 7)
    print(“全7数组:\n”, full_arr)

    [[7 7]

    [7 7]

    [7 7]]

    eye_arr = np.eye(3)
    print(“单位矩阵:\n”, eye_arr)

    [[1. 0. 0.]

    [0. 1. 0.]

    [0. 0. 1.]]

    “`

4. 数组索引与切片

像 Python 列表一样,NumPy 数组也可以通过索引和切片访问其元素。但 NumPy 的索引和切片功能更加强大和灵活。

  • 基本索引: 使用方括号 [] 访问单个元素或子数组。对于多维数组,可以使用逗号分隔不同维度的索引。

    “`python
    arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    print(“原始数组:\n”, arr)

    print(“第一个元素:”, arr[0, 0]) # 输出: 1
    print(“第二行第三列元素:”, arr[1, 2]) # 输出: 6
    print(“第三行:”, arr[2]) # 输出: [7 8 9]
    print(“第一列:”, arr[:, 0]) # 输出: [1 4 7] (使用切片和基本索引)
    “`

  • 切片 (Slicing): 使用 start:stop:step 语法获取数组的子视图。切片操作返回的是原数组的“视图”(view),而不是副本(copy)。这意味着对切片进行的修改会直接影响原数组。

    “`python
    arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

    print(“前两行:\n”, arr[:2, :]) # 或 arr[:2]

    [[1 2 3]

    [4 5 6]]

    print(“后两列:\n”, arr[:, 1:])

    [[2 3]

    [5 6]

    [8 9]]

    print(“第二行和第三行,第二列到第三列:\n”, arr[1:3, 1:3])

    [[5 6]

    [8 9]]

    切片是视图,修改会影响原数组

    sub_arr = arr[:2, :2]
    print(“子数组视图:\n”, sub_arr)

    [[1 2]

    [4 5]]

    sub_arr[0, 0] = 99
    print(“修改子数组后:\n”, sub_arr)

    [[99 2]

    [ 4 5]]

    print(“修改后原始数组:\n”, arr)

    [[99 2 3]

    [ 4 5 6]

    [ 7 8 9]]

    “`

  • 花式索引 / 整数数组索引 (Fancy Indexing / Integer Array Indexing): 使用一个整数数组或列表作为索引,可以根据索引数组的元素来选择原数组中的元素。花式索引返回的是数组的“副本”(copy),而不是视图。

    “`python
    arr = np.array([10, 20, 30, 40, 50])
    indices = [1, 3, 0]
    selected_elements = arr[indices]
    print(“通过整数数组索引选择元素:”, selected_elements) # [20 40 10]

    arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    row_indices = [0, 2, 1]
    col_indices = [1, 0, 2]

    选择元素 (arr2d[0, 1]), (arr2d[2, 0]), (arr2d[1, 2])

    selected_elements_2d = arr2d[row_indices, col_indices]
    print(“通过整数数组索引选择二维元素:”, selected_elements_2d) # [2 7 6]

    花式索引是副本,修改不影响原数组

    copy_arr = arr[indices]
    copy_arr[0] = 999
    print(“修改副本后:”, copy_arr) # [999 40 10]
    print(“原始数组:”, arr) # [10 20 30 40 50] (未改变)
    “`

  • 布尔索引 (Boolean Indexing / Masking): 使用一个与原数组形状相同的布尔数组作为索引,布尔数组中为 True 的位置对应的原数组元素会被选中。布尔索引返回的也是数组的“副本”。

    “`python
    arr = np.array([10, 20, 30, 40, 50])
    mask = arr > 25
    print(“布尔掩码:”, mask) # [False False True True True]
    selected_elements = arr[mask]
    print(“通过布尔索引选择元素:”, selected_elements) # [30 40 50]

    arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    mask2d = arr2d % 2 == 0 # 选择偶数
    print(“二维布尔掩码:\n”, mask2d)

    [[False True False]

    [ True False True]

    [False True False]]

    selected_elements_2d = arr2d[mask2d]
    print(“通过布尔索引选择二维元素:”, selected_elements_2d) # [2 4 6 8] (结果是一维数组)

    布尔索引是副本,修改不影响原数组

    copy_arr = arr[mask]
    copy_arr[0] = 999
    print(“修改副本后:”, copy_arr) # [999 40 50]
    print(“原始数组:”, arr) # [10 20 30 40 50] (未改变)
    ``
    理解切片是视图而花式索引/布尔索引是副本对于避免意外修改数据非常重要。如果您需要切片的副本,可以使用
    .copy()方法:sub_arr_copy = arr[:2, :2].copy()`。

5. 数组操作

NumPy 提供了丰富的数组操作功能,包括元素级别的数学运算、比较运算、逻辑运算以及聚合函数等。

  • 元素级别运算: 算术运算符 (+, -, , /, //, %, *) 和比较运算符 (>, <, >=, <=, ==, !=) 在 NumPy 数组上默认执行元素级别的操作。

    “`python
    arr1 = np.array([1, 2, 3])
    arr2 = np.array([4, 5, 6])

    print(“加法:”, arr1 + arr2) # [5 7 9]
    print(“乘法:”, arr1 * arr2) # [4 10 18]
    print(“平方:”, arr1 ** 2) # [1 4 9]
    print(“比较:”, arr1 > arr2) # [False False False]

    arr2d_a = np.array([[1, 2], [3, 4]])
    arr2d_b = np.array([[5, 6], [7, 8]])
    print(“二维加法:\n”, arr2d_a + arr2d_b)

    [[ 6 8]

    [10 12]]

    “`
    这些操作也非常快,因为它们是 NumPy 内部向量化实现的。

  • 数学函数: NumPy 提供了大量的通用函数(ufunc),可以直接应用于数组的每个元素。

    “`python
    arr = np.array([0, np.pi/2, np.pi])
    print(“sin:”, np.sin(arr)) # [0.000e+00 1.000e+00 1.225e-16] (接近于0)

    arr = np.array([1, 4, 9])
    print(“sqrt:”, np.sqrt(arr)) # [1. 2. 3.]

    arr = np.array([1, 2, 3])
    print(“exp:”, np.exp(arr)) # [ 2.71828183 7.3890561 20.08553692]
    ``
    常见的 ufunc 包括
    np.abs,np.log,np.log10,np.ceil,np.floor,np.round,np.maximum,np.minimum` 等。

  • 聚合函数 (Aggregation): NumPy 提供了计算数组统计特性的函数,如求和、平均值、最小值、最大值等。这些函数可以应用于整个数组,也可以沿着某个特定的轴(维度)进行计算。

    “`python
    arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    print(“原始数组:\n”, arr)

    print(“总和:”, np.sum(arr)) # 输出: 45 (1+2+3+4+5+6+7+8+9)
    print(“平均值:”, np.mean(arr)) # 输出: 5.0 (45 / 9)
    print(“最小值:”, np.min(arr)) # 输出: 1
    print(“最大值:”, np.max(arr)) # 输出: 9
    print(“标准差:”, np.std(arr)) # 输出: 2.581989…

    沿着轴进行计算

    print(“沿着行求和 (axis=0):”, np.sum(arr, axis=0)) # [1+4+7, 2+5+8, 3+6+9] = [12 15 18]
    print(“沿着列求和 (axis=1):”, np.sum(arr, axis=1)) # [1+2+3, 4+5+6, 7+8+9] = [ 6 15 24]

    print(“沿着行求最大值 (axis=0):”, np.max(arr, axis=0)) # [7 8 9]
    print(“沿着列求最小值 (axis=1):”, np.min(arr, axis=1)) # [1 4 7]
    ``
    理解
    axis参数非常重要。对于一个 N 维数组,axis=0表示沿着第一个轴(通常是“行”)进行操作,结果会减少一个维度;axis=1` 表示沿着第二个轴(通常是“列”)进行操作,依此类推。

  • 矩阵乘法: 对于二维数组,NumPy 提供了矩阵乘法的功能。从 Python 3.5 开始,可以使用 @ 运算符进行矩阵乘法。NumPy 也提供了 np.dot() 函数,虽然它可以用于矩阵乘法,但对于多维数组有更广泛的含义(点积)。

    “`python
    mat1 = np.array([[1, 2], [3, 4]])
    mat2 = np.array([[5, 6], [7, 8]])

    print(“矩阵乘法 (@ 运算符):\n”, mat1 @ mat2)

    [[15 + 27, 16 + 28],

    [35 + 47, 36 + 48]]

    [[19 22]

    [43 50]]

    print(“矩阵乘法 (np.dot):\n”, np.dot(mat1, mat2))

    [[19 22]

    [43 50]]

    “`

6. 广播机制 (Broadcasting)

广播是 NumPy 的一个强大而灵活的功能,它描述了 NumPy 如何在执行算术运算时处理具有不同形状的数组。当两个形状不同的数组进行元素级别运算时,如果满足某些规则,NumPy 会自动扩展(“广播”)其中一个或两个数组,使其形状兼容,而无需实际复制数据。

广播的规则:当操作两个数组时,NumPy 会逐个比较它们的维度,从最后一个维度开始向前比较。两个维度是兼容的,如果:
1. 它们相等。
2. 其中一个维度为 1。
不兼容的维度会引发错误。

如果两个数组的维度数量不同,那么维度较少的数组会在其前面填充 1,直到维度数量相等,然后再按照上述规则进行比较。

示例:

  • 标量与数组广播: 标量可以广播到任何形状的数组。

    python
    arr = np.array([1, 2, 3])
    print(arr + 5) # [1+5, 2+5, 3+5] = [6 7 8]

    这里的标量 5 被广播成形状为 (3,) 的数组 [5, 5, 5],然后进行元素加法。

  • 一维数组与二维数组广播:

    “`python
    arr2d = np.array([[1, 2, 3], [4, 5, 6]]) # 形状 (2, 3)
    arr1d = np.array([10, 20, 30]) # 形状 (3,)

    print(arr2d + arr1d)

    广播过程:

    arr1d 的形状 (3,) 被扩展为 (1, 3)

    然后 (1, 3) 沿着第一个轴(行)被广播以匹配 (2, 3)

    相当于 [[10, 20, 30], [10, 20, 30]]

    结果:

    [[1 + 10, 2 + 20, 3 + 30],

    [4 + 10, 5 + 20, 6 + 30]]

    [[11 22 33]

    [14 25 36]]

    “`

  • 不兼容的广播示例:

    “`python
    arr2d = np.array([[1, 2], [3, 4]]) # 形状 (2, 2)
    arr1d = np.array([10, 20, 30]) # 形状 (3,)

    比较维度:

    数组1: (2, 2)

    数组2: ( , 3) -> 扩展为 (1, 3)

    从后向前比较:

    最后一个维度: 2 和 3 -> 不兼容

    这将引发 ValueError: operands could not be broadcast together with shapes (2,2) (3,)

    print(arr2d + arr1d) # 会报错

    “`

广播机制是 NumPy 提高效率的关键之一,它避免了创建大型的中间数组副本。理解广播规则对于编写高效的 NumPy 代码非常重要。

7. 数组的重塑与操作

NumPy 提供了多种方法来改变数组的形状或组合/分割数组。

  • 重塑 (Reshaping): 使用 .reshape() 方法或 np.reshape() 函数改变数组的形状。新的形状必须与原数组的总元素数量一致。可以使用 -1 让 NumPy 自动计算该维度的大小。

    “`python
    arr = np.arange(12) # [ 0 1 2 3 4 5 6 7 8 9 10 11]
    print(“原始数组:”, arr)

    reshaped_arr = arr.reshape((3, 4))
    print(“重塑为 (3, 4):\n”, reshaped_arr)

    [[ 0 1 2 3]

    [ 4 5 6 7]

    [ 8 9 10 11]]

    reshaped_arr_auto = arr.reshape((2, -1)) # 自动计算列数
    print(“重塑为 (2, -1):\n”, reshaped_arr_auto)

    [[ 0 1 2 3 4 5]

    [ 6 7 8 9 10 11]]

    ``.reshape()` 返回的是一个视图(如果可能的话),否则是副本。

  • 展平 (Flattening): 将多维数组变为一维数组。可以使用 .ravel().flatten().ravel() 返回的是一个视图(如果可能),而 .flatten() 总是返回一个副本。

    python
    arr2d = np.array([[1, 2, 3], [4, 5, 6]])
    print("展平 (ravel):", arr2d.ravel()) # [1 2 3 4 5 6]
    print("展平 (flatten):", arr2d.flatten()) # [1 2 3 4 5 6]

  • 转置 (Transposing): 交换数组的维度。对于二维数组,就是行列互换。可以使用 .T 属性或 np.transpose() 函数。

    “`python
    arr2d = np.array([[1, 2], [3, 4], [5, 6]]) # 形状 (3, 2)
    print(“原始数组:\n”, arr2d)

    transposed_arr = arr2d.T
    print(“转置后数组:\n”, transposed_arr) # 形状 (2, 3)

    [[1 3 5]

    [2 4 6]]

    “`
    转置通常返回的是视图。

  • 堆叠 (Stacking): 将多个数组沿某个轴堆叠起来形成一个更高维度的数组。np.vstack()(垂直堆叠,沿第一个轴)和 np.hstack()(水平堆叠,沿第二个轴)是常用的函数。更通用的函数是 np.concatenate(),它允许指定沿着哪个轴连接。

    “`python
    arr1 = np.array([1, 2])
    arr2 = np.array([3, 4])

    print(“垂直堆叠 (vstack):\n”, np.vstack((arr1, arr2)))

    [[1 2]

    [3 4]]

    print(“水平堆叠 (hstack):”, np.hstack((arr1, arr2)))

    [1 2 3 4]

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

    print(“concatenate 沿轴 0:\n”, np.concatenate((arr_a, arr_b), axis=0))

    [[1 2]

    [3 4]

    [5 6]

    [7 8]]

    print(“concatenate 沿轴 1:\n”, np.concatenate((arr_a, arr_b), axis=1))

    [[1 2 5 6]

    [3 4 7 8]]

    “`

  • 分割 (Splitting): 将一个数组沿某个轴分割成多个子数组。np.vsplit()(垂直分割)、np.hsplit()(水平分割)和 np.split() 是常用的函数。

    “`python
    arr = np.arange(12).reshape((3, 4))
    print(“原始数组:\n”, arr)

    split_v = np.vsplit(arr, 3) # 沿垂直方向分割成 3 份
    print(“垂直分割:\n”, split_v)

    [array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8, 9, 10, 11]])]

    split_h = np.hsplit(arr, 2) # 沿水平方向分割成 2 份
    print(“水平分割:\n”, split_h)

    [array([[ 0, 1], [ 4, 5], [ 8, 9]]), array([[ 2, 3], [ 6, 7], [10, 11]])]

    “`

  • 添加/移除维度:

    • 使用 np.newaxisNone 在现有轴上添加一个新的维度。这常用于广播。

      “`python
      arr = np.array([1, 2, 3]) # 形状 (3,)
      print(“原始形状:”, arr.shape)

      arr_row = arr[np.newaxis, :] # 在第一个轴前添加一个新维度
      print(“添加行维度后形状:”, arr_row.shape) # (1, 3)
      print(arr_row) # [[1 2 3]]

      arr_col = arr[:, np.newaxis] # 在第二个轴(后面)添加一个新维度
      print(“添加列维度后形状:”, arr_col.shape) # (3, 1)
      print(arr_col)

      [[1]

      [2]

      [3]]

      ``
      * 使用
      np.squeeze()` 移除形状中大小为 1 的维度。

      “`python
      arr = np.array([[[1], [2], [3]]]) # 形状 (1, 3, 1)
      print(“原始形状:”, arr.shape)

      squeezed_arr = np.squeeze(arr)
      print(“移除大小为 1 的维度后形状:”, squeezed_arr.shape) # (3,)
      print(squeezed_arr) # [1 2 3]
      “`

8. 数据类型 (dtype) 的重要性

前面提到,ndarray 是同质的,所有元素必须具有相同的数据类型。数据类型 (dtype) 决定了数组中每个元素在内存中占用的空间以及如何解释这些字节。指定合适的数据类型对于内存使用和计算性能都很重要。

NumPy 提供了比 Python 原生类型更丰富、更精确的数值类型,例如不同位数的整数(int8, int16, int32, int64)、浮点数(float16, float32, float64)、复数(complex64, complex128)、布尔值(bool)等。

创建数组时,NumPy 会根据输入的数据自动推断 dtype。如果需要特定的类型,可以使用 dtype 参数显式指定。

“`python
arr_int = np.array([1, 2, 3]) # 默认可能是 int64 或 int32
print(arr_int.dtype)

arr_float = np.array([1.0, 2.0, 3.0]) # 默认 float64
print(arr_float.dtype)

arr_explicit_float = np.array([1, 2, 3], dtype=np.float32)
print(arr_explicit_float.dtype) # float32

arr_bool = np.array([0, 1, 0], dtype=np.bool_)
print(arr_bool.dtype) # bool_
print(arr_bool) # [False True False]
“`

可以通过 .astype() 方法将数组转换为不同的数据类型,这会返回一个新数组(副本)。

python
arr_float = np.array([1.5, 2.3, 3.7])
arr_int_casted = arr_float.astype(np.int64)
print(arr_int_casted) # [1 2 3] (小数部分被截断)
print(arr_int_casted.dtype) # int64

选择合适的数据类型可以显著影响程序的内存占用,尤其是在处理海量数据时。例如,如果确定数据不会超过某个范围,使用 int32 而不是默认的 int64 可以节省一半的内存。

结论

NumPy 作为 Python 科学计算的基石,其重要性不言而喻。通过本文,我们详细了解了如何通过 PyPI 及其配套工具 pip 安装 NumPy,并强烈推荐了使用虚拟环境的最佳实践。随后,我们深入学习了 NumPy 最核心的数据结构 ndarray 的特性,包括其形状、维度、大小和数据类型等重要属性。我们还探讨了创建 ndarray 的各种方法,以及 NumPy 强大的索引、切片和各种数组操作,特别是广播机制这一独特的强大功能。

掌握 NumPy 的 ndarray 及其操作是使用 Python 进行高效数值计算和数据分析的关键。虽然本文涵盖了 NumPy 的核心概念,但这仅仅是 NumPy 功能的冰山一角。NumPy 还提供了线性代数、随机数生成、傅里叶变换等更多高级功能。

学习 NumPy 的最佳方式是实践。建议您在阅读本文的同时,在 Python 环境中动手尝试每个代码示例,并通过修改参数和数据来观察结果。熟悉并熟练运用 ndarray 和 NumPy 的各种函数,将极大地提升您在科学计算和数据处理领域的效率。

现在,您已经掌握了 NumPy 的安装方法和核心概念,可以自信地开始使用它来解决实际问题了。祝您在探索 NumPy 的世界中取得丰硕的成果!

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部