如何对DataFrame所有列使用.apply(lambda x:自定义函数)并解决返回NaN/报错问题
问题诱因
两个异常的核心原因分别如下:
- apply返回NaN的原因:自定义函数存在参数错位问题,你将df的列(大概率是样本强度值)当作波数数组传入函数,函数用这个错误的「波数数组」生成筛选mask,最终筛选全局变量
Zhangfit_output得到的是空数组,np.max运算空数组会直接返回NaN。另外你在函数内固定用全局变量Zhangfit_output作为强度数组,也不符合遍历df每一列计算的需求,相当于所有列的计算都用了同一个强度数据源,逻辑本身就存在错误。 - applymap报错的原因:
applymap是遍历DataFrame的单个元素而非整列/整行,你传入函数的x是单个数值,生成的mask是单个布尔值,筛选数组后得到空数组,np.max无法对空数组执行运算,就抛出zero-size array to reduction operation maximum的错误。
解决方法
首先确认你的DataFrame结构:光谱类数据通常是行索引为波数,每一列对应一个样本的强度值,如果你的数据结构符合该规则,可以按下方步骤修改:
- 修正自定义函数,把强度数组、波数数组都作为入参,同时增加空数组判断避免报错:
import numpy as np def snr_pd(intensity_arr, wavenumber_arr): signal_low = 1650 signal_high = 1750 noise_low = 1750 noise_high = 1850 signal_mask = np.logical_and(wavenumber_arr >= signal_low, wavenumber_arr < signal_high) noise_mask = np.logical_and(wavenumber_arr >= noise_low, wavenumber_arr < noise_high) # 空值判断,避免无匹配范围时抛出异常 if intensity_arr[signal_mask].size == 0 or intensity_arr[noise_mask].size == 0: return np.nan signal = np.max(intensity_arr[signal_mask]) noise = np.std(intensity_arr[noise_mask]) return signal / noise
- 修改apply调用逻辑,把df的行索引(波数)作为固定参数传入,按列遍历每一个样本的强度数组计算:
# 提取波数数组 wavenumber_arr = df.index.values # 按列遍历计算信噪比 sd['s/n'] = df.apply(lambda x: snr_pd(x, wavenumber_arr), axis=0)
如果你的DataFrame结构是「列是波数,每一行对应一个样本的强度值」,只需要把apply的axis=0改成axis=1,同时把wavenumber_arr替换为df的列名数组即可:
wavenumber_arr = df.columns.values sd['s/n'] = df.apply(lambda x: snr_pd(x, wavenumber_arr), axis=1)
额外注意事项
- 提前检查你的波数范围,确认16501750、17501850两个区间内存在对应波数,否则符合条件的筛选结果为空,依旧会返回NaN。
- 不要在自定义函数内使用全局变量传递核心计算数据,全局变量的取值容易和预期不符,建议都通过参数传递。
内容的提问来源于stack exchange,提问作者Niall Doherty
相关产品推荐
相关产品推荐

