【问题标题】:Why does StandardScaler give non-zero values for dimensions as the variance is not zero?为什么 StandardScaler 为维度提供非零值,因为方差不为零?
【发布时间】:2016-03-16 15:13:32
【问题描述】:

我有一个如下所示的 DataFrame:

+-----+--------------------+
|  uid|            features|
+-----+--------------------+
|user1|       (7,[1],[5.0])|
|user2|(7,[0,2],[13.0,4.0])|
|user3|(7,[2,3],[7.0,45.0])|
+-----+--------------------+

特征列是一个稀疏向量,大小等于4。

我正在申请StandardScaler,如下所示:

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

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

val scalerModel = scaler.fit(df)

// Normalize each feature to have unit standard deviation.
val scaledData = scalerModel.transform(transformed)

输出的 DataFrame 如下所示:

+-----+--------------------+--------------------+
|  uid|            features|      scaledFeatures|
+-----+--------------------+--------------------+
|user1|       (7,[1],[5.0])|(7,[1],[1.7320508...|
|user2|(7,[0,2],[13.0,4.0])|(7,[0,2],[1.73205...|
|user3|(7,[2,3],[7.0,45.0])|(7,[2,3],[1.99323...|
+-----+--------------------+--------------------+

我们可以看到,例如 user1 的 scaledFeatures 仅包含一个元素(其他元素为零),但我希望每个 scaledFeatures 始终包含所有维度的非零值,因为方差不为零。

我们以第三维为例,即每个特征向量的索引2:

  • 此维度的值为 user1 的 0.0、user2 的 4.0 和 user3 的 7.0。
  • 这些值的平均值是:(0+4+7)/3 = 3.667
  • SD 为:sqrt[ ( (0-3.667)^2 + (4-3.667)^2 + (7-3.667)^2 ) /3] = 2.868
  • user1 的单位标准差应为:(value-average)/SD = (0-3.667)/2.868 = -1.279

问题是:为什么输出 DataFrame 中的 user1 的 this 维度为零?

【问题讨论】:

    标签: apache-spark apache-spark-ml


    【解决方案1】:

    这是罪魁祸首:

    .setWithMean(false) 
    

    由于您应用的唯一方法是缩放到单位标准差,因此结果与应有的完全一样:

    xs1 <- c(5, 0, 0)
    xs1 / sd(xs1)
    ## [1] 1.732051 0.000000 0.000000
    sd(xs1 / sd(xs1))
    ## [1] 1
    
    xs2 <- c(0.0, 4.0, 7.0)
    xs2 / sd(xs2)
    ## [1] 0.000000 1.138990 1.993232
    sd(xs2 / sd(xs2))
    ## [1] 1
    

    另外withMean 需要密集数据。来自文档:

    withMean:默认为假。在缩放之前以均值居中数据。它将构建密集输出,因此这不适用于稀疏输入并且会引发异常。

    从 cmets 合并:

    所以没有setWithMean,它不会从值中减去平均值,而是直接将值除以sd

    为了做到.setWithMean(true),我必须将特征转换为密集向量而不是稀疏向量(因为它会引发稀疏向量异常)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-14
      • 1970-01-01
      • 1970-01-01
      • 2021-04-30
      相关资源
      最近更新 更多