NumPy 详解:从入门到掌握
NumPy(Numerical Python)是 Python 语言的一个开源库,是 Python 科学计算和数据分析领域的核心工具之一。它提供了多维数组对象(ndarray
),以及一系列用于快速操作数组的函数。NumPy 的出现极大地提高了 Python 在数值计算方面的性能,是 Pandas、SciPy、Matplotlib、scikit-learn 等众多库的基石。
本文将带你从零开始,逐步深入了解 NumPy 的强大功能和使用方法。
第一部分:初识 NumPy – 为什么需要它?
Python 原生的列表(list)非常灵活,可以存储不同类型的数据,且大小可变。然而,在进行大量的数值计算时,Python 列表的效率较低。主要原因包括:
- 异构性: 列表可以存储任何类型的对象,这使得 Python 需要为每个元素存储类型信息和指针,增加了开销。
- 性能: 列表的操作通常是在 Python 解释器层面进行,涉及大量的循环,速度慢。
- 功能限制: Python 列表没有内置的向量化(vectorization)操作,例如两个列表相加需要手动循环。
NumPy 的 ndarray
对象解决了这些问题:
- 同构性:
ndarray
只能存储相同数据类型的元素,这使得 NumPy 可以紧凑地存储数据,无需存储额外的类型信息,并且可以通过 C 语言的库来实现高效的数据操作。 - 高性能: NumPy 的核心是用 C 和 Fortran 编写的,其操作在底层进行,避免了 Python 循环的开销,实现了向量化计算。这意味着许多操作可以直接应用于整个数组,而无需编写显式的循环。
- 丰富的功能: NumPy 提供了大量的数学、统计、线性代数、傅里叶变换等函数,可以直接在
ndarray
上执行。
因此,对于任何涉及大量数值数据的处理和计算任务,使用 NumPy 几乎是不可或缺的选择。
第二部分:安装与导入
安装 NumPy 非常简单,推荐使用 pip
包管理器:
bash
pip install numpy
安装完成后,在 Python 代码中导入 NumPy 通常使用以下惯例:
python
import numpy as np
我们将使用 np
作为 NumPy 的别名贯穿本文。
第三部分:NumPy 的核心 – ndarray 对象
ndarray
(n-dimensional array)是 NumPy 中最重要的数据结构。它是一个多维的、同构的、固定大小的项目集合。数组中的每个元素都是相同的数据类型(dtype
),并且可以使用一个整数元组来索引。
3.1 创建 ndarray
有多种方法可以创建 ndarray
:
1. 从 Python 列表或元组创建:
“`python
从列表创建一维数组
list1 = [1, 2, 3, 4, 5]
arr1 = np.array(list1)
print(arr1)
print(type(arr1))
print(arr1.dtype) # 查看数据类型
从列表的列表创建二维数组
list2 = [[1, 2, 3], [4, 5, 6]]
arr2 = np.array(list2)
print(arr2)
print(arr2.shape) # 查看形状(行数, 列数)
print(arr2.ndim) # 查看维度
指定数据类型
arr3 = np.array([1.0, 2.0, 3.0], dtype=np.float64)
print(arr3)
print(arr3.dtype)
“`
2. 使用内置函数创建特定数组:
np.zeros(shape)
: 创建全零数组。np.ones(shape)
: 创建全一数组。np.empty(shape)
: 创建一个内容随机(取决于内存状态)的数组,比zeros
或ones
稍快。np.arange(start, stop, step)
: 类似于 Python 的range
,创建等差数组。np.linspace(start, stop, num)
: 创建指定数量的等间隔数组。
“`python
全零数组
zeros_arr = np.zeros((2, 3))
print(zeros_arr)
全一数组
ones_arr = np.ones((4, 2), dtype=np.int32) # 可以指定数据类型
print(ones_arr)
空数组
empty_arr = np.empty((3, 3))
print(empty_arr) # 内容随机
等差数组
range_arr = np.arange(0, 10, 2) # 从0到10(不包含10),步长为2
print(range_arr)
等间隔数组
linspace_arr = np.linspace(0, 1, 5) # 从0到1,共5个点
print(linspace_arr)
创建单位矩阵 (正方形数组)
identity_matrix = np.eye(3)
print(identity_matrix)
“`
3.2 ndarray 的重要属性
ndarray
对象有几个重要的属性可以帮助我们了解数组的信息:
shape
: 一个元组,表示数组在每个维度上的大小。ndim
: 数组的维度(轴的数量)。size
: 数组中元素的总数。dtype
: 数组中元素的数据类型。itemsize
: 数组中每个元素的字节大小。data
: 包含实际数组元素的缓冲区对象。
“`python
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(“Shape:”, arr.shape) # (2, 3)
print(“Dimensions:”, arr.ndim) # 2
print(“Size:”, arr.size) # 6
print(“Data type:”, arr.dtype) # int64 (取决于系统和创建方式)
print(“Item size:”, arr.itemsize) # 8 (bytes per element for int64)
“`
理解这些属性对于操作数组至关重要。
第四部分:数组的索引和切片
访问和修改 ndarray
的元素是基本操作。NumPy 提供了比 Python 列表更灵活和强大的索引和切片功能。
4.1 基本索引
类似于 Python 列表,可以使用方括号 []
加上索引来访问元素。对于多维数组,使用逗号 ,
分隔不同维度的索引。
“`python
arr1 = np.array([10, 20, 30, 40, 50])
print(arr1[0]) # 访问第一个元素: 10
print(arr1[-1]) # 访问最后一个元素: 50
arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2[0, 0]) # 访问第一行第一列元素: 1
print(arr2[1, 2]) # 访问第二行第三列元素: 6
print(arr2[2, 1]) # 访问第三行第二列元素: 8
“`
4.2 切片
切片用于获取数组的子数组。使用 start:stop:step
语法,同样使用逗号分隔不同维度的切片。
“`python
arr1 = np.array([10, 20, 30, 40, 50, 60])
print(arr1[1:4]) # 从索引1到3 (不包含4): [20 30 40]
print(arr1[:3]) # 从开始到索引2 (不包含3): [10 20 30]
print(arr1[3:]) # 从索引3到结束: [40 50 60]
print(arr1[::2]) # 所有元素,步长为2: [10 30 50]
print(arr1[::-1]) # 反转数组: [60 50 40 30 20 10]
arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2[0:2, 1:3]) # 访问前两行(0和1),以及这两行的第2列到第3列(索引1和2)
输出:
[[2 3]
[5 6]]
print(arr2[:, 1]) # 访问所有行的第2列(索引1)
输出: [2 5 8] (这是一维数组)
print(arr2[1, :]) # 访问第二行(索引1)的所有列
输出: [4 5 6] (这是一维数组)
“`
重要提示:切片是视图(View),不是副本(Copy)
NumPy 的切片操作通常返回原始数组的视图。这意味着对切片数组的修改会直接反映到原始数组上。这在处理大型数据集时非常高效,因为它避免了复制整个数组。
“`python
arr = np.array([1, 2, 3, 4, 5])
slice_arr = arr[1:4]
print(“Original slice:”, slice_arr) # [2 3 4]
slice_arr[0] = 99 # 修改切片的第一个元素
print(“Modified slice:”, slice_arr) # [99 3 4]
print(“Original array after modification:”, arr) # [ 1 99 3 4 5] – 原始数组也被修改了!
如果你需要一个独立的副本,请使用 .copy() 方法
arr_copy = arr[1:4].copy()
arr_copy[0] = 100
print(“Copy:”, arr_copy) # [100 3 4]
print(“Original array after modifying copy:”, arr) # [ 1 99 3 4 5] – 原始数组未被修改
“`
4.3 布尔索引(花式索引)
布尔索引允许你根据条件选择数组元素。你可以使用一个与原数组形状相同(或可广播)的布尔数组作为索引。
“`python
arr = np.array([10, 20, 30, 40, 50])
创建一个布尔数组,判断元素是否大于25
bool_indices = arr > 25
print(bool_indices) # [False False True True True]
使用布尔数组进行索引
print(arr[bool_indices]) # [30 40 50]
也可以直接将条件表达式放在方括号中
print(arr[arr % 2 == 0]) # 选择偶数元素: [10 20 30 40 50]
在二维数组中使用布尔索引
arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2[arr2 > 5]) # [6 7 8 9] – 结果是一维数组
“`
4.4 整数数组索引(花式索引)
你可以使用整数数组作为索引来选择元素的任意组合。结果数组的形状将根据索引数组的形状确定。
“`python
arr = np.array([10, 20, 30, 40, 50])
选择索引 0, 2, 4 的元素
print(arr[[0, 2, 4]]) # [10 30 50]
选择索引 4, 2, 0 的元素 (可以改变顺序)
print(arr[[4, 2, 0]]) # [50 30 10]
重复选择索引
print(arr[[0, 0, 2, 2]]) # [10 10 30 30]
arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
选择 (0,0), (1,1), (2,2) 的元素 (对角线)
print(arr2[[0, 1, 2], [0, 1, 2]]) # [1 5 9] – 结果是一维数组
选择行索引 [0, 2],列索引 [1, 0]
会组合成 (0,1), (0,0), (2,1), (2,0) 这四个点
print(arr2[[0, 0, 2, 2], [1, 0, 1, 0]]) # [2 1 8 7] – 结果是一维数组
如果想选择特定的行或列子集,并保持二维结构
选择行索引 [0, 2]
print(arr2[[0, 2], :])
输出:
[[1 2 3]
[7 8 9]]
选择列索引 [1, 0]
print(arr2[:, [1, 0]])
输出:
[[2 1]
[5 4]
[8 7]]
“`
重要提示:整数数组索引和布尔索引通常返回副本(Copy),不是视图(View)
与切片不同,使用整数数组索引或布尔索引获取的数组通常是原始数组的副本。修改这些副本不会影响原始数组。
第五部分:数组操作
NumPy 提供了丰富的函数来操作和处理数组。
5.1 形状操作
改变数组的形状而不改变其数据。
reshape(new_shape)
: 返回一个新形状的数组(如果可能)。ravel()
/flatten()
: 将多维数组展平为一维数组。flatten()
总是返回副本,ravel()
返回视图(如果可能)。transpose()
/.T
: 转置数组(交换行列)。resize(new_shape)
: 直接修改原数组的形状。
“`python
arr = np.arange(12) # [0 1 2 … 11]
将一维数组重塑为 3×4 的二维数组
reshaped_arr = arr.reshape((3, 4))
print(reshaped_arr)
将二维数组展平
flattened_arr = reshaped_arr.ravel()
print(flattened_arr) # 通常返回视图,修改会影响原数组
flattened_copy = reshaped_arr.flatten()
print(flattened_copy) # 总是返回副本
转置数组
transposed_arr = reshaped_arr.T
print(transposed_arr)
修改原数组形状 (不常用,可能丢失数据或填充0)
arr.resize((4, 3))
print(arr)
“`
5.2 组合与分割
将多个数组组合成一个,或将一个数组分割成多个。
np.concatenate((arr1, arr2, ...), axis=...)
: 沿指定轴连接数组。np.vstack((arr1, arr2, ...))
: 垂直(按行)堆叠数组。等同于concatenate(..., axis=0)
。np.hstack((arr1, arr2, ...))
: 水平(按列)堆叠数组。等同于concatenate(..., axis=1)
。np.split(arr, indices_or_sections, axis=...)
: 沿指定轴分割数组。np.vsplit(arr, indices_or_sections)
: 垂直(按行)分割数组。等同于split(..., axis=0)
。np.hsplit(arr, indices_or_sections)
: 水平(按列)分割数组。等同于split(..., axis=1)
。
“`python
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6]])
垂直堆叠
vstacked = np.vstack((arr1, arr2))
print(“VStack:\n”, vstacked)
水平堆叠 (arr2 需要转置或重塑以匹配列数)
arr3 = np.array([[5], [6]])
hstacked = np.hstack((arr1, arr3))
print(“HStack:\n”, hstacked)
concatenate 示例
arr4 = np.array([[7, 8]])
沿着 axis=0 (行) 连接
concatenated_rows = np.concatenate((arr1, arr4), axis=0)
print(“Concatenate (axis=0):\n”, concatenated_rows)
沿着 axis=1 (列) 连接 (需要形状匹配)
arr5 = np.array([[10], [20]])
concatenated_cols = np.concatenate((arr1, arr5), axis=1)
print(“Concatenate (axis=1):\n”, concatenated_cols)
arr_to_split = np.arange(16).reshape((4, 4))
print(“Original array for splitting:\n”, arr_to_split)
垂直分割成2块
vsplit_arrs = np.vsplit(arr_to_split, 2)
print(“VSplit into 2:\n”, vsplit_arrs) # 返回列表,包含两个子数组
水平分割成两块
hsplit_arrs = np.hsplit(arr_to_split, 2)
print(“HSplit into 2:\n”, hsplit_arrs) # 返回列表,包含两个子数组
沿着 axis=1 在索引 1 和 3 处分割
split_at_indices = np.split(arr_to_split, [1, 3], axis=1)
print(“Split at indices [1, 3] along axis=1:\n”, split_at_indices)
“`
第六部分:数学运算与通用函数(ufuncs)
NumPy 最强大的功能之一是其高效的数值计算能力。
6.1 元素级运算
NumPy 数组之间的基本算术运算(+,-,,/,*)都是元素级的。如果两个数组形状相同,则对应位置的元素进行运算。
“`python
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
print(“Addition:\n”, arr1 + arr2) # 或 np.add(arr1, arr2)
print(“Subtraction:\n”, arr1 – arr2) # 或 np.subtract(arr1, arr2)
print(“Multiplication:\n”, arr1 * arr2) # 或 np.multiply(arr1, arr2)
print(“Division:\n”, arr1 / arr2) # 或 np.divide(arr1, arr2)
print(“Power:\n”, arr1 ** 2) # 或 np.power(arr1, 2)
print(“Square Root:\n”, np.sqrt(arr1))
“`
与标量的运算也是元素级的:
python
arr = np.array([1, 2, 3, 4])
print(arr + 5) # [ 6 7 8 9]
print(arr * 2) # [ 2 4 6 8]
6.2 通用函数 (ufuncs)
通用函数(Universal Functions, ufuncs)是 NumPy 中对 ndarray
执行元素级操作的函数。它们通常快速且支持广播。NumPy 提供了大量的 ufuncs,包括:
- 数学函数:
np.sin
,np.cos
,np.tan
,np.arcsin
,np.arctan
,np.log
,np.exp
,np.sqrt
,np.abs
,np.floor
,np.ceil
,np.round
等。 - 比较函数:
np.greater
(>),
np.less(<)
,np.equal
(==),
np.not_equal(!=)
,np.maximum
,np.minimum
等。 - 逻辑函数:
np.logical_and
,np.logical_or
,np.logical_not
等。
“`python
arr = np.array([0, np.pi/2, np.pi])
print(np.sin(arr)) # [0. 1. 0.]
arr_a = np.array([1, 5, 2])
arr_b = np.array([4, 3, 6])
print(np.maximum(arr_a, arr_b)) # [4 5 6]
arr_bool = np.array([True, False, True])
print(np.logical_not(arr_bool)) # [False True False]
“`
6.3 聚合函数
NumPy 提供了用于计算数组总和、平均值、最小值、最大值等的聚合函数。这些函数可以应用于整个数组,也可以沿着指定的轴(axis)进行计算。
常用的聚合函数:
sum()
: 求和mean()
: 平均值std()
: 标准差var()
: 方差min()
: 最小值max()
: 最大值argmin()
: 最小值的索引argmax()
: 最大值的索引cumsum()
: 累积和cumprod()
: 累积积
“`python
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(“Sum of all elements:”, arr.sum()) # 21
print(“Mean of all elements:”, arr.mean()) # 3.5
沿着 axis=0 (列) 求和
print(“Sum along axis 0:”, arr.sum(axis=0)) # [5 7 9] (第一列和, 第二列和, 第三列和)
沿着 axis=1 (行) 求平均值
print(“Mean along axis 1:”, arr.mean(axis=1)) # [2. 5.] (第一行平均, 第二行平均)
print(“Minimum element:”, arr.min()) # 1
print(“Maximum element index along axis 0:”, arr.argmax(axis=0)) # [1 1 1] (每列最大值所在的行索引)
arr_single = np.array([1, 2, 3, 4, 5])
print(“Cumulative sum:”, arr_single.cumsum()) # [ 1 3 6 10 15]
“`
理解 axis
参数至关重要:
axis=0
表示操作沿着第一个轴(行)进行,聚合结果会减少行的维度。axis=1
表示操作沿着第二个轴(列)进行,聚合结果会减少列的维度。- 没有
axis
参数时,操作应用于所有元素。
6.4 矩阵/线性代数运算
NumPy 的 dot
函数或 @
运算符用于执行矩阵乘法。np.linalg
模块提供了更丰富的线性代数功能。
“`python
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
矩阵乘法
print(“Matrix multiplication (dot):\n”, np.dot(arr1, arr2))
print(“Matrix multiplication (@ operator):\n”, arr1 @ arr2)
矩阵的逆
matrix_to_invert = np.array([[1, 2], [3, 4]])
try:
inverse_matrix = np.linalg.inv(matrix_to_invert)
print(“Inverse matrix:\n”, inverse_matrix)
except np.linalg.LinAlgError:
print(“Matrix is singular and cannot be inverted.”)
矩阵的特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(arr1)
print(“Eigenvalues:”, eigenvalues)
print(“Eigenvectors:\n”, eigenvectors)
“`
第七部分:广播 (Broadcasting)
广播是 NumPy 在不同形状的数组之间执行算术运算的一种机制。当两个数组的形状不同,但满足一定的广播规则时,较小的数组的形状会被“广播”到较大数组的形状,以便进行元素级运算。
广播规则:
- 如果两个数组的维度不同,则维度较少的数组的形状会在其前面填充 1,直到维度相同。
- 如果两个数组在任一维度上的大小相同,或者其中一个数组在该维度上的大小为 1,则认为它们在该维度上是兼容的。
- 如果两个数组在任一维度上的大小不同且都不为 1,则会引发错误。
“`python
arr = np.array([[1, 2, 3], [4, 5, 6]]) # 形状 (2, 3)
scalar = 10 # 形状 () -> 广播为 (1, 1) -> 再广播为 (2, 3)
print(arr + scalar)
输出:
[[11 12 13]
[14 15 16]]
vec = np.array([100, 200, 300]) # 形状 (3,) -> 广播为 (1, 3) -> 再广播为 (2, 3)
print(arr + vec)
输出:
[[101 202 303]
[404 505 606]] # vec 的每一列广播到 arr 的对应列
形状不兼容的例子
vec2 = np.array([10, 20]) # 形状 (2,)
print(arr + vec2) # ValueError: operands could not be broadcast together with shapes (2,3) (2,)
可以通过重塑或转置来使其兼容
vec2_reshaped = vec2.reshape((2, 1)) # 形状 (2, 1) -> 广播为 (2, 3)
print(arr + vec2_reshaped)
输出:
[[ 2 3 4]
[ 5 6 7]] # vec2_reshaped 的每一行广播到 arr 的对应行
“`
广播是 NumPy 高效性的关键之一,它避免了创建不必要的大内存副本来匹配形状。
第八部分:文件输入/输出
NumPy 可以方便地将数组保存到文件或从文件加载。
np.save('filename.npy', arr)
: 将数组以.npy
格式保存(NumPy 特有的二进制格式)。np.load('filename.npy')
: 从.npy
文件加载数组。np.savetxt('filename.txt', arr, delimiter=',')
: 将数组保存为文本文件(如 CSV)。np.loadtxt('filename.txt', delimiter=',')
: 从文本文件加载数组。
“`python
arr = np.arange(10).reshape(2, 5)
保存为 .npy 文件
np.save(‘my_array.npy’, arr)
从 .npy 文件加载
loaded_arr = np.load(‘my_array.npy’)
print(“Loaded from .npy:\n”, loaded_arr)
保存为文本文件 (CSV)
np.savetxt(‘my_array.csv’, arr, delimiter=’,’)
从文本文件加载
loaded_csv = np.loadtxt(‘my_array.csv’, delimiter=’,’)
print(“Loaded from .csv:\n”, loaded_csv)
“`
.npy
格式是 NumPy 推荐的方式,因为它能保留数组的 dtype
和 shape
信息,且读写速度快。.txt
或 .csv
格式更易读,方便与其他工具共享数据,但可能需要手动处理数据类型和分隔符。
第九部分:性能优势:向量化 vs 循环
为了更直观地理解 NumPy 的性能优势,我们比较一下使用 Python 列表和 NumPy 数组进行简单运算(如数组相加)的速度。
“`python
import time
使用 Python 列表
list1 = list(range(1000000))
list2 = list(range(1000000))
start_time = time.time()
result_list = [x + y for x, y in zip(list1, list2)]
end_time = time.time()
print(f”Python list addition took: {end_time – start_time:.6f} seconds”)
使用 NumPy 数组
np_arr1 = np.arange(1000000)
np_arr2 = np.arange(1000000)
start_time = time.time()
result_np = np_arr1 + np_arr2 # 向量化操作
end_time = time.time()
print(f”NumPy array addition took: {end_time – start_time:.6f} seconds”)
“`
运行这段代码,你会发现 NumPy 数组的计算速度远远快于 Python 列表。这是因为 NumPy 的向量化操作是在底层 C 语言中执行的,而 Python 列表的循环是在解释器中执行。在实际应用中,尽量利用 NumPy 的向量化操作,避免显式的 Python 循环。
第十部分:高级主题与应用简介
掌握了以上内容,你已经具备了 NumPy 的核心使用能力。NumPy 还有一些更高级的功能和广泛的应用:
- 随机数生成:
np.random
模块提供了各种分布的随机数生成功能,对于模拟、统计分析非常有用。
python
# 生成 3x3 的服从标准正态分布的随机数
rand_matrix = np.random.randn(3, 3)
print(rand_matrix)
# 生成 0 到 100 (不包含 100) 的随机整数,形状为 2x4
rand_int_matrix = np.random.randint(0, 100, size=(2, 4))
print(rand_int_matrix) -
排序与搜索:
np.sort()
,np.argsort()
(返回排序后的索引),np.where()
(根据条件返回满足条件的元素索引)。
“`python
arr = np.array([3, 1, 4, 1, 5, 9, 2, 6])
print(“Sorted array:”, np.sort(arr))
print(“Indices of sorted elements:”, np.argsort(arr)) # [1 3 6 0 2 4 7 5]print(“Indices where element > 3:”, np.where(arr > 3)) # (array([2, 4, 5, 7]),)
结合索引使用
print(“Elements > 3:”, arr[np.where(arr > 3)]) # [4 5 9 6]
``
np.nan
* **处理缺失数据:** NumPy 使用(Not a Number)表示缺失值。需要使用专门的函数(如
np.isnan(),
np.nanmean(),
np.nan sum()`)来处理包含 NaN 的数组,因为标准的聚合函数遇到 NaN 会返回 NaN。
* 与其他库集成:
* Pandas: Pandas 的 DataFrame 和 Series 对象底层就是基于 NumPy 数组构建的。
* SciPy: 提供了更高级的科学计算模块(优化、插值、信号处理等),它们的操作对象也是 NumPy 数组。
* Matplotlib: 在 Matplotlib 中绘制数据时,通常使用 NumPy 数组作为输入。
* Scikit-learn: 大部分机器学习算法的输入数据格式要求是 NumPy 数组。
熟练使用 NumPy 是进行 Python 数据科学、机器学习、科学计算等工作的基础。
第十一部分:总结与展望
NumPy 是 Python 数值计算领域的基石。通过本文的学习,你应该已经掌握了 NumPy 的核心概念和常用操作:
- 理解
ndarray
的优势和基本属性。 - 掌握数组的创建、索引、切片、布尔索引和花式索引。
- 学会进行数组的形状操作、组合与分割。
- 熟练运用元素级运算、通用函数和聚合函数。
- 理解并利用广播机制。
- 了解 NumPy 的文件 I/O。
- 认识到 NumPy 向量化操作带来的巨大性能提升。
- 对 NumPy 的高级功能和应用有了初步了解。
从入门到掌握是一个持续学习和实践的过程。掌握了 NumPy 的基本用法后,建议多进行实践,尝试解决一些实际的数值计算问题,深入了解 ufuncs
的更多功能,并结合其他库(如 Pandas、Matplotlib)进行更复杂的数据分析和可视化任务。
NumPy 的官方文档是学习和查阅的宝库,遇到问题时,查阅官方文档通常能找到最权威和详细的解答。
希望这篇文章能帮助你踏上 NumPy 的学习之路,并在未来的数据探索和计算工作中发挥它的强大威力!祝你学习愉快!