Spark MLlib简介

1. Spark MLlib简介

1.1 传统ML

ML利用数据或以往经验,以此优化计算机程序的性能标准。

 ML强调的3个关键词: 算法、经验、性能

基于大数据的ML

1. 传统的ML算法,由于技术和单机存储的限制,只能在少量数据上使用,依赖于数据抽样。而大数据技术的出现,可以支持在全量数据上进行ML。

2. ML算法涉及大量迭代计算,基于磁盘的MR不适合进行大量迭代计算,而基于内存的Spark比较适合。

1.2 Spark 机器学习库MLlib

旨在简化ML的工程实践工作。

1. Spark的机器学习库是基于海量数据的,提供了常用ML算法的分布式实现。

2. 可以轻松的通过调用相应API来实现基于海量数据的ML过程。

3. spark-shell 可以满足交互式运行,方便结果查阅。

 MLlib由一些通用的学习算法和工具组成,同时还包括底层的优化原语和高层的流水线API。

1. 算法工具:常用的学习算法,如分类、回归、聚类、协同过滤等。

2. 特征化工具:特征提取、转化、降维和选择工具。

3. 流水线Pipeline: 用于构建、评估和调整ML工作流的工具。

4. 持久化:保存和加载算法、模型和管道。

5. 实用工具:线性代数、统计、数据处理等工具。

从1.2 版本后被分为两个包

1. spark.mllib

历史较长,包含了基于RDD的原始算法API。3.0版本后已废弃

2. spark.ml

提供了基于DataFrames高层次的API,可以用来构建ML Pipeline,弥补了MLlib库的不足,向用户提供了一个基于DF的ML 工作流式API。

 

2.  机器学习工作流

2.1 ML Pipeline 概念

2.1.1 DataFrame

使用Spark SQL中的DataFrame作为数据集,相比RDD,可以容纳各种数据类型,还包含了schema信息。被ML Pipeline 用来存储源数据,DF的列可以是存储的文本、特征向量、真实标签和预测的标签等。

2.1.2 Transformer

       转换器是一种进行DF转换的算法。一个模型就是一个Transformer,它可以把一个不包含预测标签的测试集DF打上标签,转化成另一个包含预测标签的DF。技术上,Transformer实现了一个transform(),通过附加一个或多个列将一个DF转换为另一个DF。

2.1.3 Estimator

评估器是学习算法或在训练数据上的训练方法的概念抽象,在Pipeline里通常是被用来操作DF数据并生成一个Transformer。从技术上讲,Estimator实现了一个fit(),接受一个DF并产生一个Transfomer。比如一个RF算法就是一个Estimator,它可以调用fit(),通过训练特征数据而得到一个RF模型。

2.1.4 Parameter

被用来设置Transformer或Estimator的参数。

2.1.5 PipeLine

工作流将多个阶段连接在一起,形成ML的工作流并获得结果输出。

val pipeline = new Pipeline.setStages(Array(stage1,stage2,...))

然后就可以把训练数据集作为输入参数,调用pipeline.fit()来开始以流的方式处理源训练数据,并返回一个PipelineModel,进而被用来预测测试数据的标签。(Pipeline本身也可以看作一个Estimator,而Pipeline Model是一个Transformer。)

 2.2 构建一个ML Pipeline

以LR为例,构建一个典型的ML过程。

识别包含"spark"的句子,包含的标签为1,反之标签为0。

1. 构建训练数据集。

train.csv

id,text,label
0L,"a b c d e spark",1.0
1L,"b d",0.0
2L,"spark f g h",1.0
3L,"hadoop mr",0.0
import org.apache.spark.sql.SparkSession
import org.apache.spark.ml.classification.LogisticRegression
import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.PredictionModel
import org.apache.spark.ml.linalg.Vector
import org.apache.spark.ml.feature._
import org.apache.spark.sql.Row

