spark应用程序转换_4.Spark特征提取、转换和选择 - 简书

在实际机器学习项目中,我们获取的数据往往是不规范、不一致、有很多缺失数据,甚至不少错误数据,这些数据有时又称为脏数据或噪音,在模型训练前,务必对这些脏数据进行处理,否则,再好的模型,也只能脏数据进,脏数据出。

这章我们主要介绍对数据处理涉及的一些操作,主要包括: 特征提取

特征转换

特征选择

4.1 特征提取

特征提取一般指从原始数据中抽取特征。

4.1.1 词频-逆向文件频率(TF-IDF)

词频-逆向文件频率(TF-IDF)是一种在文本挖掘中广泛使用的特征向量化方法,它可以体现一个文档中词语在语料库中的重要程度。

在下面的代码段中,我们以一组句子开始。首先使用分解器Tokenizer把句子划分为单个词语。对每一个句子(词袋),我们使用HashingTF将句子转换为特征向量,最后使用IDF重新调整特征向量。这种转换通常可以提高使用文本特征的性能。 import org.apache.spark.ml.feature.{HashingTF, IDF, Tokenizer}

val sentenceData = spark.createDataFrame(Seq(

(0, "Hi I heard about Spark"),

(0, "I wish Java could use case classes"),

(1, "Logistic regression models are neat")

)).toDF("label", "sentence")

val tokenizer = new Tokenizer().setInputCol("sentence").setOutputCol("words")

val wordsData = tokenizer.transform(sentenceData)

val hashingTF = new HashingTF().setInputCol("words").setOutputCol("rawFeatures").setNumFeatures(20)

val featurizedData = hashingTF.transform(wordsData)

// CountVectorizer也可获取词频向量

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

val idfModel = idf.fit(featurizedData)

val rescaledData = idfModel.transform(featurizedData)

rescaledData.select("features", "label").take(3).foreach(println)

4.1.2 Word2Vec

Word2vec是一个Estimator,它采用一系列代表文档的词语来训练word2vecmodel。 在下面的代码段中,我们首先用一组文档,其中每一个文档代表一个词语序列。对于每一个文档,我们将其转换为一个特征向量。此特征向量可以被传递到一个学习算法。 import org.apache.spark.ml.feature.Word2Vec

// 输入数据,每行为一个词袋,可来自语句或文档。

val documentDF = spark.createDataFrame(Seq(

"Hi I heard about Spark".split(" "),

"I wish Java could use case classes".split(" "),

"Logistic regression models are neat".split(" ")

).map(Tuple1.apply)).toDF("text")

//训练从词到向量的映射

val word2Vec = new Word2Vec()

.setInputCol("text")

.setOutputCol("result")

.setVectorSize(3)

.setMinCount(0)

val model = word2Vec.fit(documentDF)

val result = model.transform(documentDF)

result.select("result").take(3).foreach(println)

4.1.3 计数向量器

计数向量器(Countvectorizer)和计数向量器模型(Countvectorizermodel)旨在通过计数来将一个文档转换为向量。

以下用实例来说明计数向量器的使用。

假设有以下列id和texts构成的DataFrame: id texts

0 Array("a", "b", "c")

1 Array("a", "b", "b", "c", "a")

每行text都是Array [String]类型的文档。调用fit,CountVectorizer产生CountVectorizerModel含词汇(a,b,c)。转换后的输出列“向量”包含:

调用的CountVectorizer产生词汇(a,b,c)的CountVectorizerModel,转换后的输出向量如下: id texts vector

0 Array("a", "b", "c") (3,[0,1,2],[1.0,1.0,1.0])

1 Array("a", "b", "b", "c", "a") (3,[0,1,2],[2.0,2.0,1.0])

每个向量代表文档的词汇表中每个词语出现的次数。 import org.apache.spark.ml.feature.{CountVectorizer,CountVectorizerModel}

val df = spark.createDataFrame(Seq(

(0,Array("a","b","c")),

(1,Array("a","b","b","c","a"))

)).toDF("id","words")

//从语料库中拟合CountVectorizerModel

val cvModel:CountVectorizerModel=newCountVectorizer()

.setInputCol("words")

.setOutputCol("features")

.setVocabSize(3)

.setMinDF(2)

.fit(df)

//或者,用先验词汇表定义CountVectorizerModel

