NumPy 数组创建基础技术

NumPyBeginner
立即练习

介绍

先决条件

在开始本课程之前,你应该具备基本的 Python 编程技能。如果你还没有学习 Python,可以从我们的 Python 学习路径 开始。

欢迎来到关于 NumPy 数组创建基础技术的实验。在开始编码之前,让我们先了解一下 NumPy 是什么以及它在科学计算中的重要性。

什么是 NumPy?

NumPy(Numerical Python 的缩写)是 Python 中科学计算的基础库。它提供了强大的数据结构和函数,用于处理大型数值数组和矩阵。

为什么选择 NumPy 而不是 Python 列表?

虽然 Python 内置的列表灵活且易于使用,但在处理数值数据时存在一些局限性:

  • 性能:NumPy 数组在数学运算方面速度快得多。
  • 内存效率:NumPy 在存储相同数据量时占用的内存更少。
  • 便捷性:NumPy 提供了数百个内置数学函数。
  • 功能性:NumPy 支持矩阵乘法、傅里叶变换等高级运算。

在本实验中,你将学习创建 NumPy 数组最常用的方法。你将编写并执行 Python 脚本来练习转换 Python 序列、使用内置 NumPy 函数、操作现有数组以及从文件中加载数据。所有编码都将在 WebIDE 中完成。

从 Python 序列创建数组

创建 NumPy 数组最基本的方法是转换 Python 序列,例如列表或元组。numpy.array() 函数接收一个序列作为参数,并返回一个新的 NumPy 数组。

理解 NumPy 数组

在创建数组之前,让我们先了解 NumPy 数组的特别之处:

数组维度

  • 一维数组 (向量):一个简单的数字列表,例如 [1, 2, 3, 4]
  • 二维数组 (矩阵):一个包含行和列的数字表格,类似于电子表格
  • 三维数组 (张量):一个数字立方体,适用于图像或三维数据
Array Dimensions

与 Python 列表的关键区别

  • 同质性 (Homogeneous):所有元素必须是相同的数据类型(通常是数字)
  • 固定大小 (Fixed size):创建后,大小无法更改
  • 高效性 (Efficient):数学运算速度更快
  • 丰富的功能 (Rich functionality):支持向量化操作(一次性对整个数组进行操作)

导入 NumPy

在 Python 中,我们使用标准的别名 np 来导入 NumPy:

import numpy as np

这个 np 别名是科学计算 Python 社区广泛采用的约定。

现在让我们创建一些数组。从左侧文件浏览器中打开 array_from_sequence.py 文件。将以下代码添加到其中。此代码将导入 NumPy 库,并从 Python 列表创建一维 (1D)、二维 (2D) 和三维 (3D) 数组。

Python code to create NumPy arrays
import numpy as np

## 从列表创建一维数组
a1D = np.array([1, 2, 3, 4])
print("1D Array:")
print(a1D)

## 从列表的列表创建二维数组
a2D = np.array([[1, 2], [3, 4]])
print("\n2D Array:")
print(a2D)

## 从嵌套列表创建三维数组
a3D = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print("\n3D Array:")
print(a3D)

建议: 你可以将上面的代码复制到你的代码编辑器中,然后仔细阅读每一行代码以理解其功能。如果你需要进一步的解释,可以点击“解释代码”按钮 👆。你可以与 Labby 互动以获得个性化帮助。

添加代码后,保存文件。现在,从终端运行脚本以查看输出。

python array_from_sequence.py

你应该会看到以下输出,它显示了你创建的数组:

1D Array:
[1 2 3 4]

2D Array:
[[1 2]
 [3 4]]

3D Array:
[[[1 2]
  [3 4]]

 [[5 6]
  [7 8]]]

理解数据类型 (dtype)

NumPy 数组的所有元素都具有固定的数据类型,该类型由 dtype 参数指定。这与 Python 列表不同,Python 列表中的每个元素可以具有不同的类型。

数据类型的重要性

  • 内存效率: 不同类型使用不同量的内存
  • 性能: 操作针对特定数据类型进行了优化
  • 精度: 控制数字的存储和计算方式

