You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何强制PySpark的round函数使用Banker's Rounding(银行家舍入)

PySpark实现银行家舍入的可行方案

PySpark内置的round()函数固定采用HALF_UP(即常说的四舍五入)模式,无法通过参数切换为0.5向最近偶数舍入的银行家舍入规则,且Python原生round()无法直接作用于分布式Column对象,可通过以下方案实现需求:


方案1:使用原生内置bround函数(优先推荐,无性能损耗)

PySpark 2.0及以上版本已经内置了专门实现银行家舍入的bround函数(命名来自banker's round的缩写),该函数由Spark引擎原生实现,会被Catalyst优化器正常优化,执行性能和普通round函数完全一致,是生产环境首选方案。

代码示例

from pyspark.sql.functions import col, bround

# 完成汇率转换计算
df = df.withColumn(new_name, col(old_name) * col('ExchangeRate'))
# 调用bround执行银行家舍入,默认保留0位小数,需要保留指定位数小数时传入第二个参数即可
df = df.select("*", bround(col(new_name)).alias(f"{new_name}_rounded"))

# 例:保留2位小数的写法
# df = df.select("*", bround(col(new_name), 2).alias(f"{new_name}_rounded"))

效果验证

对测试值做舍入的结果完全符合银行家舍入规则:

  • 2.5 → 2
  • 3.5 → 4
  • 2.4 → 2
  • 2.6 → 3

方案2:Pandas UDF封装原生round(仅适用于2.0以下老旧Spark版本)

如果你的Spark版本低于2.0(目前已极少使用),可以通过Pandas UDF封装Python原生的round()方法实现,该方式为向量化执行,性能远高于逐行计算的普通Python UDF,可适配大数据量场景。

代码示例

from pyspark.sql.functions import pandas_udf
import pandas as pd

# 定义银行家舍入UDF,返回值类型可根据需求调整,示例为返回整数类型
@pandas_udf("long")
def banker_round(s: pd.Series) -> pd.Series:
    # 括号内参数为保留的小数位数,和Python原生round参数规则一致
    return s.round(0)

# 使用方式
df = df.withColumn(new_name, col(old_name) * col('ExchangeRate'))
df = df.select("*", banker_round(col(new_name)).alias(f"{new_name}_rounded"))

注意:不要使用普通逐行Python UDF实现该逻辑,在大数据量下会有非常明显的性能瓶颈。


避坑提示

  • 不要尝试直接将Python原生round()函数传入withColumn/select方法,该函数仅能处理本地Python数值,无法识别Spark分布式Column对象,会直接抛出类型错误。
  • bround的参数规则和round完全一致,除了舍入逻辑不同外,不需要做额外的代码适配。

内容的提问来源于stack exchange,提问作者ifrycolorado

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 23:48:24