
本文介绍如何使用 numpy 与 pandas 高效计算具有上三角稀疏结构的 dataframe 中每条“斜对角线”(即按行偏移对齐的元素)的非空值平均值,适用于时间序列、状态转移或递推型数据建模场景。
本文介绍如何使用 numpy 与 pandas 高效计算具有上三角稀疏结构的 dataframe 中每条“斜对角线”(即按行偏移对齐的元素)的非空值平均值,适用于时间序列、状态转移或递推型数据建模场景。
在实际数据分析中,常遇到类似“半对角线填充”的表格结构:数据沿主对角线下方呈阶梯状分布(如示例中 SP=0 对应第 1–18 列均有有效值,SP=1 从第 2 列开始,依此类推),目标是为每一行提取其对应的对角线元素(即列索引 = 原始列号 + 行号偏移),并计算这些元素的平均值(自动忽略 NaN)。
Pandas 本身不提供直接的“对角线切片”聚合方法,但可通过底层 NumPy 操作高效实现。核心思路是:将每行的有效对角线元素“左对齐”,再按列求均值。具体分两步:
✅ 步骤一:提取数值区域并转为 NumPy 数组
跳过前 3 列(SP, State, Year),仅处理从第 4 列开始的数值部分:
import pandas as pd import numpy as np # 构建原始 DataFrame(略,见问题数据) a = df.iloc[:, 3:].to_numpy() # shape: (18, 18)
✅ 步骤二:左对齐有效元素并按列求平均
由于 NaN 全部位于下三角(即每行末尾),可利用 np.argsort 将 NaN 排至右侧,再用 np.take_along_axis 重排每行:
# 方法1:适用于 NaN 仅出现在行尾(标准上三角结构)
df['diag_avg'] = np.nanmean(
np.take_along_axis(a, np.argsort(np.isnan(a), axis=1, kind='stable'), axis=1),
axis=0
)该操作等价于对每行执行 row[~np.isnan(row)] 后补零/截断至统一长度,再纵向取平均。
⚠️ 注意:若数据中存在上三角 NaN(即有效值被 NaN 断开),需改用更鲁棒的掩码排序:
# 方法2:兼容任意位置 NaN(推荐用于生产环境) m = ~df.iloc[:, 3:].notna().cummax(axis=1).to_numpy() # True for positions before first NaN in each row df['diag_avg'] = np.nanmean( np.take_along_axis(a, np.argsort(m, axis=1, kind='stable'), axis=1), axis=0 )
? 输出解读
新增列 diag_avg 的第 i 个值,即对应 SP=i 行所代表对角线(D2,E3,...)所有非空数值的算术平均。例如:
- SP=0 行:取 1~18 列全部 18 个值 → 平均 ≈ 18.69
- SP=5 行:取 6~18 列共 13 个值 → 平均 = 15.00(精确值,因该对角线无 NaN)
最终结果可直接用于趋势分析、异常检测或作为特征输入机器学习模型。
✅ 最佳实践建议:
- 始终验证 NaN 分布模式,优先使用方法 2;
- 若后续需保留原始对角线索引,可额外生成 diag_elements 列存储列表;
- 大规模数据时,避免循环 df.apply(lambda x: ...),NumPy 向量化方案性能提升 10×+。

















