Spark UDF执行报错:TypeError: 'float' object is not subscriptable 问题排查求助
嘿,这个问题我太熟了!咱们先把问题根源理清楚,再给你解决办法:
问题原因
你遇到的TypeError: 'float' object is not subscriptable,本质是PySpark UDF和Pandas的apply函数传参逻辑完全不一样:
- 在Pandas里,你用
df.apply(discount_udf, axis=1)时,axis=1会把每一行打包成一个Series对象传给UDF,所以你用row['total_order']去取列值是完全没问题的。 - 但在PySpark里,你写的
discount_udf(F.col('total_order'))是把total_order这一列的单个值(这里是float类型)传给UDF,而不是整行数据!这时候函数里的row其实就是一个普通的float数字,你再用row['total_order']去下标访问,自然就会报错——总不能对一个数字用字典下标吧?
解决办法
根据你的需求,最直接的方案是修改UDF,让它直接接收单个列值(因为你只用到了total_order这一列):
from pyspark.sql import functions as F from pyspark.sql.functions import udf @udf("double") def discount_udf(total_order): # 把一堆or的条件改成区间判断,代码更简洁易读 if total_order in (2, 3): return 2.50 elif total_order in (4, 5): return 1.20 elif total_order in (6, 7): return 0.60 elif 8 <= total_order <= 11: return 0.00 elif 12 <= total_order <= 23: return -0.20 elif 24 <= total_order <= 31: return -0.40 else: return -0.50 # 调用时直接传入total_order列即可 df = df.withColumn("discount_rate", discount_udf(F.col('total_order')))
如果之后你的逻辑需要用到多列(比如要结合其他字段计算折扣),那可以改成接收整行的UDF,调用时传入整行:
from pyspark.sql.types import StructType, StructField, IntegerType # 先定义你的DataFrame结构(根据实际列调整) df_schema = StructType([ StructField("total_order", IntegerType(), nullable=True) # 其他列按需添加 ]) @udf("double") def discount_udf(row): total_order = row['total_order'] # 下面的逻辑和上面一致... # 调用时传入整个DataFrame(或者用F.struct指定需要的列) df = df.withColumn("discount_rate", discount_udf(df))
额外小建议
你原来的代码里重复导入了udf(先装饰器用了@udf,后面又from pyspark.sql.functions import udf),其实只需要导入一次就行,避免冗余。
内容的提问来源于stack exchange,提问作者user3459293
相关产品推荐
相关产品推荐