常见数据类型

  • int32 / int64: 整数(32 位或 64 位)
  • float32 / float64: 小数(32 位或 64 位)
  • complex: 复数
  • bool: True/False 值

你可以在创建数组时使用 dtype 参数指定数据类型,例如 np.array([1, 2], dtype=complex)。如果你不指定 dtype,NumPy 将根据输入数据自动选择一个合适的数据类型。

使用内置数组创建函数

NumPy 提供了几个内置函数,可以直接创建数组,而无需使用 Python 序列。这些函数针对特定用例进行了优化,并且比手动从列表创建数组快得多。

为什么使用这些函数?

与其编写 np.array([0, 0, 0, 0, 0]),不如直接使用 np.zeros(5)。这些函数具有:

  • 速度更快:底层是优化的 C 代码。
  • 更具可读性:函数名清晰地表达了意图。
  • 内存效率高:直接分配内存。
  • 方便:无需手动指定每个元素。

打开 intrinsic_creation.py 文件并添加以下代码。此脚本演示了几个常用的创建函数。

import numpy as np

## 从一个范围的元素创建数组
## np.arange(start, stop, step) - 类似于 Python 的 range()
## 用例:为循环创建序列,生成索引
arr_range = np.arange(0, 10, 2)  ## [0, 2, 4, 6, 8]
print("Array from arange:")
print(arr_range)

## 在两个点之间创建具有特定数量元素的数组
## np.linspace(start, stop, num_elements) - 等间距的点
## 用例:为绘图创建点,采样数据
arr_linspace = np.linspace(0, 10, 5)  ## 5 个从 0 到 10 的点
print("\nArray from linspace:")
print(arr_linspace)

## 创建一个全为零的数组
## np.zeros((rows, columns)) - 为计算预分配数组
## 用例:在填充计算值之前预先分配数组
arr_zeros = np.zeros((2, 3))  ## 2x3 的零数组
print("\nArray of zeros:")
print(arr_zeros)

## 创建一个全为一的数组
## np.ones((rows, columns)) - 用一初始化
## 用例:创建掩码、缩放因子或算法的起始点
arr_ones = np.ones((3, 2))  ## 3x2 的一数组
print("\nArray of ones:")
print(arr_ones)

## 创建一个单位矩阵
## np.eye(size) - 对角线上为 1,其余为 0 的方阵
## 用例:线性代数、重置变换、矩阵乘法
identity_matrix = np.eye(3)  ## 3x3 单位矩阵
print("\nIdentity matrix:")
print(identity_matrix)

保存文件并在终端中执行它。

python intrinsic_creation.py

输出将显示这些函数创建的不同数组:

Array from arange:
[0 2 4 6 8]

Array from linspace:
[ 0.   2.5  5.   7.5 10. ]

Array of zeros:
[[0. 0. 0.]
 [0. 0. 0.]]

Array of ones:
[[1. 1.]
 [1. 1.]
 [1. 1.]]

Identity matrix:
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]

操作现有数组

你也可以通过修改、组合或拆分现有数组来创建新数组。本节将介绍两个重要概念:视图 (views) 与副本 (copies) 以及数组连接 (array concatenation)

视图与副本:理解内存共享

这是 NumPy 中最重要且常常让初学者感到困惑的概念之一。

什么是视图?

视图是内存中查看相同数据的不同方式。当你创建一个视图(例如通过切片)时,你并没有创建一个新数组——你只是创建了一个指向现有数据的全新引用。

什么是副本?

副本会在内存中创建一个全新的数组,拥有自己的数据。对副本的修改不会影响原始数组,反之亦然。

为什么这很重要?

  • 视图内存效率高:它们不复制数据。
  • 视图速度快:没有复制的开销。
  • 但视图可能导致意外的副作用:修改视图会改变原始数据。
  • 副本更安全:修改是隔离的,但会占用更多内存。

我们还将探讨如何将多个数组连接成一个更大的数组。

打开 array_manipulation.py 文件并添加以下代码:

import numpy as np

## --- Part 1: Views vs. Copies ---
a = np.arange(1, 5)
print("Original array 'a':", a)

## 创建一个包含前两个元素的视图
b = a[:2]
b[0] = 99 ## 修改视图
print("Modified view 'b':", b)
print("Array 'a' after modifying the view:", a) ## 'a' 也被改变了

