Spark ML中的特征转换算法(三)

一、VectorAssembler

VectorAssembler 是一个转换器,它将给定的列列表组合成单个向量列。 它对于将原始特征和不同特征转换器生成的特征组合成单个特征向量很有用,以便训练 ML 模型,如逻辑回归和决策树。 VectorAssembler 接受以下输入列类型:所有数字类型、布尔类型和向量类型。 在每一行中,输入列的值将按指定顺序连接成一个向量。

%spark
// 特征转换 —— —— VectorAssembler
// 将多列合并为向量列的特征转换器。
// 这需要遍历整个数据集。 如果我们需要从数据中推断列长度,我们需要额外调用“first”Dataset 方法
import org.apache.spark.ml.feature.VectorAssembler
import org.apache.spark.ml.linalg.Vectors

val dataset = spark.createDataFrame(
  Seq((0, 18, 1.0, Vectors.dense(0.0, 10.0, 0.5), 1.0))
).toDF("id", "hour", "mobile", "userFeatures", "clicked")

val assembler = new VectorAssembler()
  .setInputCols(Array("hour", "mobile", "userFeatures"))
  .setOutputCol("features")

val output = assembler.transform(dataset)
println("Assembled columns 'hour', 'mobile', 'userFeatures' to vector column 'features'")
output.select("features", "clicked").show(false)

输出:
Assembled columns 'hour', 'mobile', 'userFeatures' to vector column 'features'
+-----------------------+-------+
|features               |clicked|
+-----------------------+-------+
|[18.0,1.0,0.0,10.0,0.5]|1.0    |
+-----------------------+-------+

 

二、VectorSizeHint

  有时显式指定 VectorType 列的向量大小会很有用。例如,VectorAssembler 使用来自其输入列的大小信息为其输出列生成大小信息和元数据。虽然在某些情况下可以通过检查列的内容来获取此信息,但在流数据帧中,内容在流启动之前不可用。 VectorSizeHint 允许用户显式指定列的向量大小,以便 VectorAssembler 或其他可能需要知道向量大小的转换器可以使用该列作为输入。

  要使用 VectorSizeHint,用户必须设置 inputCol 和 size 参数。将此转换器应用于数据帧会生成一个新的数据帧,其中包含用于指定向量大小的 inputCol 的更新元数据。对结果数据帧的下游操作可以使用元数据获得这个大小。

  VectorSizeHint 还可以采用可选的 handleInvalid 参数,当向量列包含空值或大小错误的向量时,该参数控制其行为。默认情况下,handleInvalid 设置为“error”,表示应该抛出异常。此参数也可以设置为“skip”,表示应从结果数据帧中过滤掉包含无效值的行,或“optimistic”,表示不应检查列的无效值,应保留所有行。请注意,使用“optimistic”可能会导致生成的数据帧处于不一致状态,这意味着 VectorSizeHint 应用于列的元数据与该列的内容不匹配。用户应注意避免这种不一致的状态。

%spark
// 特征转换 —— —— VectorSizeHint
// 将大小信息添加到向量列的元数据的特征转换器。 VectorAssembler需要其输入列的大小信息,并且不能在没有此元数据的流数据帧上使用。
// 注意:VectorSizeHint 修改 inputCol 以包含大小元数据,并且没有 outputCol。
import org.apache.spark.ml.feature.{VectorAssembler, VectorSizeHint}
import org.apache.spark.ml.linalg.Vectors

val dataset = spark.createDataFrame(
  Seq(
    (0, 18, 1.0, Vectors.dense(0.0, 10.0, 0.5), 1.0),
    (0, 18, 1.0, Vectors.dense(0.0, 10.0), 0.0))
).toDF("id", "hour", "mobile", "userFeatures", "clicked")

val sizeHint = new VectorSizeHint()
  .setInputCol("userFeatures")
  .setHandleInvalid("skip")
//   inputCol 中向量的大小。 
  .setSize(3)

val datasetWithSize = sizeHint.transform(dataset)
println("过滤掉“userFeatures”中大小不正确的行 ")
datasetWithSize.show(false)

val assembler = new VectorAssembler()
  .setInputCols(Array("hour", "mobile", "userFeatures"))
  .setOutputCol("features")

// 该数据帧可以像以前一样被下游转换器使用 
val output = assembler.transform(datasetWithSize)
println("Assembled columns 'hour', 'mobile', 'userFeatures' to vector column 'features'")
output.select("features", "clicked").show(false)

输出:
过滤掉“userFeatures”中大小不正确的行 
+---+----+------+--------------+-------+
|id |hour|mobile|userFeatures  |clicked|
+---+----+------+--------------+-------+
|0  |18  |1.0   |[0.0,10.0,0.5]|1.0    |
+---+----+------+--------------+-------+

Assembled columns 'hour', 'mobile', 'userFeatures' to vector column 'features'
+-----------------------+-------+
|features               |clicked|
+-----------------------+-------+
|[18.0,1.0,0.0,10.0,0.5]|1.0    |
+-----------------------+-------+

 