object Test {
    def main(args: Array[String]): Unit = {
        val spark = SparkSession
          .builder()
          .appName("wc")
          .master("local")
          .getOrCreate()
        val train_data = spark.createDataFrame(Seq(
            (0L, "a b c d e spark", 1.0),
            (1L, "b d", 0.0),
            (2L, "spark f g h", 1.0),
            (3L, "hadoop mr", 0.0)
        )).toDF("id", "text", "label")

        train_data.show(4)
        // 或从csv文件读取
        val trainDataPath = "/Users/zz/Desktop/train.csv"
        val train_data = spark.read
          .option("inferSchema", "true")  // 推断数据类型
          .option("delimiter",",")     //  可设置分隔符,默认,
          .option("nullValue", "?")      //  设置空值
          .option("header", true)        //  表示有表头,若没有则为false
          .csv(trainDataPath)
        train_data.printSchema()
        train_data.show(false)
        spark.stop()
    }
}

输出:

 2. 定义各个PipelineStage

val tokenizer = new Tokenizer()
  .setInputCol("text")
  .setOutputCol("words")
val hashingTF = new HashingTF()
  .setNumFeatures(1000)
  .setInputCol(tokenizer.getOutputCol)
  .setOutputCol("features")
val lr = new LogisticRegression()
  .setMaxIter(10)
  .setRegParam(0.01)

 3. 创建Pipeline

val pipeline = new Pipeline()
  .setStages(Array(tokenizer, hashingTF, lr))
val model = pipeline.fit(train_data)

4. 构建测试数据

test.csv

id,text
4L,"spark i j k"
5L,"l m n"
6L,"spark a"
7L,"apache hadoop"

val testDataPath = "/Users/zenmen/Desktop/test.csv"
val test_data = spark.read
  .option("inferSchema", "true")  // 推断数据类型
  .option("delimiter",",")     //  可设置分隔符,默认,
  .option("nullValue", "?")      //  设置空值
  .option("header", true)        //  表示有表头,若没有则为false
  .csv(testDataPath)       

5. 数据预测

model.transform(test_data)
  .select("id", "text", "probability", "prediction")
  .collect()
  .foreach{
    case Row(id:String, text:String, prob:Vector, prediction:Double)
    => println(s"($id,$text) --> prob=$prob, prediction=$prediction")
}

 3. 特征抽取、转化和选择

3.1 特征抽取TF-IDF

TF-IDF “词频-逆向文件概率” 是一种在文本挖掘中广泛使用的特征向量化方法,它可以体现一个文档中词语在语料库中的重要度。t:词语、d:文档、D:语料库。词频TF(t,d)是词语t在文档d中出现的次数。文件频率DF(t,D)是包含词语的文档的个数。

TF-IDF就是在数值化文档信息,衡量词语能提供多少信息以区分文档。

IDF(t,D)=log\frac{|D|+1}{DF(t,D)+1}

TF-IDF 度量值表示如下:

TFIDF(t,d,D)=TF(t,d)\cdot IDF(t,D)

在Spark ML库中,TF-IDF1被分成两部分

1. TF(+hashing)

HashingTF 是一个Transformer,接收词条的集合,然后把这些集合转化成固定长度的特征向量,该算法在哈希的同时会统计各个词条的词频。

2. IDF

是一个Estimator,在一个数据集上,调用其fit(),产生一个IDFModel,该模型接收HashingTF产生的特征向量,然后计算每一个词在文档中出现的频次。IDF会减少那些在语料库中出现频率较高的词的权重。

 过程描述:

1. 使用分解器Tokenizer把句子划分为单个词语;

2. 对每一个句子(词袋),使用HashingTF将句子转换为特征向量;

3.使用IDF重新调整特征向量,这种转换通常可以提高使用文本特征的性能。

 1. 语料准备

train.csv 每一个句子代表一个文档

label,sentence
0,"I heard about Spark and I love Spark"
0,"I wish Java could use case classes"
1,"Logistic regression models are neat"

 2. 用tokenizer对句子进行分词

import org.apache.spark.ml.feature.HashingTF
import org.apache.spark.ml.feature.IDF
import org.apache.spark.ml.feature.Tokenizer

val spark = SparkSession.builder().master("local").getOrCreate()
import spark.implicits._
val tokenizer = new Tokenizer()
  .setInputCol("sentence")
  .setOutputCol("words")
val wordsData = tokenizer.transform(train_data)
wordsData.show(false)

 3. 生成特征向量

设置分桶数为2000

val hashingTF = new HashingTF()
  .setNumFeatures(2000)
  .setInputCol("words")
  .setOutputCol("rawFeatures")
