2016-02-19 135 views
2

我有一个数据帧,看起来像如下:为什么StandardScaler会给出非零的维值,因为方差不是零?

+-----+--------------------+ 
| 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:

  • 此维度具有0.0用户1,4.0和用户2 7.0用户3的值。 (0 + 4 + 7)/ 3 = 3.667
  • SD为:sqrt [ 3.667)^ 2)/ 3] = 2.868
  • 为User1的单位标准偏差应为:(值均)/ SD =(0-3.667)/2.868 = -1.279

的问题是:为什么输出DataFrame中的user1对此维度具有零值?

回答

5

这里是罪魁祸首:

.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:默认为False。在缩放之前将数据与平均值集中。它将构建一个密集的输出,所以这对于稀疏输入不起作用,并会引发异常。

从注释合并:

因此,没有setWithMean也不会值减去平均值,但它会直接sd划分值。

为了做.setWithMean(true)我不得不将特征转换为密集矢量而不是稀疏矢量(因为它会引发稀疏矢量的异常)。