Skip to content

NumPy 面试题

1. NumPy 基础

问题:什么是 NumPy?它有什么优势?

答案

NumPy 是 Python 科学计算的基础库,提供高性能的多维数组对象和工具。

主要优势

  • 高性能:基于 C 实现,比 Python 列表快 10-100 倍
  • 内存效率:数组存储紧凑,占用内存少
  • 向量化操作:无需循环即可对整个数组进行操作
  • 广播机制:不同形状数组间的运算
  • 丰富的数学函数库
python
import numpy as np

# 创建数组
a = np.array([1, 2, 3, 4, 5])
b = np.array([[1, 2, 3], [4, 5, 6]])

# 特殊数组
np.zeros((3, 4))          # 全零数组
np.ones((2, 3))           # 全一数组
np.eye(3)                 # 单位矩阵
np.arange(0, 10, 2)       # 等差数组 [0, 2, 4, 6, 8]
np.linspace(0, 1, 5)      # 等间隔数组 [0, 0.25, 0.5, 0.75, 1]
np.random.rand(3, 3)      # 随机数组

2. 数组操作

问题:NumPy 数组有哪些常用操作?

答案

python
import numpy as np

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

# 1. 索引和切片
arr[0, 1]           # 2
arr[0:2, 1:3]       # [[2, 3], [5, 6]]
arr[:, 1]           # [2, 5, 8](第二列)
arr[1, :]           # [4, 5, 6](第二行)

# 2. 形状操作
arr.shape           # (3, 3)
arr.reshape(1, 9)   #  reshape 为 1x9
arr.flatten()       # 展平为一维
arr.T               # 转置

# 3. 数组拼接
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])

np.vstack((a, b))   # 垂直拼接
np.hstack((a, b.T)) # 水平拼接
np.concatenate([a, b], axis=0)  # 指定轴拼接

# 4. 数组分割
np.split(arr, 3)    # 分割为3份
np.vsplit(arr, 3)   # 垂直分割
np.hsplit(arr, 3)   # 水平分割

# 5. 条件筛选
arr[arr > 5]        # [6, 7, 8, 9]
arr[(arr > 3) & (arr < 7)]  # [4, 5, 6]
np.where(arr > 5, arr, 0)   # 大于5保留,否则置0

# 6. 去重和排序
np.unique(arr)      # 去重
np.sort(arr)        # 排序
np.argsort(arr)     # 返回排序索引

3. 数学运算

问题:NumPy 支持哪些数学运算?

答案

python
import numpy as np

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

# 1. 基本运算
a + b               # [5, 7, 9]
a - b               # [-3, -3, -3]
a * b               # [4, 10, 18](元素乘法)
a / b               # [0.25, 0.4, 0.5]
a ** 2              # [1, 4, 9]

# 2. 矩阵运算
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

np.dot(A, B)        # 矩阵乘法
A @ B               # 矩阵乘法(Python 3.5+)
np.linalg.inv(A)    # 逆矩阵
np.linalg.det(A)    # 行列式
np.linalg.eig(A)    # 特征值和特征向量

# 3. 统计运算
arr = np.array([[1, 2, 3], [4, 5, 6]])

np.sum(arr)         # 21
np.sum(arr, axis=0) # [5, 7, 9](按列求和)
np.sum(arr, axis=1) # [6, 15](按行求和)

np.mean(arr)        # 平均值
np.std(arr)         # 标准差
np.var(arr)         # 方差
np.min(arr)         # 最小值
np.max(arr)         # 最大值
np.argmin(arr)      # 最小值索引
np.argmax(arr)      # 最大值索引

# 4. 广播机制
a = np.array([[1, 2, 3], [4, 5, 6]])  # shape: (2, 3)
b = np.array([10, 20, 30])             # shape: (3,)

a + b  # b 被广播为 [[10, 20, 30], [10, 20, 30]]
# 结果: [[11, 22, 33], [14, 25, 36]]

# 5. 数学函数
np.sin(arr)         # 正弦
np.cos(arr)         # 余弦
np.exp(arr)         # 指数
np.log(arr)         # 对数
np.sqrt(arr)        # 平方根
np.power(arr, 2)    # 幂运算

4. 广播机制

问题:什么是 NumPy 的广播机制?

答案

广播是 NumPy 中不同形状数组进行算术运算的机制。它通过扩展数组的维度来匹配形状,而无需实际复制数据。

广播规则

  1. 如果两个数组维度不同,将形状较小的数组在前面补1
  2. 如果两个数组在某个维度上的大小相等,或其中一个为1,则可以广播
  3. 如果两个数组在所有维度上都满足条件,则可以广播
python
import numpy as np

# 示例1:标量广播
a = np.array([1, 2, 3])
a + 10  # [11, 12, 13],标量10被广播为[10, 10, 10]

# 示例2:一维数组广播到二维
a = np.array([[1, 2, 3],    # shape: (2, 3)
              [4, 5, 6]])
b = np.array([10, 20, 30])  # shape: (3,)

a + b  # b 被广播为 [[10, 20, 30], [10, 20, 30]]

# 示例3:列向量广播
c = np.array([[10],          # shape: (2, 1)
              [20]])

a + c  # c 被广播为 [[10, 10, 10], [20, 20, 20]]

# 示例4:不兼容的形状
# a: (3, 2)
# b: (3, 3)  # 无法广播

# 显式扩展维度
a = np.array([1, 2, 3])         # shape: (3,)
a[:, np.newaxis]                # shape: (3, 1)
np.expand_dims(a, axis=1)       # shape: (3, 1)
a.reshape(-1, 1)                # shape: (3, 1)

5. 性能优化

问题:如何优化 NumPy 代码的性能?

答案

python
import numpy as np

# 1. 向量化操作(避免循环)
# 慢:使用循环
result = []
for i in range(1000):
    result.append(i ** 2)

# 快:向量化
result = np.arange(1000) ** 2

# 2. 预分配内存
# 慢:动态扩展
result = []
for i in range(10000):
    result.append(i)

# 快:预分配
result = np.empty(10000)
for i in range(10000):
    result[i] = i

# 3. 使用视图而非复制
arr = np.array([[1, 2, 3], [4, 5, 6]])

view = arr[0, :]      # 视图,不复制数据
copy = arr[0, :].copy()  # 复制数据

# 4. 广播优于重复
# 慢:使用 tile
a = np.array([1, 2, 3])
b = np.tile(a, (1000, 1))  # 复制数据
result = b + 1

# 快:使用广播
result = a + 1  # 广播,不复制

# 5. 使用 NumPy 函数而非 Python 函数
arr = np.random.rand(1000000)

# 慢:Python 函数
result = np.array([np.sin(x) for x in arr])

# 快:NumPy 函数
result = np.sin(arr)

# 6. 内存布局
# C-order(行优先)vs F-order(列优先)
arr_c = np.array([[1, 2], [3, 4]], order='C')
arr_f = np.array([[1, 2], [3, 4]], order='F')

# 按行操作时 C-order 更快
# 按列操作时 F-order 更快

# 7. 使用 numba 加速
from numba import jit

@jit(nopython=True)
def fast_function(arr):
    result = np.empty_like(arr)
    for i in range(len(arr)):
        result[i] = arr[i] ** 2
    return result