## 创建一个副本
c = a[:2].copy()
c[0] = 0 ## 修改副本
print("\nModified copy 'c':", c)
print("Array 'a' after modifying the copy:", a) ## 'a' 未改变

## --- Part 2: Joining Arrays ---
A = np.ones((2, 2))
B = np.eye(2) * 2
C = np.zeros((2, 2))
D = np.diag((-3, -4))

## 将数组组合成一个块矩阵
block_matrix = np.block([
    [A, B],
    [C, D]
])
print("\nBlock matrix:")
print(block_matrix)

保存文件并在终端中运行它。

python array_manipulation.py

输出将演示修改视图如何影响原始数组,而修改副本则不会。它还将显示将四个较小的数组组合成一个块矩阵的结果。

Original array 'a': [1 2 3 4]
Modified view 'b': [99  2]
Array 'a' after modifying the view: [99  2  3  4]

Modified copy 'c': [0 2]
Array 'a' after modifying the copy: [99  2  3  4]

Block matrix:
[[ 1.  1.  2.  0.]
 [ 1.  1.  0.  2.]
 [ 0.  0. -3.  0.]
 [ 0.  0.  0. -4.]]

从文件读取数组

在数据分析中,一个常见的任务是将数据从文件加载到 NumPy 数组中。NumPy 在这方面表现出色,因为它能够高效地读取大型数据集,并自动将它们转换为合适的数值格式。

为什么选择 NumPy 进行文件 I/O?

  • 速度: 比逐行读取 Python 快得多
  • 类型推断: 自动检测合适的数据类型
  • 内存效率: 直接将数据加载到优化的数组中
  • 便捷性: 单个函数调用,无需复杂的解析

常见文件格式

  • CSV 文件: 逗号分隔值(最常见)
  • TSV 文件: 制表符分隔值
  • 文本文件: 空格或自定义分隔符分隔
  • 二进制文件: 适用于非常大的数据集(高级)

对于像 CSV(逗号分隔值)这样的简单文本文件,NumPy 提供了 np.loadtxt() 函数。

本实验的设置脚本已在你的项目目录中创建了一个名为 data.csv 的文件。其内容如下:

col1,col2,col3
1.0,2.5,3.2
4.5,5.0,6.8
7.3,8.1,9.9

现在,打开 read_from_file.py 文件,并添加以下代码来读取这些数据。

理解 np.loadtxt 参数

np.loadtxt() 函数有几个重要参数:

  • delimiter=',': 指定列的分隔符(CSV 文件为逗号)
  • skiprows=1: 跳过第一行(通常是标题行)
  • dtype: 可选 - 指定数据类型(如果未提供,则自动检测)
  • usecols: 可选 - 指定要读取的列
  • comments: 可选 - 指定用于忽略行的注释字符

我们使用 delimiter=',' 来指定列由逗号分隔,并使用 skiprows=1 来忽略标题行。

import numpy as np

## 从 CSV 文件加载数据
try:
    ## 相对路径会导致验证失败,请在实验中使用绝对路径
    data = np.loadtxt('/home/labex/project/data.csv', delimiter=',', skiprows=1)
    print("Data loaded from data.csv:")
    print(data)
except IOError:
    print("Error: data.csv not found.")

保存文件,然后从终端执行它。

python read_from_file.py

该脚本将从 data.csv 读取数值数据,并将其打印为 NumPy 数组。

Data loaded from data.csv:
[[1.  2.5 3.2]
 [4.5 5.  6.8]
 [7.3 8.1 9.9]]

这种方法对于将结构化数值数据加载到数组中进行进一步处理非常高效。

总结

在本实验中,你学习了创建 NumPy 数组的基本技术。你练习了从 Python 列表创建数组,使用 np.arangenp.zeros 等内置函数,通过视图、副本和连接来操作现有数组,以及使用 np.loadtxt 从文本文件加载数据。

这些技能是你将使用 Python 进行的几乎所有数值和科学计算任务的基石。通过对数组创建的扎实理解,你现在可以开始探索 NumPy 中更高级的数组操作和数学运算了。