特征中有三种算法:ChiSqSelector、VectorSlicer和RFormula为特征选择方法;
有三种方法:CountVectorizer、TF-IDF和Word2Vec组成三种文本特征抽取方法;
其余方法为特征变换。
特征变换又分5个类:
对于建立模型而言并非特征越多越好,因为建模的目标是使用尽量简单的模型去实现尽量好的效果。减少一些价值小贡献小的特征有利于在表现效果不变或降低度很小的前提下,找到最简单的模型。我们之所以用机器学习的模型去学习特征,是为了更好地预测被特征影响着的应变量(标签)。那么那些根本不会对应变量产生影响或者影响很小的特征理应事先去掉。
对于如何判断特征对应变量的影响程度大小问题,我们可以使用卡方检验对特征与应变量进行独立性检验,如果独立性高,那么表明两者没太大关系,特征可以舍弃;如果独立性小,两者相关性高,则说明该特征会对应变量产生比较大的影响,应当选择。如化妆不化妆与性别相关性问题。
ChiSqSelector用于使用卡方检验来选择特征(降维)。
VectorSlicer用于从原来的特征向量中切割一部分,形成新的特征向量,比如,原来的特征向量长度为10,我们希望切割其中的5~10作为新的特征向量,使用VectorSlicer可以快速实现。
VectorSlicer是一个处理特征向量的变换器,并输出一个新的原始特征子集的特征向量。从向量列中提取特征,VectorSlicer接受具有指定索引的向量列,然后输出一个新的向量列,其值通过这些索引进行选择。有两种类型的索引:
RFormula用于将数据中的字段通过R语言的Model Formulae转换成特征值,输出结果为一个特征向量和Double类型的label。当前版本中,RFormula仅支持部分R操作,包括:~ . : + _ 如:假设有a,b两列作为2个特征,y是应变量,则y ~ a + b表示线性模型:y ~ w0 + w1 * a + w2 * b,其中w0是截距。
CountVectorizer和CountVectorizerModel旨在通过计数来讲一个文档转换为向量。当不存在先验字典时,CountVectorizer可作为Estimator来提取词汇,并生成一个CountVectorizerModel。该模型产生文档关于词语的稀疏表示,其表示可以传递给其他算法如LDA。
在fitting过程中,CountVectorizer将根据语料库中的词频排序选出前vocabsize个词。一个可选的参数minDF也影响fitting过程,它指定词汇表中的词语在文档中最少出现的次数。另一个可选的二值参数控制输出向量,如果设置为真,那么所有非零的计数为1,这对二值型离散概率模型非常有用。
TF - IDF是一种统计方法,用以评估一个字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
目前,真正的搜索引擎等实际应用中广泛使用的是TF-IDF模型,该模型的主要思想是:如果词w在一篇文档d中出现的频率高,并且在其他文档中很少出现,则认为词w具有很好的区分能力,适合用来把文章d和其他文章区分开来。该模型主要包含了两个因素:
TF - IDF模型根据TF和IDF为每一个文档d和由关键词w(1,2...)组成的查询串q计算一个权值,用于表示查询串q与文档d的匹配度:TF - IDF = TF * IDF。
Word2Vec,字面意思,将Word转化为Vector,Word是顺序有意义的实体,比如文档中单词。Word2Vec得到实体向量,可以用来度量实体间相似度,在此基础上可用于分类、聚类、推荐等等方向中。
Word2Vec有两种实现方式,二者模型互为镜像:
Word2Vec是一个Estimator(评估器),它采用一系列代表文档的词语来训练Word2VecModel。该模型将每个词语映射到一个固定大小的向量。Word2VecModel使用文档中每个词语的平均数来将文档转换为向量,然后这个向量可以作为预测的特征,来计算文档相似度计算等等。
Tokenization(文本符号化)是将文本拆分成单词的过程。RegexTokenizer提供了基于正则表达式(regex)匹配的更高级的单词拆分。默认情况下,参数“pattern”(默认的正则表达式:“\\s+”)作为分隔符用于拆分输入的文本。或者,用户可以将参数“gaps”设置为false,指定正则表达式“pattern”表示“tokens”,而不是分隔符,并且作为分词结果找到的所有匹配项。
Stop Words是在文档中频繁出现,但未携带太多意义的词语,它们不应该参与算法运算。Stop Words Remover的作用是将输入的字符串(如分词器Tokenizer的输出)中的停用字删除后输出。停用字表由StopWords参数指定。对于某些语言的默认停止词是通过调用StopWordsRemover.loadDefaultStopWords(language)设置的,可用的选项为“丹麦语”,“荷兰语”,“英语”,“芬兰语”,“法语”,“德语”,“意大利语”,“匈牙利语”,“挪威语”,“葡萄牙语”,“俄语”,“西班牙语”,“瑞典语”和“土耳其语”。布尔类型参数caseSensitive指示是否区分大小写(默认为否)。
一个n-gram是一个长度为n(整数)的字的序列。NGram的输入为一系列的字符串(如:Tokenizer分词器的输出)。参数n表示每个n-gram构成的序列,其中,每个n-gram表示被空格分割出来的n个连续的单词。如果输入的字符串少于n个单词,NGram输出为空。
n-gram代表由n个字组成的句子。利用上下文中相邻词间的搭配信息,在需要把连续无空格的拼音、笔划,或代表字母或笔划的数字,转换成汉字串(即句子)时,可以计算出具有最大概率的句子,从而实现到汉字的自动转换,无需用户手动选择,避开了许多汉字对应一个相同的拼音(或笔划串,或数字串)的重码问题。N-Gram模型用于中文,称为汉语语言模型CLM。该模型基于这样的假设,第n个词的出现只与前面N-1个词相关,而与其他任何词都不相关,整句话的概率就是各个词出现概率的乘积。这些词的概率可以通过直接从语料库中统计N个词同时出现的次数得到。
假设语句T是由词序列W1,W2,W3,…Wn组成的,那么
P(T)=P(W1W2W3Wn)=P(W1)P(W2|W1)P(W3|W1W2)…P(Wn|W1W2…Wn-1)
这种方法缺点:1.参数空间过大,不容易实用化。2.数据稀疏严重。
二值化(Binarization)是通过选定的阈值,将数值化的特征转换成二进制(0/1)特征表示的过程。Binarizer涉及的参数有inputCol(输入)、outputCol(输出)以及threshold(阈值)。输入的特征值大于阈值将映射为1.0,特征值小于等于阈值将映射为0.0.Binarizer支持向量(Vector)和双精度(Double)类型的输出。
分箱(分段处理):将连续数值转换为离散类别。
同样是连续型变量,如果分成两类还不够,同样也可以分成多类。
二元转换的时候需要给出一个阀值,在多元换转换中,如果要分成n类,就要给出n+1个阀值组成的array,任意一个数都可以被放在某两个阀值的区间内,就像把它放进属于它的桶中,故称为分箱策略。
比如有x,y两个阀值,那么他们组成的区间是[x,y)的前闭后开区间;对于最后一个区间是前闭后闭区间。
给出的这个阀值array,里面的元素必须是递增的。如果在转换的过程中有一个数没有被包含在然后区间内,那么就会报错,所以,如果不确定特征值的最小与最大值,那么就添加Double.NegativeInfinity(负无穷)和Double.PositiveInfinity(正无穷)到array的两侧。
与上面两个方法一样,QuantileDiscretizer(分位数离散化)也是将一列连续型的数据列转成分类型数据。通过取一个样本的数据,并将其分为大致相等的部分,设定范围。其下限为 -Infinity(负无重大) ,上限为+Infinity(正无重大)。
分级的数量由numBuckets参数决定。分级的范围有渐进算法决定。渐进的精度由relativeError参数决定。当relativeError设置为0时,将会计算精确的分位点(计算代价较高)。
但如果样本数据只划分了3个区间,此时设置numBuckets为4,则仍只划分为3个区间。
在训练模型的时候,要输入features,即因子,也叫特征。对于同一个特征,不同的样本中的取值可能会相差非常大,一些异常小或异常打的数据会误导模型的正确训练;另外,如果数据的分布很分散也会影响训练结果。以上两种方式都体现在方差会非常大。此时,我们可以将特征中的值进行标准差标准化,即转换为均值为0、方差为1的正态分布。所以在训练模型之前,一定要对特征的数据分布进行探索,并考虑是否有必要将数据进行标准化。
标准差标准化也成Z-zero标准化,经过处理的数据会符合标准正态分布,即均值为0、方差为1.转化函数为: x* = (x - μ) / δ。公式中标准化后的值x*等于原来的值x先减去原数据的均值μ,然后再除以源数据的标准差δ,最后得到的新数据的均值就是0、方差/标准差为1.
它需要如下参数:
1. withStd:默认值为真,将数据缩放到统一标准差方式。
2. withMean:默认为假。将均值为0。该方法将产出一个稠密的输出向量,所以不适用于稀疏向量。
StandardScaler是一个Estimator,它可以通过拟合(fit)数据集产生一个StandardScalerModel,用来统计汇总。StandardScalerModel可以用来将向量转换至统一的标准差以及(或者)零均值特征。注意如果特征的标准差为零,则该特征在向量中返回的默认值为0.0。
注:是否要进行标准化,要根据具体实验而定。如果特征非常稀疏,并且有大量的0,Z-score标准化的过程几乎就是一个除0的过程,结果不可预料。
归一化就是将所有特征值都等比地缩小到0-1之间的区间内。其目的与标准化类似,为了使特征都在相同的规模中。sparkml提供两种方式:MinMaxScaler,MaxAbsScaler。
将一个特征中最大的值转换为1,最小的那个值转换为0,其余的值按照一定比例分布在(0,1)之间。计算公式如下:
注意,如果原来是稀疏矩阵,因为原来的0转换后会不在是0,而只有最小值才是0,所以转换后价格形成一个密集矩阵。
注意:(1)最大最小值可能受到离群值的左右。(2)零值可能会转换成一个非零值,因此稀疏矩阵将变成一个稠密矩阵。
将一个特征中的值规模化到(-1, 1)的区间内。将每一个数都除以特征值中的最大绝对数。 这样的做法并不会改变原来为0的值,所以也不会改变稀疏性。
有没有遇到过这样的情景,训练模型的时候误差非常小,但是在测试模型的时候误差就大了,也就是我们的模型复杂到可以拟合到我们的所有训练样本了,但在实际预测新的样本的时候,糟糕的一塌糊涂。而优秀的模型往往是在简单的基础上最小化误差,因此,可以使用范数规则化去约束模型。
为了避免出现过度拟合的问题,我们通过这些范数规则去约束我们原始的特征数据。这个过程被称之“Normalizer”。
Normalizer是一个转换器,它可以将一组特征向量(通过计算p-范数)规范化。参数为p(默认值:2)来指定规范化中使用的p-norm。规范化操作可以使输入数据标准化,这种归一化可以帮助标准化输入数据并改进学习算法的行为。
智能乘积(Elementwise Product)又称哈达玛积(Hadamard Product)。在训练模型的时候,经常会遇到这样的情况,特征之间的规模相差悬殊,对模型的训练产生了误导。此时我们需要人为的去平衡特征之间的规模,使他们都在同一个规模等级上,比如将0-1之间的特征,和100-1000之间的特征都分别乘以10,和除以100,使得两个特征的规模都在1-10之间。这个处理其实和归一化很像,只是归一化是使得所有的数据都在0-1之间分布。要注意的是规模化并不是保证所有数据一定落在某个区间内,而只是将不同的特征规模尽量放在一个水平上。
另一种情况,如果在特征中,有些特征特别重要,有些则相对重要度较低,那么需要给重要的特征以较高的权重,也可以使用本方法,将特征都乘上对应的权重从而形成新的特征组。具体如何处理就要看具体情况的需求了。
ElementwiseProduct对输入向量的每个元素乘以一个权重(weight),即对输入向量每个元素逐个进行放缩。对输入向量v 和变换向量scalingVec 使用Hadamard product(阿达玛积)进行变换,最终产生一个新的向量。用向量 w 表示 scalingVec ,则Hadamard product可以表示为
Interaction是一个变换器,它使用向量或双值列,并生成单个向量列,其中包含每个输入列的一个值的所有组合的乘积。例如,如果有两个向量类型列,每个列有三个维度作为输入列,那么将获得一个9维向量作为输出列。(类似笛卡尔积)
多项式扩展(Polynomial Expansion)是将n维的原始特征组合扩展到多项式空间的过程。如:线性回归中,有2个特征x1,x2,可以根据这两个特征建立回归方程:y = a0 + a1x1 + a2x2.如果将特征进行3维转换,多项式扩展后便从(x1, x2)变成了(x1, x2)^3.展开后就是:(x1, x1^2, x1^3, x2, x2^2, x2^3, x1x2, x1^2x2, x1x2^2)。结果就是2个特征进行3维多项式扩展变成了9个特征,就可以进行非线性分布的预测了。
当维度越高的时候,对样本点的拟合可能就越精准。但是,并不是维度越高越好,因为会造成对训练集的过拟合,从而丧失了模型的泛化能力。
StringIndexer(字符串-索引变换)将字符串的标签编码成标签索引。标签索引序列的取值范围是[0, numLabels(字符串中所有出现的单词去掉重复的词之后总和)],按照标签出现的频率排序,出现最多的标签索引为0.如果输入的是数值型数据,则会先将数值映射到字符串,再对字符串进行索引化。如果下游的管道节点(如:Estimator或者Transformer)需要用到索引化后的标签序列,则需要将输入列名称指定为索引化序列的名称。大部分情况下,通过setInputCol设置输入的列名。
它能够自动判断那些特征是离散值型的特征,并对他们进行编号,具体做法是通过设置一个maxCategories,特征向量中某一个特征不重复取值个数小于maxCategories,则被重新编号为0~K(K<=maxCategories-1)。某一个特征不重复取值个数大于maxCategories,则该特征视为连续值,不会重新编号(不会发生任何改变)。
有的时候我们通过一个数据集构建了一个StringIndexer,然后准备把它应用到另一个数据集上的时候,会遇到新数据集中有一些没有在前一个数据集中出现的标签,这时候一般有两种策略来处理:第一种是抛出一个异常(默认情况下),第二种是通过掉用 setHandleInvalid("skip")来彻底忽略包含这类标签的行。
Index To String(索引-字符串变换)与StringIndexer对应, 对称的,IndexToString的作用是把标签索引的一列重新映射回原有的字符型标签。一般都是和StringIndexer配合,先用StringIndexer转化成标签索引,进行模型训练,然后在预测标签的时候再把标签索引转化成原有的字符标签。当然,也允许你使用自己提供的标签。
Vector Indexer对数据集特征向量中的类别特征进行编号索引,它能够自动判断哪些特征是可以重新编号的类别型,并对他们进行重新编号索引。处理流程如下:
独热编码是指把一列标签索引映射成一列二进制数组,且最多的时候只有一位有效。这种编码适合一些期望类别为连续特征的算法,比如逻辑回归。
One-Hot编码,又称为一位有效编码,主要是采用位状态寄存器来对个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。 在实际的机器学习的应用任务中,特征有时候并不总是连续值,有可能是一些分类值,如性别可分为“male”和“female”。在机器学习任务中,对于这样的特征,通常我们需要对其进行特征数字化,如下面的例子: 有如下三个特征属性:
性别:["male","female"]
地区:["Europe","US","Asia"]
浏览器:["Firefox","Chrome","Safari","Internet Explorer"]
对于某一个样本,如["male","US","Internet Explorer"],我们需要将这个分类值的特征数字化,最直接的方法,我们可以采用序列化的方式:[0,1,3]。但是这样的特征处理并不能直接放入机器学习算法中。
对于上述的问题,性别的属性是二维的,同理,地区是三维的,浏览器则是四维的,这样,我们可以采用One-Hot编码的方式对上述的样本“["male","US","Internet Explorer"]”编码,“male”则对应着[1,0],同理“US”对应着[0,1,0],“Internet Explorer”对应着[0,0,0,1]。则完整的特征数字化的结果为:[1,0,0,1,0,0,0,0,1]。这样导致的一个结果就是数据会变得非常的稀疏。 One-Hot Encoding 作用也就是为了将特征数字化为一个特征向量。
Vector Assembler是一个转换器,它将给定的若干列合并为单列向量。它可以将原始特征和一系列通过其他转换器变换得到的特征合并为单一的特征向量,来训练如逻辑回归和决策树等机器学习算法。
Vector Assembler可接受的输入列类型:数值型、布尔型、向量型。输入列的值将按自定顺序依次添加到一个新向量中。
SQLTransformer用来转换由SQL定义的陈述。目前仅支持SQL语法如"SELECT ... FROM __THIS__ ...",其中"__THIS__"代表输入数据的基础表。选择语句指定输出中展示的字段、元素和表达式,支持Spark SQL中的所有选择语句。用户可以基于选择结果使用Spark SQL建立方程或者用户自定义函数(UDFs)。SQLTransformer支持语法示例如下:
主成分分析(PCA)是一种对数据进行旋转变换的统计学方法,其本质是在线性空间中进行一个基变换,使得变换后的数据投影在一组新的“坐标轴”上的方差最大化,随后裁剪屌变换后方差很小的“坐标抽”,剩下的新“坐标轴”即被称为主成分(Principal Component),它们可以在一个较低维度的子空间中尽可能地表示原有数据的性质。主成分分析是常见的降维方法之一,被广发应用在各种统计学、机器学习问题中,常见的数据降维的方法还有因子分析和独立成分分析。
PCA通过计算协方差矩阵进行实现的步骤:
注:PCA适用于数值型数据,且MLlib提供的PCA变换方法最多只能处理65535(2^16 - 1)维的数据。
离散余弦变换(DCT)是与傅里叶变换相关的一种变换,它与离散傅里叶变换相似,但是只使用实数。这种变换经常被信号处理和图像处理使用,用于对信号和图像(包括静止图像和运动图像)进行有损压缩。
一维DCT变换共有8中,常见的一种:
其中N是一维数据的元素总数,c(u)系数使得DCT变换矩阵成为正交矩阵,正交特性在二维DCT变换中能更体现其优势。一维DCT变换的复杂度是O(n^2)。二维DCT变换是在一维DCT变换的基础上再进行一次DCT变换,复杂度为O(n^4)。
返回主目录(Spark MLlib算法思想总结)