Scala Spark如何将0-1连续列划分为指定规则的等大小分桶?
解决方案
你需要的是等宽度分桶,而QuantileDiscretizer是按分位数(保证每个桶样本数近似均等)分桶,这就是你得到的桶大小(区间宽度)不等的核心原因——你的数据集中在0.9-1区间,分位数分桶会为了平衡各桶样本量,把密集区间拆得更细,自然不符合你要的等宽需求。
要实现你的分桶规则,应该用Bucketizer手动指定等宽分割点,具体步骤如下:
步骤1:定义等宽分割点
按照你的规则,分割点需要覆盖:
- 0值单独一个桶
- 0<值<1的部分平分为8个等宽桶(每个桶宽度为
(1-0)/8=0.125) - 1值单独一个桶
最终的分割点序列为:
splits = [-float("inf"), 0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0, float("inf")]
步骤2:用Bucketizer执行分桶
假设你的DataFrame名为df,目标列名为value,代码如下:
from pyspark.ml.feature import Bucketizer from pyspark.sql.functions import col # 初始化Bucketizer bucketizer = Bucketizer( splits=splits, inputCol="value", outputCol="bucket_index" ) # 执行分桶 df_bucketed = bucketizer.transform(df) # 将索引转换为桶编号(索引从0开始,加1得到你需要的桶1-10) df_bucketed = df_bucketed.withColumn("bucket_number", col("bucket_index") + 1)
分桶对应关系
bucket_number=1:所有0值bucket_number=2:(0, 0.125]bucket_number=3:(0.125, 0.25]- ...
bucket_number=9:(0.875, 1.0)bucket_number=10:所有1值
注意事项
- 浮点数精度问题:如果数据中存在刚好等于分割点(如0.125)的数值,会被分到右侧的桶中(Bucketizer默认左开右闭,第一个区间除外),这符合你的分桶逻辑。
- 如果数据中存在小于0或大于1的异常值,会被分到
bucket_number=1或bucket_number=10,若需单独处理可调整分割点。
内容的提问来源于stack exchange,提问作者ek11222
相关产品推荐
相关产品推荐

