SparkML机器学习之特征工程(一)特征提取(TF-IDF、Word2Vec、CountVectorizer)
特征工程
我们都知道特征工程在机器学习中是很重要的,然而特征工程到底是什么?怎么样通俗的理解它呢?打个比方,即使你有再好的渔具,如果给你一片没有鱼的池塘,那也是白费力气的。而特征工程就是找有鱼的那片水域。所以我们可以这么理解,特征是数据中抽取出来的对结果预测有用的信息(水域),而特征工程就是使用专业知识来处理数据,筛选出具有价值的特征(从100个水域中挑选出鱼最多最好的水域)。所以有句话是这么说的:算法再牛逼,其上限也是由特征工程决定的,就像你渔具再好,捕鱼多少也是由水域这个特征决定的。
在SparkML中、对于特征工程的操作主要分为特征提取,特征转化、特征选择。
特征提取
从原始数据中提取特征
TF-IDF (Term frequency-inverse document frequency)
TF-IDF称为词频-逆文件频率,先搞清楚它有什么作用吧!很经典的一个问题,如何得到一篇文章的关键词??大家都能想到,看看这篇文章什么词出现最多!思路是没问题,但是,一篇文章,出现最多的,应该都是诸如“的”之类的停用词吧?这就没意义了啊!那就把这些停用词过滤掉呗,这样还是会出问题。比如一篇文章,叫做中国功夫,中国和功夫出现了同样多次数,可是显而易见,该文重点应该是功夫。而出现问题的原因,是因为中国是个热门词。这让我想到我曾写过的基于物品的协同过滤算法,也是要将热门物品做一个惩罚,否则会导致推荐不精确。
TF-IDF完美的解决了这个问题,TF-IDF作用就是体现一个文档中词语重要程度。TF是某个词或短语在一篇文章中出现的频率。而IDF,就是一种对热门词语的惩罚,对于较热门词语比如"中国"会给予较小的权重,较少见的词“功夫”给予较大的权重。至于如何判断它是否为热门词,则通过该词在整个语料库的出现次数决定。比如中国这个词,语料库一共1000篇文章他就出现了100次,自然为热门词,而功夫,1000篇文章只有1篇出现了,那就为冷门词了。
package ml.test import org.apache.spark.ml.feature.{HashingTF, IDF, Tokenizer} import org.apache.spark.sql.SparkSession /** * Created by LYL on 2018/4/4. */ object TFDemo { def main(args: Array[String]): Unit = { val spark = SparkSession.builder().appName("TF-IDF Demo").master("local").getOrCreate() val sentenceData = spark.createDataFrame(Seq( (0.0, "china kungfu kungfu is good"), (1.0, "I lova china"), (2.0, "I love china shenzhen") )).toDF("label", "sentence") //Tokenizer分词器 将句子分成单词 val tokenizer = new Tokenizer().setInputCol("sentence").setOutputCol("words") val wordsData = tokenizer.transform(sentenceData) //将每个词转换成Int型,并计算其在文档中的词频(TF) //setNumFeatures(200)表示将Hash分桶的数量设置为200个,可以根据你的词语数量来调整,一般来说,这个值越大不同的词被计算为一个Hash值的概率就越小,数据也更准确,但需要消耗更大的内存 val hashingTF = new HashingTF().setInputCol("words").setOutputCol("TF Features").setNumFeatures(200) val featurizedData = hashingTF.transform(wordsData) //计算IDF val idf = new IDF().setInputCol("TF Features").setOutputCol("TF-IDF features") val idfModel = idf.fit(featurizedData) val rescaledData = idfModel.transform(featurizedData) rescaledData.select("words","TF Features","TF-IDF features")show(false) } }
输出结果为:
由于china在三个文档中都出现了,所以TF-IDF=0.0,而kungfu只在第一个文档出现(说明是冷门词),却是第一个文档中出现次数最多的,因此计算出来的TF-IDF=1.3862943611198906也是最高的
+---------------------------------+----------------------------------------+---------------------------------------------------------------------------------------+ |words |TF Features |TF-IDF features | +---------------------------------+----------------------------------------+---------------------------------------------------------------------------------------+ |[china, kungfu, kungfu, is, good]|(200,[81,168,169,198],[1.0,1.0,1.0,2.0])|(200,[81,168,169,198],[0.6931471805599453,0.28768207245178085,0.0,1.3862943611198906]) | |[i, lova, china] |(200,[91,129,169],[1.0,1.0,1.0]) |(200,[91,129,169],[0.6931471805599453,0.28768207245178085,0.0]) | |[i, love, china, shenzhen] |(200,[40,129,168,169],[1.0,1.0,1.0,1.0])|(200,[40,129,168,169],[0.6931471805599453,0.28768207245178085,0.28768207245178085,0.0])| +---------------------------------+----------------------------------------+---------------------------------------------------------------------------------------+
Word2Vec
word2vec是用一个向量去表示一个对象(因为计算机是无法识别对象实体的),对象可以是单词,句子,文章,用户等等。然后基于向量相似度去计算对象的相似度,找到相关的对象,发现相关关系,可以用来做分类、聚类、也可以做词的相似度计算。应用非常广泛,比如:相关词(搜索乔布斯会出来苹果),补全句子中缺失的单词,推荐系统,分析用户关系等等。
object Word2VecDemo { def main(args: Array[String]): Unit = { val spark = SparkSession.builder().master("local[2]").appName("Word2VecDemo").getOrCreate() val documentDF = spark.createDataFrame(Seq( "Hi I love Spark".split(" "), "Hi I love java".split(" "), "Logistic regression models are neat".split(" ") ).map(Tuple1.apply)).toDF("text") // setVectorSize 目标数值向量的维度大小 setMinCount 只有当某个词出现的次数大于或者等于 minCount 时,才会被包含到词汇表里,否则会被忽略掉 val word2Vec = new Word2Vec() .setInputCol("text") .setOutputCol("result") .setVectorSize(3) .setMinCount(0) val model = word2Vec.fit(documentDF) //利用Word2VecModel把文档转变成特征向量。 val result = model.transform(documentDF) result.show(false) } }
输出结果为:
+-----------------------------------------+-------------------------------------------------------------------+ |text |result | +-----------------------------------------+-------------------------------------------------------------------+ |[Hi, I, love, Spark] |[-0.03605498746037483,-0.02823249064385891,0.06127407215535641] | |[Hi, I, love, java] |[-0.046827200800180435,-0.052235052920877934,0.0025074686855077744]| |[Logistic, regression, models, are, neat]|[0.04324783757328987,0.030185341089963916,-5.047338083386422E-4] | +-----------------------------------------+-------------------------------------------------------------------+
CountVectorizer
由于计算机是不能识别单词的,所以我们要把它转为向量。Countvectorizer和Countvectorizermodel旨在通过计数来将一个文档转换为向量。
object CountVectorizerDemo { def main(args: Array[String]): Unit = { val spark = SparkSession.builder().master("local[2]").getOrCreate() val dataFrame = spark.createDataFrame(Seq( (0, Array("a", "b","b","c","d","d")), (1, Array("a","c","b" )) )).toDF("id", "words") //setVocabSize设定词汇表的最大容量为3,setMinDF设定词汇表中的词至少要在2个文档中出现过。 //如果setMinDF=2 那么就不会出现d(只在一个文档存在)了。 val cv = new CountVectorizer().setVocabSize(3).setMinDF(2).setInputCol("words").setOutputCol("features") //如果setVocabSize=2 那么就不会出现a,c(次数少)了。 val cv1 = new CountVectorizer().setVocabSize(2).setInputCol("words").setOutputCol("features") val cvModel = cv.fit(dataFrame) val cvModel1 = cv1.fit(dataFrame) cvModel.transform(dataFrame).show(truncate = false) cvModel1.transform(dataFrame).show(truncate = false) } }
输出结果为:
//3代表词汇表的容量,[0,1,2]分别对应b,a,c,[2.0,1.0,1.0]代表出现次数 +---+------------------+-------------------------+ |id |words |features | +---+------------------+-------------------------+ |0 |[a, b, b, c, d, d]|(3,[0,1,2],[2.0,1.0,1.0])| |1 |[a, c, b] |(3,[0,1,2],[1.0,1.0,1.0])| +---+------------------+-------------------------+ +---+------------------+-------------------+ |id |words |features | +---+------------------+-------------------+ |0 |[a, b, b, c, d, d]|(2,[0,1],[2.0,2.0])| |1 |[a, c, b] |(2,[0],[1.0]) | +---+------------------+-------------------+
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
[Phoenix] 八、动态列
一、概要 动态列是指在查询中新增字段,操作创建表时未指定的列。传统关系型数据要实现动态列目前常用的方法有:设计表结构时预留新增字段位置、设计更通用的字段、列映射为行和利用json/xml存储字段扩展字段信息等,这些方法多少都存在一些缺陷,动态列的实现只能依赖逻辑层的设计实现。由于Phoenix是HBase上的SQL层,借助HBase特性实现的动态列,避免了传统关系型数据库动态列实现存在的问题。 二、动态列使用 示例表(用于语法说明) CREATE TABLE EventLog ( eventId BIGINT NOT NULL, eventTime TIME NOT NULL, eventType CHAR(3) CONSTRAINT pk PRIMARY KEY (eventId, eventTime)
- 下一篇
SparkML机器学习之特征工程(二)特征转化(Binarizer、StandardScaler、MaxAbsScaler、Normaliz...
特征转化 为什么要转化数据呢,就是要让它成为有效的特征,因为原始数据是很多脏数据无用数据的。常用的方法是标准化,归一化,特征的离散化等等。比如我输入的数据是句子,我得把它切分为一个个单词进行分析,这就是一种转化。 连续型数据处理之二值化:Binarizer 假设淘宝现在有个需求,我得根据年龄来进行物品推荐,把50以上的人分为老年,50以下分为非老年人,那么我们根据二值化可以很简单的把50以上的定为1,50以下的定为0。这样就方便我们后续的推荐了。Binarizer就是根据阈值进行二值化,大于阈值的为1.0,小于等于阈值的为0.0 package ml.test import org.apache.spark.ml.feature.Binarizer import org.apache.spark.sql.SparkSession /** * Created by liuyanling on 2018/3/19 */ object BinarizerDemo { def main(args: Array[String]): Unit = { var spark = SparkSessio...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果