Pandas高效将每行数值列前导0值转为numpy.nan的方法
Pandas 高效实现行首连续0值转NaN
需求梳理
- 目标DataFrame结构如下,包含2个文本列
thing1/thing2,以及4个数值列num_col1到num_col4:
thing1 thing2 num_col1 num_col2 num_col3 num_col4 aaa abc 0.0 99.76 101.1 111.2 bbb cde 11.3 109.76 201.1 121.2 ccc def 91.3 0.0 301.1 131.2 ... aaa efg 0.0 0.0 401.1 141.2 bbb fgh 41.3 299.76 0.0 151.2 ccc ghi 201.3 199.76 601.1 161.2
- 处理规则:仅对4个数值列操作,每行从最左侧数值列开始连续出现的0值替换为
numpy.nan,出现在非0值之后的0(不管在列序列中间还是末尾)全部保留,预期处理结果如下:
thing1 thing2 num_col1 num_col2 num_col3 num_col4 aaa abc nan 99.76 101.1 111.2 bbb cde 11.3 109.76 201.1 121.2 ccc def 91.3 0.0 301.1 131.2 ... aaa efg nan nan 401.1 141.2 bbb fgh 41.3 299.76 0.0 151.2 ccc ghi 201.3 199.76 601.1 161.2
- 实现要求:优先使用pandas内置向量化方法,避免Python原生循环、逐行apply等低效写法,保证大数据量下的执行性能。
实现代码
import numpy as np import pandas as pd # 指定需要处理的数值列 num_cols = ["num_col1", "num_col2", "num_col3", "num_col4"] num_subset = df[num_cols] # 生成替换掩码:逐行从左到右找第一个非0值,标记其左侧所有位置 replace_mask = (num_subset != 0).cumsum(axis=1) == 0 # 执行替换 df.loc[:, num_cols] = num_subset.mask(replace_mask, np.nan)
逻辑说明
- 整个实现全程为pandas底层C实现的向量化运算,无Python层面的循环操作,性能比逐行遍历、
apply写法高1~2个数量级,可直接支撑百万级以上行的数据处理。 - 核心判断逻辑拆解:
num_subset != 0生成和数值子集同形状的布尔矩阵,值为0的位置返回False,非0位置返回True- 沿行方向(
axis=1,即从左到右)做累计求和cumsum()时,每行第一个非0值出现之前,累计和始终为0;第一个非0值出现后,累计和永远大于等于1,不会再回落为0 - 累计和为0的位置恰好就是每行开头连续为0的位置,用
mask()方法将这些位置替换为np.nan即可。非0值之后出现的0因为累计和已经大于0,不会被误替换,完全匹配规则要求。
样例验证:
ccc def行的num_col2值为0,但左侧num_col1值为91.3(非0),累计和在num_col1位置已经为1,因此这个中间位置的0会被保留;aaa efg行前两列都是0,第三列才出现非0值,因此前两列的0会被替换为nan,和预期结果完全一致。
内容的提问来源于stack exchange,提问作者Naveen Reddy Marthala
相关产品推荐
相关产品推荐

