文档章节

Spark数据挖掘-数据标准化

clebeg
 clebeg
发布于 2015/11/10 19:52
字数 1125
阅读 1398
收藏 9

Spark数据挖掘-数据标准化

1 前言

特征数据标准化指的是对训练样本通过利用每一列的统计量将特征列转换为0均值单位方差的数据。 这是非常通用的数据预处理步骤。
例如:RBF核的支持向量机或者基于L1和L2正则化的线性模型在数据标准化之后效果会更好。
数据标准化能够改进优化过程中数据收敛的速度,也能防止一些方差过大的变量特征对模型训练 产生过大的影响。
如何对数据标准化呢?公式也非常简单:新的列 = (老的列每一个值 - 老的列平均值) / (老的列标准差)

2 数据准备

在标准化之前,Spark必须知道每一列的平均值,方差,具体怎么知道呢?
想法很简单,首先给 Spark的 StandardScaler 一批数据,这批数据以 org.apache.spark.mllib.feature.Vector 的形式提供给 StandardScaler。StandardScaler 对输入的数据进行 fit 即计算每一列的平均值,方差。 调度代码如下:

import org.apache.spark.SparkContext._
import org.apache.spark.mllib.feature.StandardScaler
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.util.MLUtils

val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")

val scaler1 = new StandardScaler().fit(data.map(x => x.features))
val scaler2 = new StandardScaler(withMean = true, withStd = true).fit(data.map(x => x.features))

上面代码的本质是生成一个包含每一列均值和方差的 StandardScalarModel,具体解释一下 withMean 和 withStd 的含义:

  • withMean 如果值为true,那么将会对列中每个元素减去均值(否则不会减)
  • withStd 如果值为true,那么将会对列中每个元素除以标准差(否则不会除,这个值一般为 true,否则没有标准化没有意义) 所以上面两个参数都为 false 是没有意义的,模型什么都不会干,返回原来的值,这些将会在下面的代码中得到验证。

下面给出上面 fit 函数的源代码:

 /**
  * 计算数据每一列的平均值标准差,将会用于之后的标准化.
  *
  * @param data The data used to compute the mean and variance to build the transformation model.
  * @return a StandardScalarModel
  */
 @Since("1.1.0")
 def fit(data: RDD[Vector]): StandardScalerModel = {
   // TODO: 如果 withMean 和 withStd 都为false,什么都不用干
   //计算基本统计
   val summary = data.treeAggregate(new MultivariateOnlineSummarizer)(
     (aggregator, data) => aggregator.add(data),
     (aggregator1, aggregator2) => aggregator1.merge(aggregator2))
   //通过标准差,平均值得到模型
   new StandardScalerModel(
     Vectors.dense(summary.variance.toArray.map(v => math.sqrt(v))),
     summary.mean,
     withStd,
     withMean)
 }

从这里可以发现,如果你知道每一列的平均值和方差,直接通过 StandardScalarModel 构建模型就可以了,如下代码:

val scaler3 = new StandardScalerModel(scaler2.std, scaler2.mean)

3 数据标准化

准备工作做好了,下面真正标准化,调用代码也非常简单:

al data1 = data.map(x => (x.label, scaler1.transform(x.features)))

用模型对每一行 transform 就可以了,背后的原理也非常简单,代码如下:

 // 因为 `shift` 只是在 `withMean` 为真的分支中才使用, 所以使用了
 // `lazy val`. 注意:这里不想在每一次 `transform` 都计算一遍 shift.
 private lazy val shift: Array[Double] = mean.toArray

 /**
  * Applies standardization transformation on a vector.
  *
  * @param vector Vector to be standardized.
  * @return Standardized vector. If the std of a column is zero, it will return default `0.0`
  *         for the column with zero std.
  */
 @Since("1.1.0")
 override def transform(vector: Vector): Vector = {
   require(mean.size == vector.size)
   if (withMean) {
     // By default, Scala generates Java methods for member variables. So every time when
     // the member variables are accessed, `invokespecial` will be called which is expensive.
     // This can be avoid by having a local reference of `shift`.
     val localShift = shift
     vector match {
       case DenseVector(vs) =>
         val values = vs.clone()
         val size = values.size
         if (withStd) {
           var i = 0
           while (i < size) {
             values(i) = if (std(i) != 0.0) (values(i) - localShift(i)) * (1.0 / std(i)) else 0.0
             i += 1
           }
         } else {
           var i = 0
           while (i < size) {
             values(i) -= localShift(i)
             i += 1
           }
         }
         Vectors.dense(values)
       case v => throw new IllegalArgumentException("Do not support vector type " + v.getClass)
     }
   } else if (withStd) {
     vector match {
       case DenseVector(vs) =>
         val values = vs.clone()
         val size = values.size
         var i = 0
         while(i < size) {
           values(i) *= (if (std(i) != 0.0) 1.0 / std(i) else 0.0)
           i += 1
         }
         Vectors.dense(values)
       case SparseVector(size, indices, vs) =>
         // For sparse vector, the `index` array inside sparse vector object will not be changed,
         // so we can re-use it to save memory.
         val values = vs.clone()
         val nnz = values.size
         var i = 0
         while (i < nnz) {
           values(i) *= (if (std(indices(i)) != 0.0) 1.0 / std(indices(i)) else 0.0)
           i += 1
         }
         Vectors.sparse(size, indices, values)
       case v => throw new IllegalArgumentException("Do not support vector type " + v.getClass)
     }
   } else {
     // Note that it's safe since we always assume that the data in RDD should be immutable.
     vector
   }
 }

