【问题标题】:Feature normalization algorithm in SparkSpark中的特征归一化算法
【发布时间】:2016-03-18 00:46:15
【问题描述】:

试图理解 Spark 的规范化算法。我的小测试集包含 5 个向量:

{0.95, 0.018, 0.0, 24.0, 24.0, 14.4, 70000.0},  
{1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 70000.0},  
{-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 70000.0},  
{-0.95, 0.018, 0.0, 24.0, 24.0, 14.4, 70000.0},  
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 70000.0},  

我希望 new Normalizer().transform(vectors) 会创建 JavaRDD,其中每个向量特征在 feature-0、`feature-1 等的所有值中都被归一化为 (v-mean)/stdev
结果集是:

[-1.4285714276967932E-5,-1.4285714276967932E-5,-1.4285714276967932E-5,-1.4285714276967932E-5,-1.4285714276967932E-5,-1.4285714276967932E-5,0.9999999993877552]  
[1.357142668768307E-5,2.571428214508371E-7,0.0,3.428570952677828E-4,3.428570952677828E-4,2.057142571606697E-4,0.9999998611976999]  
[-1.357142668768307E-5,2.571428214508371E-7,0.0,3.428570952677828E-4,3.428570952677828E-4,2.057142571606697E-4,0.9999998611976999]  
[1.4285714276967932E-5,1.4285714276967932E-5,1.4285714276967932E-5,1.4285714276967932E-5,1.4285714276967932E-5,1.4285714276967932E-5,0.9999999993877552]  
[0.0,0.0,0.0,0.0,0.0,0.0,1.0]  

请注意,所有原始值 7000.0 都会产生不同的“标准化”值。此外,例如,1.357142668768307E-5 的值是:.951-1-.950 时如何计算?更重要的是,如果我删除一个功能,结果会有所不同。找不到有关此问题的任何文档。
其实我的问题是,如何正确规范化RDD中的所有向量?

【问题讨论】:

  • 你确定你的输入都是正确的吗?如果您手动计算,您认为 stdev 是什么?

标签: apache-spark apache-spark-mllib apache-spark-ml


【解决方案1】:

您的期望完全不正确。正如the official documentation "Normalizer 中明确指出的那样,将单个样本缩放为具有单位 L p norm" 其中 p 的默认值为2.忽略数值精度问题:

import org.apache.spark.mllib.linalg.Vectors

val rdd = sc.parallelize(Seq(
    Vectors.dense(0.95, 0.018, 0.0, 24.0, 24.0, 14.4, 70000.0),  
    Vectors.dense(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 70000.0),  
    Vectors.dense(-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 70000.0),  
    Vectors.dense(-0.95, 0.018, 0.0, 24.0, 24.0, 14.4, 70000.0),  
    Vectors.dense(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 70000.0)))

val transformed = normalizer.transform(rdd)
transformed.map(_.toArray.sum).collect
// Array[Double] = Array(1.0009051182149054, 1.000085713673417,
//   0.9999142851020933, 1.00087797536153, 1.0

MLLib 不提供您需要的功能,但可以使用来自MLStandardScaler

import org.apache.spark.ml.feature.StandardScaler

val df = rdd.map(Tuple1(_)).toDF("features")

val scaler = new StandardScaler()
  .setInputCol("features")
  .setOutputCol("scaledFeatures")
  .setWithStd(true)
  .setWithMean(true)

val transformedDF =  scaler.fit(df).transform(df)

transformedDF.select($"scaledFeatures")show(5, false)

// +--------------------------------------------------------------------------------------------------------------------------+
// |scaledFeatures                                                                                                            |
// +--------------------------------------------------------------------------------------------------------------------------+
// |[0.9740388301169303,0.015272022105217588,0.0,1.0938637007095298,1.0938637007095298,1.0910691283447955,0.0]                |
// |[1.0253040317020319,1.4038947727833362,1.414213562373095,-0.6532797101459693,-0.6532797101459693,-0.6010982697825494,0.0] |
// |[-1.0253040317020319,-1.4242574689236265,-1.414213562373095,-0.805205224133404,-0.805205224133404,-0.8536605680105113,0.0]|
// |[-0.9740388301169303,0.015272022105217588,0.0,1.0938637007095298,1.0938637007095298,1.0910691283447955,0.0]               |
// |[0.0,-0.010181348070145075,0.0,-0.7292424671396867,-0.7292424671396867,-0.7273794188965303,0.0]                           |
// +--------------------------------------------------------------------------------------------------------------------------+

【讨论】:

  • 注意:StandardScaler 和 Normalizer 是不同的动物! - StandardScaler 作用于向量的列,减去平均值然后除以 stdev。 - 归一化器在每个向量上单独工作并除以范数。
  • @WillemM 是的,他们是。这正是这里的问题
猜你喜欢
  • 2021-05-22
  • 2015-11-23
  • 2016-11-30
  • 2014-12-27
  • 1970-01-01
  • 2018-11-29
  • 2020-02-10
  • 2013-02-20
  • 2019-01-24
相关资源
最近更新 更多