Appearance
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,则可以广播
- 如果两个数组在所有维度上都满足条件,则可以广播
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