三、QuantileDiscretizer

  QuantileDiscretizer 采用具有连续特征的列,并输出具有分箱分类特征的列。可以使用 numBuckets 参数设置 bin 的数量。使用的桶数可能会小于此值,例如,如果输入的不同值太少而无法创建足够的不同分位数。从 2.3.0 开始,QuantileDiscretizer 可以通过设置 inputCols 参数一次映射多个列。如果同时设置了 inputCol 和 inputCols 参数,则会抛出异常。要指定每列的桶数,可以设置 numBucketsArray 参数,或者如果跨列的桶数应该相同,可以设置 numBuckets 以方便。请注意,在多列的情况下,相对误差适用于所有列。

  NaN 处理:在 QuantileDiscretizer 拟合期间,将忽略列中的 null 和 NaN 值。这将生成一个用于进行预测的 Bucketizer 模型。在转换过程中,Bucketizer 在数据集中找到 NaN 值时会引发错误,但用户也可以通过设置 handleInvalid 来选择保留或删除数据集中的 NaN 值。如果用户选择保留 NaN 值,会进行特殊处理,放入自己的桶中,例如,如果使用 4 个桶,则非 NaN 数据将放入桶[0-3],但 NaN 将计数在一个特殊的桶中[4]。

  算法:使用近似算法选择 bin 范围(有关详细说明,请参阅 org.apache.spark.sql.DataFrameStatFunctions.approxQuantile 的文档)。近似的精度可以通过 relativeError 参数来控制。 bin 的下限和上限将是 -Infinity 和 +Infinity,涵盖所有实数值。

%spark
// 特征转换 —— —— QuantileDiscretizer
// QuantileDiscretizer 采用具有连续特征的列,并输出具有分箱分类特征的列。
// QuantileDiscretizer(分位数离散化)将一列连续型的数据列转成分类型数据。通过取一个样本的数据,并将其分为大致相等的部分,设定范围。其下限为 -Infinity(负无穷大) ,上限为+Infinity(正无穷大)。
// 按分位数,对给出的数据列进行离散化分箱处理。
import org.apache.spark.ml.feature.QuantileDiscretizer

val data = Array((0, 18.0), (1, 19.0), (2, 8.0), (3, 5.0), (4, 2.2))
val df = spark.createDataFrame(data).toDF("id", "hour")

val discretizer = new QuantileDiscretizer()
  .setInputCol("hour")
  .setOutputCol("result")
//   将数据点分组到其中的存储桶数(分位数或类别)。必须大于或等于 2。默认值:2
  .setNumBuckets(3)
//   支持参数:"skip","keep","error"
//   .setHandleInvalid("error")

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

输出:
+---+----+------+
|id |hour|result|
+---+----+------+
|0  |18.0|2.0   |
|1  |19.0|2.0   |
|2  |8.0 |1.0   |
|3  |5.0 |1.0   |
|4  |2.2 |0.0   |
+---+----+------+

 

四、Imputer

Imputer 估计器使用缺失值所在列的平均值或中值来完成数据集中的缺失值。 输入列应该是数字类型。 目前 Imputer 不支持分类特征,并且可能为包含分类特征的列创建不正确的值。 Imputer 可以通过 .setMissingValue(custom_value) 估算除“NaN”以外的自定义值。 例如,.setMissingValue(0) 将估算所有出现的 (0)。

注意输入列中的所有空值都被视为缺失,因此也被估算。

使用缺失值所在列的平均值或中值来完成缺失值的插补估计器。输入列应该是数字类型。目前 Imputer 不支持分类特征 (SPARK-15041) 并且可能为分类特征创建不正确的值。

请注意,当输入列是整数时,估算值被强制转换(截断)为整数类型。例如,如果输入列是 IntegerType (1, 2, 4, null),则平均插补后的输出将是 IntegerType (1, 2, 4, 2)。

请注意,均值/中值是在过滤掉缺失值后计算的。输入列中的所有 Null 值都被视为缺失,因此也被估算。对于计算中位数,使用 DataFrameStatFunctions.approxQuantile,相对误差为 0.001。

%spark
// 特征转换 —— —— Imputer
// 缺失值处理类
// 在此示例中,Imputer 将使用从相应列中的其他值计算的平均值(默认插补策略)替换所有出现的 Double.NaN(缺失值的默认值)。 在此示例中,a 列和 b 列的代理值分别为 3.0 和 4.0。 转换后,输出列中的缺失值将替换为相关列的代理值。 
import org.apache.spark.ml.feature.Imputer

val df = spark.createDataFrame(Seq(
  (1.0, Double.NaN),
  (2.0, Double.NaN),
  (Double.NaN, 3.0),
  (4.0, 4.0),
  (5.0, 5.0)
)).toDF("a", "b")

val imputer = new Imputer()
  .setInputCols(Array("a", "b"))
  .setOutputCols(Array("out_a", "out_b"))
//   缺失值的占位符。 所有出现的缺失值都将被估算。 请注意,空值始终被视为缺失。 默认值:Double.NaN 
// final valmissingValue: DoubleParam
  .setMissingValue(Double.NaN)
//   插补策略。目前仅支持“mean”和“median”。如果“mean”,则使用特征的平均值替换缺失值。如果是“median”,则使用特征的近似中值替换缺失值。默认值:mean 
  .setStrategy("mean")

val model = imputer.fit(df)
model.transform(df).show()

输出:
+---+---+-----+-----+
|  a|  b|out_a|out_b|
+---+---+-----+-----+
|1.0|NaN|  1.0|  4.0|
|2.0|NaN|  2.0|  4.0|
|NaN|3.0|  3.0|  3.0|
|4.0|4.0|  4.0|  4.0|
|5.0|5.0|  5.0|  5.0|
+---+---+-----+-----+

 

posted @ 2022-03-07 14:55  干了这瓶老干妈  阅读(451)  评论(0编辑  收藏  举报
Live2D