结果全为nan最常见原因是索引对不上:div默认按索引对齐,而sum()返回标量时若列含非数值、nan或索引不一致,广播失败导致全nan。

用 div 和 sum 计算列占比时,为什么结果全是 NaN?
最常见原因是索引对不上:div 默认按索引对齐,如果调用 sum() 后返回的是标量(比如 df['col'].sum()),而你用它去 div 一整列,Pandas 会尝试广播——但若列有非数值类型、含 NaN 或索引不一致,就容易全变成 NaN。
正确做法是确保除数是标量且参与运算的列为纯数值:
- 先用
pd.to_numeric(df['col'], errors='coerce')清洗数据 - 用
df['col'].sum(skipna=True)显式控制空值处理 - 直接用
/而非div更直观(div主要用于带索引对齐的复杂广播)
示例:
df['pct'] = df['sales'] / df['sales'].sum()
按行求和再计算每列占比:必须用 axis=1 和 sum
想算“每行各字段占该行总和的比例”,关键在指定 axis=1,否则 sum() 默认按列(axis=0)加总,结果维度错配。
div 在这里反而容易出问题——因为 df.sum(axis=1) 返回的是 Series,索引与原 DataFrame 行索引一致,但默认广播方向可能不匹配。稳妥写法是:
- 用
df.div(df.sum(axis=1), axis=0):把行和作为除数,axis=0表示按行索引对齐(即每行用对应的和来除) - 或更直白:
df.apply(lambda x: x / x.sum(), axis=1),适合逻辑简单、数据量不大的场景 - 注意:若某行全为 0 或全
NaN,结果会出现inf或NaN,建议提前用df.replace(0, np.nan)或fillna(0)处理
分组后计算组内占比:别漏掉 groupby 的 transform
想算“每个品类下销量占该品类总销量的比例”,不能直接对原始列 div 分组 sum,因为分组结果长度不匹配。必须用 transform 把聚合结果广播回原形状:
df['pct_in_cat'] = df['sales'].div(df.groupby('category')['sales'].transform('sum'))
要点:
-
transform('sum')返回和原DataFrame等长的Series,索引对齐无压力 - 避免用
agg或apply手动合并,易引发KeyError或长度不一致错误 - 如果分组键含
NaN,groupby默认会丢弃,需加dropna=False保持对齐
输出百分比字符串(如 "72.3%"):别在计算阶段转字符串
占比计算务必保持数值类型,后续格式化才灵活。一旦用 astype(str) + '%' 或 map('{:.1%}'.format) 提前转成字符串,就无法再参与数值运算或排序。
推荐分离计算与展示:
- 计算存为小数:
df['pct'] = df['col'] / df['col'].sum() - 显示时格式化:
df['pct_display'] = df['pct'].map('{:.1%}'.format) - 导出 Excel 时可用
style.format({'pct': '{:.1%}'}),不影响底层数据
如果硬要在计算中嵌入百分比逻辑,至少保留原始数值列——改名或加后缀,别覆盖。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











