在上一篇中,我们掌握了 NumPy 的向量化运算和广播机制,这是数值计算的性能核心。而在实际的数据处理场景中,我们还需要解决「统计分析」「排序去重」「缺失值处理」等高频问题 ------ 这些正是本文要讲解的核心内容,也是 NumPy 从「基础运算」走向「实战应用」的关键。
一、统计分析工具:挖掘数据的特征
NumPy 提供了一套完整的统计函数,不仅能计算整体的统计指标,还能按指定轴(行 / 列)计算,满足不同维度的分析需求。
1. 描述性统计函数
除了上篇提到的 sum()/mean()/max()/min(),以下是实战中更常用的描述性统计函数:
python
import numpy as np
# 创建模拟数据(4行3列)
arr = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]])
# 1. 中位数:np.median()
median_all = np.median(arr) # 整个数组的中位数
median_axis0 = np.median(arr, axis=0)# 按列计算中位数
median_axis1 = np.median(arr, axis=1)# 按行计算中位数
# 2. 标准差与方差:np.std() / np.var()
std_all = np.std(arr) # 整体标准差
std_axis1 = np.std(arr, axis=1) # 每行标准差
var_all = np.var(arr) # 整体方差
# 3. 百分位数:np.percentile()(常用25%、50%、75%分位数)
p25 = np.percentile(arr, 25) # 25%分位数
p50 = np.percentile(arr, 50) # 50%分位数(等价于中位数)
p75 = np.percentile(arr, 75) # 75%分位数
p_axis0 = np.percentile(arr, 50, axis=0) # 按列计算50%分位数
# 4. 最值索引:np.argmax() / np.argmin()(返回索引而非值)
argmax_all = np.argmax(arr) # 整体最大值的扁平化索引
argmax_axis0 = np.argmax(arr, axis=0)# 每列最大值的行索引
argmin_axis1 = np.argmin(arr, axis=1)# 每行最小值的列索引
2. 累计统计函数
累计统计函数可以计算「累加」「累乘」等趋势性指标,常用于时序数据或序列分析:
python
arr = np.array([1, 2, 3, 4, 5])
# 1. 累计求和:np.cumsum()
cumsum_arr = np.cumsum(arr) # 逐个累加,结果为[1,3,6,10,15]
# 2. 累计乘积:np.cumprod()
cumprod_arr = np.cumprod(arr) # 逐个累乘,结果为[1,2,6,24,120]
# 3. 二维数组的累计统计(指定轴)
arr2d = np.array([[1,2], [3,4]])
cumsum_axis0 = np.cumsum(arr2d, axis=0) # 按列累计求和
cumsum_axis1 = np.cumsum(arr2d, axis=1) # 按行累计求和
二、排序与去重:整理数据的秩序
数据处理中常需要对数组排序、提取唯一值,NumPy 提供了简洁高效的工具,避免手动写排序逻辑。
1. 数组排序
NumPy 排序分为「原地排序」和「返回新数组排序」,核心区别是是否修改原数组:
python
arr = np.array([3, 1, 4, 1, 5, 9, 2, 6])
arr2d = np.array([[5, 2, 8], [3, 7, 1]])
# 1. np.sort():返回新数组(原数组不变)
sorted_arr = np.sort(arr) # 一维数组升序排序
sorted_axis0 = np.sort(arr2d, axis=0)# 二维数组按列排序
sorted_axis1 = np.sort(arr2d, axis=1)# 二维数组按行排序
sorted_desc = np.sort(arr)[::-1] # 降序排序(升序后反转)
# 2. arr.sort():原地排序(修改原数组)
arr_copy = arr.copy()
arr_copy.sort() # 原数组被修改
# 3. np.argsort():返回排序后的索引(而非值)
argsort_idx = np.argsort(arr) # 升序索引
sorted_by_idx = arr[argsort_idx] # 通过索引得到排序后数组
2. 去重与唯一值
np.unique() 是去重的核心函数,支持返回唯一值、计数、原索引等信息:
python
arr = np.array([2, 1, 3, 2, 1, 3, 4, 2, 5])
arr2d = np.array([[1,2,3], [2,3,4], [1,2,3]])
# 1. 基础去重:返回排序后的唯一值
unique_vals = np.unique(arr) # 一维数组去重
unique_2d = np.unique(arr2d) # 二维数组扁平化后去重
# 2. 返回唯一值的计数:return_counts=True
unique_vals, counts = np.unique(arr, return_counts=True) # 值+对应出现次数
# 3. 返回唯一值的原索引:return_index=True
unique_vals, indices = np.unique(arr, return_index=True) # 值+首次出现的索引
# 4. 判断元素是否在数组中:np.in1d()
mask = np.in1d(arr, [2, 3]) # 标记arr中属于[2,3]的元素
filtered_arr = arr[mask] # 筛选出2和3的元素
三、缺失值与异常值处理:修复数据的瑕疵
实际数据中常存在缺失值(NaN)、无穷值(Inf)等异常,NumPy 提供了专门的检测和处理工具。
1. 缺失值的特性
NumPy 中用 np.nan 表示缺失值,需注意:
- np.nan 是浮点型专属,整数数组中赋值 np.nan 会自动转为浮点型;
- np.nan != np.nan,不能用 == 判断缺失值,必须用 np.isnan()。
python
# 1. 创建含缺失值的数组
arr = np.array([1, 2, np.nan, 4, np.nan, 6], dtype=np.float64)
arr2d = np.array([[1, np.nan, 3], [np.nan, 5, 6]])
# 2. 检测缺失值:np.isnan()
nan_mask = np.isnan(arr) # 标记缺失值位置
non_nan_mask = ~np.isnan(arr) # 标记非缺失值位置
# 3. 检测无穷值:np.isinf()(Inf)
inf_arr = np.array([1, np.inf, -np.inf, 4])
inf_mask = np.isinf(inf_arr) # 标记无穷值位置
# 4. 检测有限值:np.isfinite()(非NaN、非Inf)
finite_mask = np.isfinite(arr) # 标记有限值位置
2. 缺失值的处理
缺失值处理的核心思路是「筛选删除」或「填充替换」:
python
arr = np.array([1, 2, np.nan, 4, np.nan, 6], dtype=np.float64)
arr2d = np.array([[1, np.nan, 3], [np.nan, 5, 6]])
# 1. 筛选删除缺失值(返回一维数组)
non_nan_arr = arr[~np.isnan(arr)] # 仅保留非缺失值
# 2. 填充缺失值:np.where()
filled_arr = np.where(np.isnan(arr), 0, arr) # 缺失值填充为0
filled_mean = np.where(np.isnan(arr), np.nanmean(arr), arr) # 填充为非缺失值的均值
# 3. 按轴填充缺失值(二维数组)
# 按列填充均值
col_means = np.nanmean(arr2d, axis=0)
filled_axis0 = np.where(np.isnan(arr2d), col_means, arr2d)
# 按行填充中位数
row_medians = np.nanmedian(arr2d, axis=1).reshape(-1, 1) # 重塑维度以匹配广播
filled_axis1 = np.where(np.isnan(arr2d), row_medians, arr2d)
四、其他高频工具:解决场景化需求
除了上述核心工具,以下函数在实战中也频繁用到,能大幅简化代码:
1. 重复数组:np.repeat () /np.tile ()
两者都能重复数组,但逻辑不同:
- np.repeat():按元素重复(每个元素重复指定次数);
- np.tile():按整体重复(数组作为整体重复指定次数)。
python
arr = np.array([1, 2, 3])
# 1. np.repeat():元素级重复
repeat_2 = np.repeat(arr, 2) # 每个元素重复2次:[1,1,2,2,3,3]
repeat_axis0 = np.repeat(arr.reshape(3,1), 2, axis=0) # 按行重复
# 2. np.tile():整体级重复
tile_2 = np.tile(arr, 2) # 数组整体重复2次:[1,2,3,1,2,3]
tile_2d = np.tile(arr.reshape(3,1), (2, 3)) # 二维重复:2行3列
2. 条件替换:np.where () /np.select ()
np.where() 适合单条件替换,np.select() 适合多条件替换:
python
arr = np.array([1, 2, 3, 4, 5, 6])
# 1. np.where():单条件
replace_1 = np.where(arr < 3, 0, arr) # 小于3替换为0,否则保留原值
replace_2 = np.where(arr % 2 == 0, 'even', 'odd') # 偶数标even,奇数标odd
# 2. np.select():多条件
conditions = [arr < 2, arr < 5, arr >=5]
choices = ['small', 'medium', 'large']
replace_multi = np.select(conditions, choices) # 按条件匹配替换值
3. 数组比较:np.all () /np.any ()
用于判断数组元素是否满足条件,返回布尔值:
python
arr = np.array([1, 2, 3, 4])
arr2d = np.array([[True, False], [True, True]])
# 1. np.any():任意一个元素满足条件则为True
any_true = np.any(arr2d) # 是否有任意True
any_gt3 = np.any(arr > 3) # 是否有元素大于3
# 2. np.all():所有元素满足条件则为True
all_true = np.all(arr2d) # 是否全为True
all_lt5 = np.all(arr < 5) # 是否所有元素小于5
# 3. 按轴判断
any_axis0 = np.any(arr2d, axis=0) # 按列判断是否有True
all_axis1 = np.all(arr2d, axis=1) # 按行判断是否全为True
五、小结
- 统计工具:除基础统计量外,np.percentile()(分位数)、np.cumsum()(累计求和)是实战高频函数,axis 参数控制计算维度;
- 排序去重:np.sort() 返回新数组,arr.sort() 原地排序,np.unique() 支持去重 + 计数,是数据整理的核心;
- 缺失值处理:用 np.isnan() 检测缺失值,避免直接用 == 判断,填充方式优先选「均值 / 中位数」或业务指定值;
- 场景化工具:np.repeat()/np.tile() 处理数组重复,np.select() 实现多条件替换,np.all()/np.any() 批量判断条件。
下一篇预告:《NumPy 实战:从基础到场景化应用》------ 我们将整合前五篇的所有知识点,落地到数值模拟、数据标准化、图像处理、线性回归等实战场景,让你真正掌握 NumPy 的应用能力。