标准化原理简单,代码也简单,但是作用不能小看。

个人微信公众号

欢迎关注本人微信公众号,会定时发送关于大数据、机器学习、Java、Linux 等技术的学习文章,而且是一个系列一个系列的发布,无任何广告,纯属个人兴趣。
Clebeg能量集结号

© 著作权归作者所有

clebeg
粉丝 45
博文 40
码字总数 40057
作品 0
广州
程序员
私信 提问
从Hadoop到Spark的架构实践

当下,Spark已经在国内得到了广泛的认可和支持:2014年,Spark Summit China在北京召开,场面火爆;同年,Spark Meetup在北京、上海、深圳和杭州四个城市举办,其中仅北京就成功举办了5次,内...

Emilypz
2015/10/10
1K
0
Spark部署及技术选型

Spark部署及技术选型 在飞速发展的云计算大数据时代,Spark是继Hadoop之后,成为替代Hadoop的下一代云计算大数据核心技术,目前Spark已经构建了自己的整个大数据处理生态系统,如流处理、图技...

Spark亚太研究院
2014/07/01
2.2K
4
Spark大数据分析框架的核心部件

Spark大数据分析框架的核心部件 Spark大数据分析框架的核心部件包含RDD内存数据结构、Streaming流计算框架、GraphX图计算与网状数据挖掘、MLlib机器学习支持框架、Spark SQL数据检索语言、T...

openthings
2015/08/07
375
1
Spark成为大数据高手进阶步骤

什么是Spark Spark是UC Berkeley AMP lab所开源的类Hadoop MapReduce的通用的并行计算框架,Spark基于map reduce算法实现的分布式计算,拥有Hadoop MapReduce所具有的优点;但不同于MapRedu...

MoksMo
2015/11/05
2.1K
1
hadoop和spark的区别介绍

学习hadoop已经有很长一段时间了,好像是二三月份的时候朋友给了一个国产Hadoop发行版下载地址,因为还是在学习阶段就下载了一个三节点的学习版玩一下。在研究、学习hadoop的朋友可以去找一下...

adnb34g
2018/06/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

iOS Xcode升级包地址(感谢大神)

下载地址:DeviceSupport

_____1____
23分钟前
6
0
Qt编写自定义控件71-圆弧进度条

一、前言 现在web形式的图表框架非常流行,国产代表就是echart,本人用过几次,三个字屌爆了来形容,非常强大,而且易用性也非常棒,还是开源免费的,使用起来不要太爽,内置的各种图表和仪表...

飞扬青云
23分钟前
4
0
润乾报表与 ActiveReport JS 功能对比

简介 润乾报表是用于报表制作的大型企业级报表软件,核心特点在于开创性地提出了非线性报表数学模型,采用了革命性的多源关联分片、不规则分组、自由格间运算、行列对称等技术,使得复杂报表...

泡泡糖儿
34分钟前
5
0
【1015】LNMP架构二

【1015】LNMP架构二 三、PHP安装 PHP安装和LAMP安装PHP方法有差别,需要开启php-fpm服务 1、下载PHP7至/usr/local/src/ 切换目录:cd /usr/local/src 2、解压缩 tar -jxvf php-7.3.0.tar.gz...

飞翔的竹蜻蜓
今天
5
0
浅谈Visitor访问者模式

一、前言 什么叫访问,如果大家学过数据结构,对于这点就很清晰了,遍历就是访问的一般形式,单独读取一个元素进行相应的处理也叫作访问,读取到想要查看的内容+对其进行处理就叫作访问,那么...

青衣霓裳
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部