val featurizedData = hashingTF.transform(wordsData)
featurizedData.select("rawFeatures").show(false)

 4. 使用IDF对单纯的词频特征向量进行修正,使其更能体现不同词汇对文本的区别能力。

val idf = new IDF()
  .setInputCol("rawFeatures")
  .setOutputCol("features")
val idfModel = idf.fit(featurizedData)

 5. 数据预测

得到每一个单词对应的TF-IDF度量值

val rescaledData = idfModel.transform(featurizedData)
rescaledData.select("features", "label")
  .take(3)
  .foreach(println)

 [(2000,[240,333,1105,1329,1357,1777],[0.6931471805599453,0.6931471805599453,1.3862943611198906,0.5753641449035617,0.6931471805599453,0.6931471805599453]),0]
[(2000,[213,342,489,495,1329,1809,1967],[0.6931471805599453,0.6931471805599453,0.6931471805599453,0.6931471805599453,0.28768207245178085,0.6931471805599453,0.6931471805599453]),0]
[(2000,[286,695,1138,1193,1604],[0.6931471805599453,0.6931471805599453,0.6931471805599453,0.6931471805599453,0.6931471805599453]),1]

3.2 特征抽取 Word2Vec

        是一种词嵌入(Word Embedding)方法,可以计算每个单词在其给定语料库环境下的分布式词向量。其中,词向量表示可以在一定程度上刻画每个单词的语义,如果语义相近,那么它们的词向量在向量空间中也相互接近。

        Word2vec是一个Estimator,采用一系列代表文档的词语来训练word2vecmodel,该模型将每个词语映射到一个固定大小的向量,word2vecmodel使用文档中每个词语的平均数来将文档转换为向量,然后这个向量可以作为预测的特征,来计算文档相似度等。

一个实例:一组文档,其中一个词语序列代表一个文档,对于每一个文档,我们将其转换为一个特征向量。

 1. 创建语料

val seq = Seq(
  "I heard about Spark and I love Spark".split(" "),
  "I wish Java could use case classes".split(" "),
  "Logistic regression models are neat".split(" ")
)
val documentDF = spark.createDataFrame(seq.map(Tuple1.apply))
  .toDF("text")

 2. 创建Word2Vec,设置特征向量维度为3

val word2Vec = new Word2Vec()
  .setInputCol("text")
  .setOutputCol("result")
  .setVectorSize(3)
  .setMinCount(0)

 3. 模型训练及预测

生成Word2VecModel,并进行特征向量转换

val model = word2Vec.fit(documentDF)
val result = model.transform(documentDF)
result.select("result").take(3).foreach(println)

 3.3 特征抽取:CountVectorizer

       旨在通过计数来将一个文档转换为向量,当不存在先验字典时,CountVectorizer作为Estimator提取词汇进行训练并生成一个CountVectorizerModel用于存储相应的词汇向量空间。

       该模型产生文档关于词语的稀疏表示,其表示可以传递给其他算法,例如LDA;在CountVectorizerModel的训练过程中,CountVectorizer将根据语料库中的词频排序从高到低进行选择,词汇表的最大含量由vocabsize超参数来指定;超参数minDF,则指定词汇表中词语至少要在多个不同文档中出现。

1.  创造语料库,每行看作一个文档

val seq = Seq(
  (0, Array("a", "b", "c")),
  (1, Array("a", "b", "b", "c", "a"))
)
val df = spark.createDataFrame(seq)
  .toDF("id", "words")

2. 训练一个CountVectorizerModel,设定词汇表中的词至少要在2个文档中出现过,以过滤那些偶然出现的词汇。

val model = new CountVectorizer()
  .setInputCol("words")
  .setOutputCol("features")
  .setVocabSize(3)
  .setMinDF(2)
  .fit(df)
// 获得模型的词汇表 
model.vocabulary.foreach(println)
// b a c

 4. 模型预测,得到文档的向量化表示

model.transform(df).show(false)

5. 使用先验词汇表构建模型

和其他Transformer不同,CountVectorizerModel可以通过制定一个先验词汇表来直接生成。

val vocabulary_arr = Array("a", "b", "c")
val cvm = new CountVectorizerModel(vocabulary_arr)
  .setInputCol("words")
  .setOutputCol("features")
cvm.transform(df).select("features").show(false)

 


 

  • 4
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值