Spark连续特征转化成离散特征
当数据量很大的时候,分类任务通常使用【离散特征+LR】集成【连续特征+xgboost】,如果把连续特征加入到LR、决策树中,容易造成overfit。
如果想用上连续型特征,使用集成学习集成多种算法是一种方法,但是一是过程复杂了一些,另外训练过程会非常耗时,在不损失很多特征信息的情况下,可以考虑将连续特征转换成离散特征加入到LR模型中。
转换特征分成两种情况:
- 第一种情况: 特征还未转化成训练数据所需要的向量格式,此时每个特征为单独的一列,需要对这些单独的列进行离散化分桶。
- 第二种情况: 所有特征已经转化成训练数据所需要的向量格式,但是离散化的特征编号杂乱,例如:编号为[10,15,128,……],需要转化为[0,1,2,……],此时所有特征已经合并成一个向量,但是这个向量为单独的一列但是包含了离散特征和连续特征,那么需要先识别出离散特征,再把离散特征进行规范化。
1. 第一种情况
1.1.二元转化
Binarization is the process of thresholding numerical features to binary (0/1) features.(二元转化,把连续特征转化为0/1特征)
Binarizer takes the common parameters inputCol and outputCol, as well as the threshold for binarization. Feature values greater than the threshold are binarized to 1.0; values equal to or less than the threshold are binarized to 0.0. Both Vector and Double types are supported for inputCol.(支持两种格式,double&vector,大于阈值的改为1.0,低于阈值的改为0.0)
import org.apache.spark.ml.feature.Binarizer val data = Array((, 0.1), (, 0.8), (, 0.2))
val dataFrame = spark.createDataFrame(data).toDF("id", "feature") val binarizer: Binarizer = new Binarizer()
.setInputCol("feature")
.setOutputCol("binarized_feature")
.setThreshold(0.5) val binarizedDataFrame = binarizer.transform(dataFrame) println(s"Binarizer output with Threshold = ${binarizer.getThreshold}")
binarizedDataFrame.show()
1.2.多元转换(分桶Bucketizer)
Bucketizer transforms a column of continuous features to a column of feature buckets, where the buckets are specified by users. It takes a parameter:
splits: Parameter for mapping continuous features into buckets. With n+1 splits, there are n buckets. A bucket defined by splits x,y holds values in the range [x,y) except the last bucket, which also includes y. Splits should be strictly increasing. Values at -inf, inf must be explicitly provided to cover all Double values; Otherwise, values outside the splits specified will be treated as errors. Two examples of splits are Array(Double.NegativeInfinity, 0.0, 1.0, Double.PositiveInfinity) and Array(0.0, 1.0, 2.0).
二元转换的时候需要给出一个阀值,在多元换转换中,如果要分成n类,就要给出n+1个阀值组成的array,任意一个数都可以被放在某两个阀值的区间内,就像把它放进属于它的桶中,故称为分桶策略。
比如有x,y两个阀值,那么他们组成的区间是[x,y)的前开后闭区间;对于最后一个区间是前闭后闭区间。
给出的这个阀值array,里面的元素必须是递增的。如果在转换的过程中有一个数没有被包含在区间内,那么就会报错,所以,如果不确定特征值的最小与最大值,那么就添加Double.NegativeInfinity(负无穷)和Double.PositiveInfinity(正无穷)到array的两侧。
Note that if you have no idea of the upper and lower bounds of the targeted column, you should add Double.NegativeInfinity and Double.PositiveInfinity as the bounds of your splits to prevent a potential out of Bucketizer bounds exception. 当不知道范围的时候设定成正负无穷作为边界。
Note also that the splits that you provided have to be in strictly increasing order, i.e. s0 < s1 < s2 < ... < sn.
import org.apache.spark.ml.feature.Bucketizer val splits = Array(Double.NegativeInfinity, -0.5, 0.0, 0.5, Double.PositiveInfinity) val data = Array(-999.9, -0.5, -0.3, 0.0, 0.2, 999.9)
val dataFrame = spark.createDataFrame(data.map(Tuple1.apply)).toDF("features") val bucketizer = new Bucketizer()
.setInputCol("features")
.setOutputCol("bucketedFeatures")
.setSplits(splits) // Transform original data into its bucket index.
val bucketedData = bucketizer.transform(dataFrame) println(s"Bucketizer output with ${bucketizer.getSplits.length-1} buckets")
bucketedData.show() val splitsArray = Array(
Array(Double.NegativeInfinity, -0.5, 0.0, 0.5, Double.PositiveInfinity),
Array(Double.NegativeInfinity, -0.3, 0.0, 0.3, Double.PositiveInfinity)) val data2 = Array(
(-999.9, -999.9),
(-0.5, -0.2),
(-0.3, -0.1),
(0.0, 0.0),
(0.2, 0.4),
(999.9, 999.9))
val dataFrame2 = spark.createDataFrame(data2).toDF("features1", "features2") val bucketizer2 = new Bucketizer()
.setInputCols(Array("features1", "features2"))
.setOutputCols(Array("bucketedFeatures1", "bucketedFeatures2"))
.setSplitsArray(splitsArray) // Transform original data into its bucket index.
val bucketedData2 = bucketizer2.transform(dataFrame2) println(s"Bucketizer output with [" +
s"${bucketizer2.getSplitsArray(0).length-1}, " +
s"${bucketizer2.getSplitsArray(1).length-1}] buckets for each input column")
bucketedData2.show()
封装成函数调用:
//连续特征离散化(分多个桶)
def QuantileDiscretizer_multi_class(df:DataFrame,InputCol:String,OutputCol:String,NumBuckets:Int):(DataFrame) = {
import org.apache.spark.ml.feature.Bucketizer
val discretizer = new QuantileDiscretizer()
.setHandleInvalid("skip")
.setInputCol(InputCol)
.setOutputCol(OutputCol)
.setNumBuckets(NumBuckets) println("\n\n*********分桶数量:"+ NumBuckets + "***********分桶列:" + InputCol + "**********输出列:" + OutputCol + "**********\n\n")
val result = discretizer.fit(df).transform(df)
result.show(false)
result
}
1.3.QuantileDiscretizer(分位数离散化)
QuantileDiscretizer
takes a column with continuous features and outputs a column with binned categorical features. The number of bins is set by the numBuckets
parameter. It is possible that the number of buckets used will be smaller than this value, for example, if there are too few distinct values of the input to create enough distinct quantiles.
NaN values: NaN values will be removed from the column during QuantileDiscretizer
fitting. This will produce a Bucketizer
model for making predictions. During the transformation, Bucketizer
will raise an error when it finds NaN values in the dataset, but the user can also choose to either keep or remove NaN values within the dataset by setting handleInvalid
. If the user chooses to keep NaN values, they will be handled specially and placed into their own bucket, for example, if 4 buckets are used, then non-NaN data will be put into buckets[0-3], but NaNs will be counted in a special bucket[4].
Algorithm: The bin ranges are chosen using an approximate algorithm (see the documentation for approxQuantile for a detailed description). The precision of the approximation can be controlled with the relativeError
parameter. When set to zero, exact quantiles are calculated (Note: Computing exact quantiles is an expensive operation). The lower and upper bin bounds will be -Infinity
and +Infinity
covering all real values.
QuantileDiscretizer(分位数离散化)。通过取一个样本的数据,并将其分为大致相等的部分,设定范围。其下限为 -Infinity(负无重大) ,上限为+Infinity(正无重大)。
分桶的数量由numbucket参数设置,但如果样本数据只存在n个区间,此时设置numBuckets为n+1,则仍只能划分出n个区间。
分级的范围有渐进算法决定。渐进的精度由relativeError参数决定。当relativeError设置为0时,将会计算精确的分位点(计算代价较大,通常使用默认即可)。relativeError参数必须在[0,1]范围内,默认值为0.001。
当分桶器分桶遇到NaN值时,会出现一个错误(默认)。handleInvalid参数可以来选择保留或者删除NaN值,如果选择不删除,NaN值的数据会单独放入一个桶中。
handleInvalid的选项有'skip'(过滤掉具有无效值的行)、'error'(抛出错误)或'keep'(将无效值保留在一个特殊的额外bucket中,默认是'error'。
import org.apache.spark.ml.feature.QuantileDiscretizer val data = Array((, 18.0), (, 19.0), (, 8.0), (, 5.0), (, 2.2))
val df = spark.createDataFrame(data).toDF("id", "hour") val discretizer = new QuantileDiscretizer()
.setHandleInvalid("skip")
.setInputCol("hour")
.setOutputCol("result")
.setNumBuckets() val result = discretizer.fit(df).transform(df)
result.show(false)
封装使用:
//连续特征离散化(分多个桶)
def QuantileDiscretizer_multi_class(df:DataFrame,InputCol:String,OutputCol:String,NumBuckets:Int):(DataFrame) = {
import org.apache.spark.ml.feature.QuantileDiscretizer
val discretizer = new QuantileDiscretizer()
.setHandleInvalid("skip")
.setInputCol(InputCol)
.setOutputCol(OutputCol)
.setNumBuckets(NumBuckets) println("\n\n*********分桶数量:"+ NumBuckets + "***********分桶列:" + InputCol + "**********输出列:" + OutputCol + "**********\n\n")
val result = discretizer.fit(df).transform(df)
result.show(false)
result
}
实际使用中不建议直接对全量数据做处理,因为通常全量数据都很大,使用这个函数时集群经常会出现各种问题,建议只对训练集做处理或者对全量数据采样处理,再保存训练好的模型直接转换全量数据。
2. 第二种情况
2.1.向量转规范的离散特征-VectorIndexer
import org.apache.spark.ml.feature.VectorIndexer
VectorIndexerModel featureIndexerModel=new VectorIndexer()
.setInputCol("features") //定义特征列
.setMaxCategories() //多于5个取值视为连续值,连续值不进行转换。
.setOutputCol("indexedFeatures")
.fit(rawData);
//加入到Pipeline
Pipeline pipeline=new Pipeline()
.setStages(new PipelineStage[]
{labelIndexerModel,
featureIndexerModel,
dtClassifier,
converter});
pipeline.fit(rawData).transform(rawData).select("features","indexedFeatures").show(,false);
2.2.字符串转离散特征
import org.apache.spark.ml.feature.StringIndexer
val df = spark.createDataFrame(Seq((, "a"), (, "b"), (, "c"), (, "a"), (, "a"), (, "c"))).toDF("id", "category")
val indexer = new StringIndexer()
.setInputCol("category") //改为带索引的标签,索引为该标签出现的次数。
.setOutputCol("categoryIndex")
.setHandleInvalid("skip") //如果category数量多于label的数量,选择error会报错,选择skip则直接跳过这些数据
val indexed = indexer.fit(df).transform(df)
indexed.show()
Spark连续特征转化成离散特征的更多相关文章
- spark机器学习从0到1特征变换-标签和索引的转化(十六)
一.原理 在机器学习处理过程中,为了方便相关算法的实现,经常需要把标签数据(一般是字符串)转化成整数索引,或是在计算结束后将整数索引还原为相应的标签. Spark ML 包中提供了几个相关的转换器 ...
- 处理离散型特征和连续型特征共存的情况 归一化 论述了对离散特征进行one-hot编码的意义
转发:https://blog.csdn.net/lujiandong1/article/details/49448051 处理离散型特征和连续型特征并存的情况,如何做归一化.参考博客进行了总结:ht ...
- Spark Streaming揭秘 Day2-五大核心特征
Spark Streaming揭秘 Day2 五大核心特征 引子 书接上回,Streaming更像Spark上的一个应用程序,会有多个Job的配合,是最复杂的Spark应用程序.让我们先从特征角度进行 ...
- 图像的特征工程:HOG特征描述子的介绍
介绍 在机器学习算法的世界里,特征工程是非常重要的.实际上,作为一名数据科学家,这是我最喜欢的方面之一!从现有特征中设计新特征并改进模型的性能,这就是我们进行最多实验的地方. 世界上一些顶级数据科学家 ...
- B - Housewife Wind POJ - 2763 树剖+边权转化成点权
B - Housewife Wind POJ - 2763 因为树剖+线段树只能解决点权问题,所以这种题目给了边权的一般要转化成点权. 知道这个以后这个题目就很简单了. 怎么转化呢,就把这个边权转化为 ...
- [LeetCode] Integer to Roman 整数转化成罗马数字
Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 t ...
- OpenCV特征点检测------ORB特征
OpenCV特征点检测------ORB特征 ORB是是ORiented Brief的简称.ORB的描述在下面文章中: Ethan Rublee and Vincent Rabaud and Kurt ...
- HTML5将图片转化成字符画
HTML5将图片转化成字符画 字符画大家一定非常熟悉了,那么如何把一张现有的图片转成字符画呢?HTML5让这个可能变成了现实,通过canvas,可以很轻松实现这个功能.其实原理很简单:扫描图片相应位置 ...
- xml格式的数据转化成数组
将得到的xml格式的数据转化成数组 <?php //构造xml $url = "http://api.map.baidu.com/telematics/v3/weather?locat ...
随机推荐
- 模块加载——modprobe和insmod的区别(转)
转载地址:https://blog.csdn.net/qianyizhou17/article/details/44135133 linux设备驱动有两种加载方式insmod和modprobe,下面谈 ...
- 10 分钟上手 Vim,常用命令大盘点
传闻有 180 万的程序员不知道如何退出 Vim 编辑器,真的有这么困难吗?下面给大家整理了一份 Vim 常用命令,让你 10 分钟快速上手 Vim,溜得飞起! 以下命令请在普通模式执行 1.移动光标 ...
- ELK日志分析
1. 为什么用到ELK 一般我们需要进行日志分析场景:直接在日志文件中 grep.awk 就可以获取自己想要的信息.但是规模较大的场景中,此方法效率低下,面临问题包括日志量太大如何归档.文本搜索太慢怎 ...
- Linux创建目录和文件的默认权限设置
这两天,项目中使用jenkins自动构建系统时遇到了在Linux中创建目录和文件的权限问题,临时的解决办法是在脚本中增加了chmod赋权限命令; 偶然想到Linux应该是可以设置默认权限的,故学习了一 ...
- 百度UEditor添加视频 增加支持“通用代码”功能,支持微信
今天发现用UEditor默认的添加视频,在微信内置浏览器里无法正常显示.估计是微信屏蔽了UEditor使用的<embeded>标签.插入iframe形式的通用代码则能正常显示. 用百度UE ...
- python应用-彩票随机码的输出
""" 双色球-6个红色球(1-33)和一个蓝色球(1-16) """ from random import randint def sel ...
- Ofbiz项目学习——阶段性小结——插入数据
一.通用插入操作 /** * * 编写一个服务createUomOneDemo, * 该服务的作用是在表Uom中增加一条记录,其中: * 字段uomId的值为“BaseLineProduct”. * ...
- 20182310 第二周&第三周学习总结
20182310 2019-2020-1 <数据结构与面向对象程序设计>第2周&第3周学习总结 教材学习内容总结 1.首先是String类定义的字符串,然后是print和print ...
- idea启动项目连接mysql数据库后台报duplicate name异常
自己写的sql语句在MySQL数据库中运行是没有问题的 但是在使用idea启动项目的时候,后台在运行这行sql语句的时候居然报错了,duplicate name:重复的名字,最后自己经过思考,修改了一 ...
- nginx,apache,tomcat的区别
nginx与apache 这里说的apche指apache http server ,与nginx都属于http服务器软件,主要处理静态资源. http server关心的是http协议层面的传输和访 ...