Pandas DataFrame如何将正数向上、负数向下舍入为5的倍数
问题说明
现有如下构造的Pandas DataFrame:
data={'A1':[-7.22,-9.432,-0.00111,0.233,17,23,34], 'A2':[-23,-7.2455,-0.00222,0.54,1.345,19,21]} kk=pd.DataFrame(data)
原始打印输出:
A1 A2 0 -7.22000 -23.00000 1 -9.43200 -7.24550 2 -0.00111 -0.00222 3 0.23300 0.54000 4 17.00000 1.34500 5 23.00000 19.00000 6 34.00000 21.00000
需求规则:
- 所有正数向上舍入到最近的5的倍数,例如21舍入后为25而非20
- 所有负数向下舍入到最近的5的倍数,例如-7舍入后为-10而非-5
原有写法运行报错,代码如下:
def roundupdown5(x): if x>=0: return np.ceil(x/5)*5 else: return np.floor(x/5)*5 kk[['A1','A2']].apply(lambda x: roundupdown5(x))
报错原因
apply默认按列方向执行运算,传入自定义函数的参数是整列的Series对象,直接对Series做if x>=0判断会触发Pandas的真值歧义错误——Pandas无法判断你是要判断整列全为正、还是存在正值,没法返回单个布尔值给if判断,因此报错。
正确实现方案
方案1:向量化运算(优先推荐,性能最高)
Pandas/Numpy的向量化运算不需要逐行/逐列循环,处理大数据量时效率远高于apply类遍历写法,直接通过掩码做分支判断即可:
import pandas as pd import numpy as np # 构造原始数据 data={'A1':[-7.22,-9.432,-0.00111,0.233,17,23,34], 'A2':[-23,-7.2455,-0.00222,0.54,1.345,19,21]} kk=pd.DataFrame(data) # 生成正负值掩码 positive_mask = kk >= 0 # 按规则计算舍入结果 result = pd.DataFrame( np.where( positive_mask, np.ceil(kk / 5) * 5, np.floor(kk / 5) * 5 ), columns=kk.columns, index=kk.index ) print(result)
运行输出结果完全符合规则:
A1 A2 0 -10.0 -25.0 1 -10.0 -10.0 2 -5.0 -5.0 3 5.0 5.0 4 20.0 5.0 5 25.0 20.0 6 35.0 25.0
方案2:修正apply传参逻辑
如果要沿用自定义函数的写法,需要把传参模式改成逐元素传入,使用applymap实现逐元素运算即可:
def roundupdown5(x): if x>=0: return np.ceil(x/5)*5 else: return np.floor(x/5)*5 result = kk[['A1','A2']].applymap(roundupdown5)
注意:applymap是逐元素遍历实现,数据量较大时性能会明显差于向量化方案,非必要不优先使用。
内容的提问来源于stack exchange,提问作者Win Yen Tham
相关产品推荐
相关产品推荐

