标记化是获取文本(例如句子)并将其分解为单个术语(通常是单词)的过程。 一个简单的 Tokenizer 类提供了这个功能。 下面的示例显示了如何将句子拆分为单词序列。
RegexTokenizer 允许基于正则表达式 (regex) 匹配的更高级的标记化。 默认情况下,参数“pattern”(正则表达式,默认值:“\\s+”)用作分隔输入文本的分隔符。 或者,用户可以将参数“gaps”设置为 false,表示正则表达式“pattern”表示“tokens”而不是拆分间隙,并找到所有匹配的出现作为标记化结果。
示例代码:(代码基于zeppelin平台实现)
%spark // 特征转换 —— —— Tokenizer和RegexTokenizer // Tokenizer可以将获取的文本简单拆分为单词 // RegexTokenizer 允许基于正则表达式 (regex) 匹配的更高级文本拆分 import org.apache.spark.ml.feature.{RegexTokenizer, Tokenizer} import org.apache.spark.sql.SparkSession 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 = new Tokenizer().setInputCol("sentence").setOutputCol("words") // RegexTokenizer默认情况下,参数“pattern”(正则表达式,默认值:“\\s+”) // \\s表示 空格,回车,换行等空白符, +号表示一个或多个的意思 val regexTokenizer = new RegexTokenizer() .setInputCol("sentence") .setOutputCol("words") .setPattern("\\W") // alternatively .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) 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] |1 | +-----------------------------------+------------------------------------------+------+ +-----------------------------------+------------------------------------------+------+ |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 | +-----------------------------------+------------------------------------------+------+
停用词是应该从输入中排除的词,通常是因为这些词经常出现并且没有太多意义。 StopWordsRemover 将字符串序列(例如 Tokenizer 的输出)作为输入,并从输入序列中删除所有停用词。 停用词列表由 stopWords 参数指定。 某些语言的默认停用词可以通过调用 StopWordsRemover.loadDefaultStopWords(language) 来访问,可用的选项是“丹麦语”、“荷兰语”、“英语”、“芬兰语”、“法语”、“德语”、“匈牙利语”、 “意大利语”、“挪威语”、“葡萄牙语”、“俄语”、“西班牙语”、“瑞典语”和“土耳其语”。 布尔参数 caseSensitive 指示匹配项是否应区分大小写(默认为 false)。
示例代码:
%spark // 特征转换 —— —— StopWordsRemover // StopWordsRemover 将字符串序列(例如 Tokenizer 的输出)作为输入,并从输入序列中删除所有停用词。 // 停用词列表由 stopWords 参数指定。 import org.apache.spark.ml.feature.StopWordsRemover val remover = new StopWordsRemover() .setInputCol("raw") .setOutputCol("filtered") .setStopWords(Array("saw","lamb")) //要求输入的参数类型为StringArray 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) 输出: +---+----------------------------+----------------------+ |id |raw |filtered | +---+----------------------------+----------------------+ |0 |[I, saw, the, red, balloon] |[I, the, red, balloon]| |1 |[Mary, had, a, little, lamb]|[Mary, had, a, little]| +---+----------------------------+----------------------+
n-gram 是一个整数 n 的 n 个标记(通常是单词)的序列。 NGram 类可用于将输入特征转换为 n-gram。 NGram 将字符串序列(例如 Tokenizer 的输出)作为输入。 参数 n 用于确定每个 n-gram 中的项数。 输出将由一系列 n-gram 组成,其中每个 n-gram 由 n 个连续单词的空格分隔字符串表示。 如果输入序列包含少于 n 个字符串,则不产生输出。
简单来说,N-Gram是一种基于统计语言模型的算法,它的基本思想是将文本里面的内容按照字节进行大小为N的滑动窗口操作,形成了长度是N的字节片段序列。
示例代码:
// 特征转换 —— —— n-gram // N-Gram是一种基于统计语言模型的算法。它的基本思想是将文本里面的内容按照字节进行大小为N的滑动窗口操作,形成了长度是N的字节片段序列。 import org.apache.spark.ml.feature.NGram val wordDataFrame = spark.createDataFrame(Seq( (0, Array("Hi", "I", "heard", "about", "Spark","hello")), (1, Array("I", "wish", "Java", "could", "use", "case", "classes")), (2, Array("Logistic", "regression", "models", "are", "neat")) )).toDF("id", "words") // N默认为2 val ngram = new NGram().setN(3).setInputCol("words").setOutputCol("ngrams") val ngramDataFrame = ngram.transform(wordDataFrame) ngramDataFrame.show(false) 输出: +---+------------------------------------------+--------------------------------------------------------------------------------+ |id |words |ngrams | +---+------------------------------------------+--------------------------------------------------------------------------------+ |0 |[Hi, I, heard, about, Spark, hello] |[Hi I heard, I heard about, heard about Spark, about Spark hello] | |1 |[I, wish, Java, could, use, case, classes]|[I wish Java, wish Java could, Java could use, could use case, use case classes]| |2 |[Logistic, regression, models, are, neat] |[Logistic regression models, regression models are, models are neat] | +---+------------------------------------------+--------------------------------------------------------------------------------+
二值化是将数值特征阈值化为二值(0/1)特征的过程。 Binarizer 采用公共参数 inputCol 和 outputCol,以及二值化的阈值。 大于阈值的特征值被二值化为1.0; 等于或小于阈值的值被二值化为 0.0。 inputCol 支持 Vector 和 Double 类型。
示例代码:
%spark // 特征转换 —— —— Binarizer // Binarizer是将数值特征化为二值(0/1)特征的过程 import org.apache.spark.ml.feature.Binarizer val data = Array((0, 0.1), (1, 0.8), (2, 0.2)) val dataFrame = spark.createDataFrame(data).toDF("id", "feature") val binarizer: Binarizer = new Binarizer() .setInputCol("feature") .setOutputCol("binarized_feature") // 用于二值化连续特征的阈值参数。 大于阈值的特征,将被二值化为 1.0。 等于或小于阈值的特征将被二值化为 0.0。 默认值:0.0 .setThreshold(0.5) val binarizedDataFrame = binarizer.transform(dataFrame) println(s"Binarizer output with Threshold = ${binarizer.getThreshold}") binarizedDataFrame.show() 输出: Binarizer output with Threshold = 0.5 +---+-------+-----------------+ | id|feature|binarized_feature| +---+-------+-----------------+ | 0| 0.1| 0.0| | 1| 0.8| 1.0| | 2| 0.2| 0.0| +---+-------+-----------------+
PCA 是一种统计过程,它使用正交变换将一组可能相关变量的观察值转换为一组称为主成分的线性不相关变量值。 PCA 类训练模型以使用 PCA 将向量投影到低维空间。 下面的示例展示了如何将 5 维特征向量投影到 3 维主成分中。
示例代码:
%spark // 特征转换 —— —— PCA // 数据降维就是一种对高维度特征数据预处理方法。 // 降维是将高维度的数据保留下最重要的一些特征,去除噪声和不重要的特征,从而实现提升数据处理速度的目的。 import org.apache.spark.ml.feature.PCA import org.apache.spark.ml.linalg.Vectors val data = Array( Vectors.sparse(5, Seq((1, 1.0), (3, 7.0))), Vectors.dense(2.0, 0.0, 3.0, 4.0, 5.0), Vectors.dense(4.0, 0.0, 0.0, 6.0, 7.0) ) val df = spark.createDataFrame(data.map(Tuple1.apply)).toDF("features") val pca = new PCA() .setInputCol("features") .setOutputCol("pcaFeatures") // 主成分的数量,这个参数必须要有 .setK(3) .fit(df) val result = pca.transform(df).select("pcaFeatures") result.show(false) 输出: +-----------------------------------------------------------+ |pcaFeatures | +-----------------------------------------------------------+ |[1.6485728230883807,-4.013282700516296,-5.524543751369388] | |[-4.645104331781534,-1.1167972663619026,-5.524543751369387]| |[-6.428880535676489,-5.337951427775355,-5.524543751369389] | +-----------------------------------------------------------+
多项式扩展是将您的特征扩展为多项式空间的过程,该空间由原始维度的 n 次组合制定。 PolynomialExpansion 类提供此功能。 下面的示例展示了如何将特征扩展到 3 次多项式空间。
示例代码:
%spark // 特征转换 —— —— PolynomialExpansion // 是一个将特征展开到多元空间的处理过程 // 多项式展开形式如:(x,y)的三次展开(x,x^2,x^3,y,x*y,x^2*y,y^2,x*y^2,y^3) import org.apache.spark.ml.feature.PolynomialExpansion import org.apache.spark.ml.linalg.Vectors val data = Array( Vectors.dense(2.0, 1.0), Vectors.dense(0.0, 0.0), Vectors.dense(3.0, -1.0) ) val df = spark.createDataFrame(data.map(Tuple1.apply)).toDF("features") val polyExpansion = new PolynomialExpansion() .setInputCol("features") .setOutputCol("polyFeatures") // 要展开的多项式次数,应大于等于 1。值为 1 表示不展开。 默认值:2 .setDegree(3) val polyDF = polyExpansion.transform(df) polyDF.show(false) 输出: +----------+------------------------------------------+ |features |polyFeatures | +----------+------------------------------------------+ |[2.0,1.0] |[2.0,4.0,8.0,1.0,2.0,4.0,1.0,2.0,1.0] | |[0.0,0.0] |[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0] | |[3.0,-1.0]|[3.0,9.0,27.0,-1.0,-3.0,-9.0,1.0,3.0,-1.0]| +----------+------------------------------------------+
离散余弦变换,属于傅里叶变换的一种。主要运用于数据或图像的压缩。其将时域中长度为 N 的实数值序列变换为频域中长度为 N 的实数值序列。
示例代码:
import org.apache.spark.ml.feature.DCT import org.apache.spark.ml.linalg.Vectors val data = Seq( Vectors.dense(0.0, 1.0, -2.0, 3.0), Vectors.dense(-1.0, 2.0, 4.0, -7.0), Vectors.dense(14.0, -2.0, -5.0, 1.0)) // Tuple1就是只包含一个元素的Tuple,也就是一元组. // 那么可以任意表达包含n个元素的Tuple吗?答案是否定的。Scala只定义了Tuple1~Tuple22共22个Tuple val df = spark.createDataFrame(data.map(Tuple1.apply)).toDF("features") val dct = new DCT() .setInputCol("features") .setOutputCol("featuresDCT") // 指示是执行反向 DCT (true) 还是正向 DCT (false)。 默认值:false .setInverse(false) val dctDf = dct.transform(df) dctDf.select("featuresDCT").show(false) 输出: +----------------------------------------------------------------+ |featuresDCT | +----------------------------------------------------------------+ |[1.0,-1.1480502970952693,2.0000000000000004,-2.7716385975338604]| |[-1.0,3.378492794482933,-7.000000000000001,2.9301512653149677] | |[4.0,9.304453421915744,11.000000000000002,1.5579302036357163] | +----------------------------------------------------------------+