Numpy基础到进阶:数据科学家必读 – wiki词典


NumPy 从基础到进阶:数据科学家必读

在数据科学的世界里,高效的数据处理和数值计算是基石。NumPy (Numerical Python) 正是 Python 生态系统中解决这一核心需求的强大库。它提供了高性能的多维数组对象,以及用于处理这些数组的工具。对于任何数据科学家来说,熟练掌握 NumPy 不仅仅是锦上添花,更是不可或缺的生存技能。

本文将带领您从 NumPy 的基础概念出发,逐步深入到其高级功能,揭示它如何在数据科学工作流中发挥关键作用。

1. NumPy 基础:数组与核心概念

1.1 为什么是 NumPy?

Python 原生的列表 (list) 可以存储不同类型的数据,但在进行大规模数值计算时效率低下。NumPy 的 ndarray 对象则专门设计用于存储同质化的数值数据,并利用 C/Fortran 等底层语言进行优化,从而实现了显著的性能提升。此外,NumPy 提供了大量针对数组操作的优化函数,避免了编写复杂的循环。

1.2 ndarray:NumPy 的核心

ndarray (n-dimensional array) 是 NumPy 的核心数据结构,它是一个存储相同类型元素的网格。
维度 (Dimensions/Axes):数组的轴数。例如,一个一维数组有一个轴,一个矩阵有两个轴。
形状 (Shape):一个元组,表示数组在每个维度上的大小。例如,一个 2×3 的矩阵形状为 (2, 3)
数据类型 (Data Type / dtype):数组中元素的类型,如 int32, float64 等。所有元素必须是同一类型。

创建数组:
“`python
import numpy as np

从 Python 列表创建

arr1 = np.array([1, 2, 3, 4, 5])
print(f”arr1: {arr1}, shape: {arr1.shape}, dtype: {arr1.dtype}”)

多维数组

arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(f”arr2:\n{arr2}, shape: {arr2.shape}”)

使用内置函数创建

zeros_arr = np.zeros((2, 3)) # 全零数组
ones_arr = np.ones((3, 2), dtype=int) # 全一数组,指定整数类型
arange_arr = np.arange(0, 10, 2) # 类似 range()
linspace_arr = np.linspace(0, 1, 5) # 0到1之间等距的5个点
identity_matrix = np.eye(3) # 单位矩阵
“`

1.3 基本数组操作

NumPy 数组支持直观的元素级数学运算。

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

print(f”a + b: {a + b}”) # 数组相加
print(f”a * 2: {a * 2}”) # 标量乘法
print(f”a ** 2: {a ** 2}”) # 元素级平方

矩阵乘法 (@ 或 np.dot)

matrix_a = np.array([[1, 2], [3, 4]])
matrix_b = np.array([[5, 6], [7, 8]])
print(f”Matrix multiplication:\n{matrix_a @ matrix_b}”)
“`

1.4 广播 (Broadcasting)

广播是 NumPy 的一个强大特性,它允许不同形状的数组在特定条件下进行算术运算,而无需显式地复制数据。简单来说,当两个数组的维度不匹配时,NumPy 会尝试“扩展”较小数组的维度,使其与较大数组兼容。

广播规则:
1. 如果两个数组的维度数不同,那么维度较小的数组的形状会在其前面用 1 填充。
2. 对于任一维度,如果两个数组在该维度上的大小相同,或者其中一个数组在该维度上的大小为 1,那么它们是兼容的。
3. 如果两个数组在任何维度上的大小都不同且都不是 1,则会引发错误。

“`python
arr = np.array([[1, 2, 3], [4, 5, 6]]) # 形状 (2, 3)
scalar = 10 # 形状 ()

print(f”arr + scalar:\n{arr + scalar}”) # 标量被广播到整个数组

vec = np.array([10, 20, 30]) # 形状 (3,)
print(f”arr + vec:\n{arr + vec}”) # vec 被广播到 arr 的每一行
“`

2. NumPy 进阶:索引、切片与高级操作

2.1 索引与切片

类似于 Python 列表,NumPy 数组也支持强大的索引和切片功能,但更灵活且功能更强大。

“`python
data = np.arange(1, 17).reshape(4, 4)
print(f”Original data:\n{data}”)

基本索引

print(f”Element at (0, 0): {data[0, 0]}”)
print(f”First row: {data[0, :]}”) # 或 data[0]
print(f”First column: {data[:, 0]}”)

切片

print(f”Sub-array (rows 0-1, cols 1-2):\n{data[0:2, 1:3]}”)
print(f”Last row: {data[-1, :]}”)
print(f”Every other row:\n{data[::2, :]}”)

布尔索引:根据条件选择元素

mask = data > 8
print(f”Elements > 8:\n{data[mask]}”)
print(f”Elements > 8 (alternative):\n{data[data > 8]}”)

花式索引 (Fancy Indexing):使用整数数组作为索引

rows = np.array([0, 2])
cols = np.array([1, 3])
print(f”Elements at (0,1) and (2,3):\n{data[rows, cols]}”) # 返回 [2 12]

使用一个整数数组选择行

print(f”Selected rows (0, 2):\n{data[[0, 2]]}”)
“`

2.2 形状操作 (Reshaping, Stacking)

改变数组的形状是数据预处理的常见操作。

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

reshape: 不改变数据,只改变数组的视图

reshaped_arr = arr.reshape(3, 3)
print(f”Reshaped:\n{reshaped_arr}”)

flatten: 将多维数组展平为一维数组

flat_arr = reshaped_arr.flatten()
print(f”Flattened: {flat_arr}”)

transpose: 转置数组

print(f”Transposed:\n{reshaped_arr.T}”)

concatenate: 沿指定轴连接数组

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

垂直堆叠 (行增加)

vstack_arr = np.vstack((a, b))
print(f”VStack:\n{vstack_arr}”)

水平堆叠 (列增加)

hstack_arr = np.hstack((a, b))
print(f”HStack:\n{hstack_arr}”)

dstack: 沿第三个轴堆叠 (通常用于图像处理,堆叠通道)

column_stack: 将一维数组作为列堆叠成二维数组

row_stack: 等同于 vstack

“`

