跳到主要内容

NumPy 核心操作

问题

NumPy 是什么?ndarray 和 Python 列表有什么区别?什么是广播机制?

答案

NumPy 是 Python 科学计算的基石,Pandas 的底层就是 NumPy。数据分析师主要掌握数组创建、向量化运算和广播机制即可。

ndarray vs Python list

对比Python listNumPy ndarray
类型可混合类型同一类型
性能慢(Python 循环)快(C 底层运算)
内存大(每个元素是对象)小(连续内存)
运算不支持向量化支持向量化
维度一维嵌套多维数组
性能对比
import numpy as np

# Python list 遍历求和
python_list = list(range(1000000))
result = sum(python_list) # ~50ms

# NumPy 向量化求和
np_array = np.arange(1000000)
result = np_array.sum() # ~1ms,快 50 倍

数组创建

创建 ndarray
import numpy as np

# 从列表创建
arr = np.array([1, 2, 3, 4])
arr_2d = np.array([[1, 2], [3, 4]]) # 二维

# 快捷创建
np.zeros((3, 4)) # 3x4 全零矩阵
np.ones((2, 3)) # 2x3 全一矩阵
np.full((2, 3), 7) # 2x3 全 7
np.eye(3) # 3x3 单位矩阵
np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1.0]

# 随机数
np.random.rand(3, 4) # 均匀分布 [0, 1)
np.random.randn(3, 4) # 标准正态分布
np.random.randint(1, 100, size=(3, 4)) # 随机整数
np.random.seed(42) # 设置随机种子(可复现)

向量化运算

向量化运算
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])

# 逐元素运算(无需循环)
a + b # [11, 22, 33, 44]
a * b # [10, 40, 90, 160]
a ** 2 # [1, 4, 9, 16]
a > 2 # [False, False, True, True]

# 聚合函数
a.sum() # 10
a.mean() # 2.5
a.std() # 1.118
a.min() # 1
a.max() # 4
a.argmax() # 3(最大值的索引)
np.median(a) # 2.5

广播机制 (Broadcasting)

广播是 NumPy 最重要的概念之一,让不同形状的数组可以一起运算:

广播示例
# 标量广播
arr = np.array([1, 2, 3])
arr * 10 # [10, 20, 30] —— 标量 10 "广播"到每个元素

# 一维 + 二维
matrix = np.array([[1, 2, 3], [4, 5, 6]]) # shape (2, 3)
row = np.array([10, 20, 30]) # shape (3,)
matrix + row # [[11, 22, 33], [14, 25, 36]] —— row 广播到每一行
广播规则
  1. 右侧开始逐维度对齐
  2. 维度相等,或其中一个为 1,则可广播
  3. 不满足则报错 ValueError

条件操作

条件操作(对应 Pandas 的 np.where/np.select)
scores = np.array([85, 92, 67, 45, 78])

# np.where(二选一)
np.where(scores >= 60, '及格', '不及格')

# np.select(多条件)
conditions = [scores >= 90, scores >= 60]
choices = ['优秀', '及格']
np.select(conditions, choices, default='不及格')
# ['及格', '优秀', '及格', '不及格', '及格']

# 布尔索引
scores[scores >= 80] # [85, 92]

在 Pandas 中的常见应用

NumPy 在 Pandas 中的应用
import pandas as pd
import numpy as np

df = pd.DataFrame({'score': [85, 92, 67, 45], 'name': ['A', 'B', 'C', 'D']})

# 条件赋值
df['level'] = np.where(df['score'] >= 60, 'Pass', 'Fail')

# 多条件赋值
conditions = [df['score'] >= 90, df['score'] >= 70, df['score'] >= 60]
choices = ['A', 'B', 'C']
df['grade'] = np.select(conditions, choices, default='D')

# 对数/指数变换(处理偏态数据)
df['log_score'] = np.log1p(df['score'])

# 百分位截断
lower = np.percentile(df['score'], 5)
upper = np.percentile(df['score'], 95)
df['score_clipped'] = np.clip(df['score'], lower, upper)

常见面试问题

Q1: NumPy 为什么比 Python list 快?

答案

  1. 连续内存:ndarray 元素类型相同,在内存中连续存储,CPU 缓存命中率高
  2. C 底层实现:运算在 C/Fortran 层面批量执行,跳过 Python 解释器开销
  3. 向量化:利用 CPU SIMD 指令并行处理多个元素
  4. 无装箱:Python list 每个元素是 Python 对象(有类型信息开销),ndarray 直接存储裸数据

Q2: 数据分析师需要掌握 NumPy 到什么程度?

答案

  • 必须掌握np.wherenp.select(条件赋值)、聚合函数、随机数
  • 了解即可:广播机制、reshape、矩阵运算
  • 无需深入:线性代数、傅里叶变换等(除非做机器学习)
  • 日常以 Pandas 为主,NumPy 是补充

Q3: np.nan 注意事项?

答案

  • np.nan 是 float 类型,整数列有 NaN 会自动转为 float
  • np.nan != np.nan 为 True(NaN 不等于任何值,包括自身)
  • 比较用 pd.isna()np.isnan(),不要用 ==
  • Pandas 2.0+ 支持 pd.NA(可以在整数列中表示缺失)

相关链接