
本文介绍如何对嵌套列表按列(相同索引位置)聚合计算:先求各列非零元素之和,再除以该列非零元素个数,最终得到每列的非零均值。重点推荐使用 numpy 实现,仅需一行代码即可高效、清晰地完成任务。
本文介绍如何对嵌套列表按列(相同索引位置)聚合计算:先求各列非零元素之和,再除以该列非零元素个数,最终得到每列的非零均值。重点推荐使用 numpy 实现,仅需一行代码即可高效、清晰地完成任务。
在处理矩阵式数据(如多用户评分、传感器多通道时序)时,常需沿列方向(即同一特征/时间点)进行统计——但要求排除零值干扰(例如 0 表示未评分,而非真实评分为 0)。原始循环逻辑错误在于:内层循环遍历了所有行列组合,导致结果被展平为一维长列表,且未按列分组累加。
正确思路是:按列(索引 j)分组,收集所有 data[i][j],过滤掉 0,再求和与计数。手动实现虽可行,但易出错、可读性差;而 NumPy 提供了面向数组的向量化操作,天然支持此类“轴向聚合”。
✅ 推荐方案:NumPy 向量化一行解决
import numpy as np
rating_values = [
[0, 5, -3, 5, 0, 0],
[-3, 0, 1, 0, 5, 0],
[1, 0, 5, 0, -5, 0],
[-3, 0, 3, 0, 0, 5]
]
# 转为 NumPy 数组
x = np.array(rating_values)
# 核心逻辑:列方向求和 ÷ 列方向非零计数
y = np.sum(x, axis=0) / np.sum(x != 0, axis=0)
# 输出结果(自动广播除法,遇分母为0时返回 inf;此处无全零列,故安全)
print(y.round(5).tolist()) # [-1.66667, 5.0, 1.5, 5.0, 0.0, 5.0]
关键解析:
- axis=0 表示沿行方向压缩,即对每一列独立运算;
- np.sum(x, axis=0) → 每列元素总和:[-5, 5, 6, 5, 0, 5];
- x != 0 生成布尔数组,np.sum(..., axis=0) 统计每列 True 个数(即非零数量):[3, 1, 4, 1, 2, 1];
- 向量除法 [-5/3, 5/1, 6/4, 5/1, 0/2, 5/1] → [-1.666..., 5.0, 1.5, 5.0, 0.0, 5.0]。
⚠️ 注意事项与健壮性增强
若数据中存在整列全为零的情况(如某维度无有效观测),np.sum(x != 0, axis=0) 对应位置为 0,直接相除将产生 inf 或 nan。此时建议添加防错处理:
nonzero_counts = np.sum(x != 0, axis=0) # 分母为0的位置设为1(避免除零),结果对应位置设为0 denominator = np.where(nonzero_counts == 0, 1, nonzero_counts) y_safe = np.sum(x, axis=0) / denominator y_safe = np.where(nonzero_counts == 0, 0, y_safe) # 全零列结果置0
? 纯 Python 实现(理解原理,不推荐生产使用)
若因环境限制无法使用 NumPy,可借助 zip(*data) 转置实现列遍历:
average_list = []
for col in zip(*rating_values): # col 是元组:(0,-3,1,-3), (5,0,0,0), ...
nonzeros = [x for x in col if x != 0]
avg = sum(nonzeros) / len(nonzeros) if nonzeros else 0
average_list.append(round(avg, 5))
print(average_list) # [-1.66667, 5.0, 1.5, 5.0, 0.0, 5.0]
总结: 对于结构化二维数据的轴向统计,NumPy 不仅代码简洁、性能优异,更能准确表达“列操作”语义。优先选用 np.sum(arr, axis=0) 与布尔数组计数组合,避免手动嵌套循环导致的逻辑混乱与维度错误。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