2.3 通用函数 (Universal Functions – ufuncs)

ufuncs 是对 ndarray 中的每个元素执行操作的函数。它们是矢量化的,这意味着它们直接在整个数组上操作,比 Python 的循环快得多。常见的 ufuncs 包括数学运算(np.add, np.sqrt, np.exp, np.sin 等)、比较运算(np.greater, np.equal 等)和聚合函数。

“`python
x = np.arange(1, 6) # [1 2 3 4 5]

print(f”Square root: {np.sqrt(x)}”)
print(f”Exponential: {np.exp(x)}”)
print(f”Max element: {np.max(x)}”)
print(f”Sum of elements: {np.sum(x)}”)
print(f”Mean of elements: {np.mean(x)}”)
print(f”Standard deviation: {np.std(x)}”)

matrix = np.array([[1, 2, 3], [4, 5, 6]])
print(f”Sum along axis 0 (columns): {np.sum(matrix, axis=0)}”) # [5 7 9]
print(f”Sum along axis 1 (rows): {np.sum(matrix, axis=1)}”) # [ 6 15]
“`

2.4 线性代数

NumPy 的 linalg 模块提供了强大的线性代数功能,对于机器学习和统计建模至关重要。

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

矩阵乘法

print(f”Matrix product (dot):\n{np.dot(A, B)}”)
print(f”Matrix product (@ operator):\n{A @ B}”)

逆矩阵

inv_A = np.linalg.inv(A)
print(f”Inverse of A:\n{inv_A}”)

特征值和特征向量

eigenvalues, eigenvectors = np.linalg.eig(A)
print(f”Eigenvalues: {eigenvalues}”)
print(f”Eigenvectors:\n{eigenvectors}”)

求解线性方程组 Ax = b

b_vec = np.array([9, 10])
x_solution = np.linalg.solve(A, b_vec)
print(f”Solution to Ax=b: {x_solution}”)
“`

3. NumPy 在数据科学中的高级应用

3.1 性能优化与内存管理

NumPy 数组的同质性是其高性能的关键。数据连续存储在内存中,可以利用 CPU 的 SIMD (单指令多数据) 指令进行批量处理。

  • 矢量化操作:尽量避免 Python 循环,转而使用 NumPy 的 ufuncs 和数组操作。
  • 就地操作:一些操作(如 +=, *=)是就地 (in-place) 操作,可以减少内存分配和复制。
  • 视图 vs 副本:切片通常返回原始数组的视图 (view),而不是副本 (copy),这意味着对视图的修改会影响原始数组。使用 .copy() 明确创建副本。

“`python
large_arr = np.random.rand(1000000)

避免循环 (慢)

result = [x * 2 for x in large_arr]

使用矢量化操作 (快)

result = large_arr * 2
“`

3.2 随机数生成

np.random 模块提供了各种概率分布的随机数生成功能,在模拟、采样和模型初始化中非常有用。

“`python

均匀分布

uniform_samples = np.random.rand(3, 3) # [0, 1) 之间的随机数

正态分布 (均值0,标准差1)

normal_samples = np.random.randn(3, 3)

指定范围内的整数

random_integers = np.random.randint(0, 10, size=(2, 4)) # [0, 10) 之间

从给定序列中随机选择

choices = np.random.choice([‘apple’, ‘banana’, ‘cherry’], size=5, replace=True)
“`

3.3 与其他库的集成

NumPy 是 Python 数据科学生态系统的基石,与 Pandas、Matplotlib、Scikit-learn 等库无缝集成。

  • Pandas:Pandas 的 DataFrame 和 Series 对象内部基于 NumPy 数组构建。
    python
    import pandas as pd
    df = pd.DataFrame(np.random.randint(0, 100, size=(5, 3)), columns=['A', 'B', 'C'])
    print(df)
  • Matplotlib:绘图库通常接受 NumPy 数组作为输入。
    python
    import matplotlib.pyplot as plt
    x = np.linspace(0, 2 * np.pi, 100)
    y = np.sin(x)
    plt.plot(x, y)
    plt.title("Sine Wave")
    plt.show()
  • Scikit-learn:大多数机器学习模型的输入数据都是 NumPy 数组。

3.4 结构化数组与记录数组 (Structured Arrays / Record Arrays)

当您需要存储混合数据类型(例如,名称、年龄、体重)但仍希望利用 NumPy 的高性能时,结构化数组非常有用。

python
data_type = [('name', 'S10'), ('age', 'i4'), ('weight', 'f8')]
people = np.array([("Alice", 25, 65.5), ("Bob", 30, 78.2)], dtype=data_type)
print(people)
print(f"Names: {people['name']}")
print(f"Ages: {people['age']}")

总结

NumPy 不仅仅是一个数值计算库,它更是数据科学家处理、分析和理解数据的强大工具。从基础的数组创建和操作,到高级的广播、索引和线性代数功能,NumPy 为高效的数据处理提供了坚实的基础。

熟练掌握 NumPy,您将能够:
– 以更快的速度处理大规模数据集。
– 编写更简洁、更可读的代码。
– 更好地理解和利用数据科学中各种算法的数学原理。
– 无缝地与 Python 数据科学生态系统中的其他工具协作。

继续实践,探索 NumPy 的每一个角落,它将成为您数据科学旅程中最忠实的伙伴。


滚动至顶部