val cvm =newCountVectorizerModel(Array("a","b","c"))

.setInputCol("words")

.setOutputCol("features")

cvModel.transform(df).show(false)

+---+---------------+-------------------------+

|id |words |features |

+---+---------------+-------------------------+

|0 |[a, b, c] |(3,[0,1,2],[1.0,1.0,1.0])|

|1 |[a, b, b, c, a]|(3,[0,1,2],[2.0,2.0,1.0])|

+---+---------------+-------------------------+

4.2 特征转换

在机器学习中,数据处理是一件比较繁琐的事情,需要对原有特征做多种处理,如类型转换、标准化特征、新增衍生特征等等,需要耗费大量的时间和精力编写处理程序,不过,自从Spark推出ML后,情况大有改观,Spark ML包中提供了很多现成转换器,例如:StringIndexer、IndexToString、OneHotEncoder、VectorIndexer,它们提供了十分方便的特征转换功能,这些转换器类都位org.apache.spark.ml.feature包下。

4.2.1分词器

分词器(Tokenization)将文本划分为独立个体(通常为单词)。 import org.apache.spark.ml.feature.{RegexTokenizer,Tokenizer}

import org.apache.spark.sql.functions._

val sentenceDataFrame = spark.createDataFrame(Seq(

(0,"Hi I heard about Spark"),

(1,"I wish Java could use case classes"),

(2,"Logistic,regression,models,are,neat")

)).toDF("id","sentence")

val tokenizer =newTokenizer().setInputCol("sentence").setOutputCol("words")

val regexTokenizer =newRegexTokenizer()

.setInputCol("sentence")

.setOutputCol("words")

.setPattern("\\W")//或者使用 .setPattern("\\w+").setGaps(false)

val countTokens = udf {(words:Seq[String])=> words.length }

val tokenized = tokenizer.transform(sentenceDataFrame)

tokenized.select("sentence","words")

.withColumn("tokens", countTokens(col("words"))).show(false)

+-----------------------------------+------------------------------------------+------+

|sentence |words |tokens|

+-----------------------------------+------------------------------------------+------+

|Hi I heard about Spark |[hi, i, heard, about, spark] |5 |

|I wish Java could use case classes |[i, wish, java, could, use, case, classes]|7 |

|Logistic,regression,models,are,neat|[logistic,regression,models,are,neat] |1 |

+-----------------------------------+------------------------------------------+------+

val regexTokenized = regexTokenizer.transform(sentenceDataFrame)

regexTokenized.select("sentence","words")

.withColumn("tokens", countTokens(col("words"))).show(false)

+-----------------------------------+------------------------------------------+------+

|sentence |words |tokens|

+-----------------------------------+------------------------------------------+------+

|Hi I heard about Spark |[hi, i, heard, about, spark] |5 |

|I wish Java could use case classes |[i, wish, java, could, use, case, classes]|7 |

|Logistic,regression,models,are,neat|[logistic, regression, models, are, neat] |5 |

+-----------------------------------+------------------------------------------+------+

4.2.2 移除停用词

停用词为在文档中频繁出现,但未承载太多意义的词语,它们不应该被包含在算法输入中,所以会用到移除停用词(StopWordsRemover)。

示例:

假设我们有如下DataFrame,有id和raw两列 id raw

0 [I, saw, the, red, baloon]

1 [Mary, had, a, little, lamb]

通过对raw列调用StopWordsRemover,我们可以得到筛选出的结果列如下 id raw filtered

0 [I, saw, the, red, baloon] [saw, red, baloon]

1 [Mary, had, a, little, lamb] [Mary, little, lamb]

其中,“I”, “the”, “had”以及“a”被移除。

实现以上功能的详细代码: import org.apache.spark.ml.feature.StopWordsRemover

val remover = new StopWordsRemover()

.setInputCol("raw")

.setOutputCol("filtered")

val dataSet = spark.createDataFrame(Seq(

(0, Seq("I", "saw", "the", "red", "balloon")),

(1, Seq("Mary", "had", "a", "little", "lamb"))

)).toDF("id", "raw")

remover.transform(dataSet).show(false)

4.2.3 n-gram

一个n-gram是一个长度为整数n的字序列。NGram可以用来将输入转换为n-gram。 import org.apache.spark.ml.feature.NGram

val wordDataFrame = spark.createDa

你可能感兴趣的:(spark应用程序转换)