PySpark F.when多条件判断赋值异常问题排查与咨询
问题根因
你遇到的异常分两种可能,对应不同的问题:
- 逻辑本身符合或运算规则:你代码里的布尔优先级写法没有语法错误,
|代表或逻辑,只要property_id为空,不管前三个流量指标是什么值(哪怕num_impressions=20000),都会被判定为满足条件赋值1。如果你查到的异常行property_id确实都是空值,那代码运行结果是符合你写的表达式的,只是这个表达式和你实际想要的规则有偏差。 - 数据类型不匹配导致比较错误:如果异常行的
property_id不为空,那基本是数值列的类型问题。如果num_impressions、num_clicks这类指标列是字符串类型(比如读文件时未指定schema,默认将数值读为string),<比较会按字典序执行:字符串比较是逐位对比ASCII码,'20000'的第一位是'2',比'6000'的第一位'6'ASCII码更小,所以'20000' < '6000'会返回True,直接导致阈值判断失效。
修复方案
先执行排查代码定位具体问题:
# 筛选出异常赋值的行,查看字段特征 df.filter(F.col('is_boost') == 1) .filter(F.col('num_impressions') == 20000) .select('num_clicks','num_bookings','num_impressions','property_id') .show()
再根据排查结果选对应修复方式:
- 如果异常行
property_id全为空,说明你实际想要的规则不是“三个流量条件满足 或 property_id为空”,而是“三个流量条件满足 且 property_id为空才标1”,修改条件逻辑即可:
.withColumn('is_boost', F.when( (F.col('num_clicks') < 600) & (F.col('num_bookings') < 2) & (F.col('num_impressions') < 6000) & (F.col('property_id').isNull()) , 1).otherwise(0) ).cache()
如果你确实需要保留“property_id为空就标1,不管流量指标”的规则,那这部分行的赋值是正确的,不需要修改逻辑。
2. 如果异常行property_id不为空,先将指标列转为数值类型再做比较,从根源避免字典序比较的问题:
.withColumn('is_boost', F.when( ((F.col('num_clicks').cast('long') < 600) & (F.col('num_bookings').cast('long') < 2) & (F.col('num_impressions').cast('long') < 6000)) | (F.col('property_id').isNull()) , 1).otherwise(0) ).cache()
建议在数据读入阶段就指定好数值列的类型,避免后续计算反复做类型转换,也能减少隐式类型转换带来的不可预知问题。
内容的提问来源于stack exchange,提问作者omri
相关产品推荐
相关产品推荐

