如何在数据框中的列上创建分档

时间:2017-04-26 07:11:57

标签: scala apache-spark

我有一个结构如下的数据框df:

输入

amount id
13000  1
30000  2
10000  3
5000   4

我想创建一个新列,该列基于列'amount'的分位数

预期输出:

amount id amount_bin
13000  1  10000
30000  2  15000
10000  3  10000
5000   4  5000

假设品质0.25,0.5和0.75分别为5000,10000和15000

我知道如何在R中执行此操作:

quantile <- quantile(df$amount, probs = c(0, 0.25, 0.50, 0.75, 1.0), na.rm = TRUE, 
                     names = FALSE)

df$amount_bin <- cut(df$amount, breaks = quantile, include.lowest = TRUE, 
                     labels = c(quantile[2], quantile[3], quantile[4], quantile[5]))

2 个答案:

答案 0 :(得分:6)

您可以使用ML库中的QuantileDiscretizer

根据拟合的分位数创建存储桶:

import org.apache.spark.ml.feature.QuantileDiscretizer

val data = Array((13000, 1), (30000, 2), (10000, 3), (5000, 4))
val df = spark.createDataFrame(data).toDF("amount", "id")

val discretizer = new QuantileDiscretizer()
  .setInputCol("amount")
  .setOutputCol("result")
  .setNumBuckets(4)

val result = discretizer.fit(df).transform(df)
result.show()

答案 1 :(得分:5)

如果您的数据整齐分布,则QuantileDiscretizer可以确定,但是当您指定numBuckets 时,它不会将列中的值范围拆分为相同大小的容器,而是通过某些启发式即可。你也无法选择垃圾箱的边界。

来自Spark ML的Bucketizer确实具有以下功能:

import org.apache.spark.ml.feature.Bucketizer

val data = Array(0.99, 0.64, 0.39, 0.44, 0.15, 0.05, 0.30, 0.31, 0.22, 0.45, 0.52, 0.26)
val df = spark.createDataFrame(data.map(Tuple1.apply)).toDF("continuousFeature")

val bucketizer = new Bucketizer()
    .setInputCol("continuousFeature")
    .setOutputCol("discretizedFeature")
    .setSplits( Array(0.0, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.0 ) )

    // the array of split values are the binning boundaries

val binnedData = bucketizer.transform(df)

binnedData.show

+-----------------+------------------+
|continuousFeature|discretizedFeature|
+-----------------+------------------+
|             0.99|               9.0|
|             0.64|               6.0|
|             0.39|               3.0|
|             0.44|               4.0|
|             0.15|               1.0|
|             0.05|               0.0|
|              0.3|               3.0|
|             0.31|               3.0|
|             0.22|               2.0|
|             0.45|               4.0|
|             0.52|               5.0|
|             0.26|               2.0|
+-----------------+------------------+

我觉得哪个更好。让您更好地控制结果。

请注意,拆分范围需要包含输入列中的所有值,否则您必须使用 setHandleInvalid 方法设置处理无效输入值的规则。

您不需要像我在此示例中那样指定有规律间隔的二进制位。

<强> Scaladoc https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.ml.feature.Bucketizer

另一个例子 https://github.com/apache/spark/blob/master/examples/src/main/scala/org/apache/spark/examples/ml/BucketizerExample.scala