这一节主要理解机器学习的特征抽取需要以及一些常用的特征抽取方法。这里会以Sklearn为主,也会结合下spark java版本的ml包,看下机器学习的特征抽取是怎么做的。以及在python和java中最典型的实现是怎样的。
sklearn中 使用sklearn.datasets来加载流行的数据集
datasets.load_*():获取小规模数据集,这些数据集在sklearn的本地包中。 如 load_iris()
datasets.fetch_*(data_home=None,subset='all'): 从网络上获取大规模数据集
data_home: 下载路径。默认在 ~/sckit_learn_data/
subset: train > 训练集 , test > 测试集, all > 全部集合
load和fetch返回的数据类型是 datasets.bae.Bunch。这个Bunch继承自字典类型,可以像字典一样使用[ATTR]来访问属性。另外,也可以用 .ATTR 的方式访问属性名。
返回的Bunch中包含的属性有:
data: 特征数据
target:标签数组
DESCR: 数据描述
feature_names:特征名
target_names:标签名
为了检验模型效果,通常需要将数据集划分为训练集与测试集
sklearn中 model_selection 包主要负责模型特征抽取
sklearn.model_selection.train_test_split(arrays,*options)
test_size 测试集的大小,一般为float。 默认是0.25
random_state 随机数种子,不同的种子会造成不同的随机采样结果。
return(顺序很重要): 训练集特征值x_train,测试集特征值y_train,训练集目标值x_test,测试集目标值y_test
而在spark中,一般的处理方式是将数据整理成RDD< LabelPoint>的结构,然后用randomSplit方法来切分训练集和数据集。
影响模型结果的因素: 数据,算法(常用的公开算法) 特征工程
数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限。
机器学习本质是统计学方法 ,只能处理数字类型的数据,因此,对于文本、图像、视频等其他类型的数据,都需要转换成数字类型才能被机器学习处理。
python中常用特征抽取工具:sklearn 特征工程。 pandas: 数据清洗、数据处理
通常方法:特征抽取 特征预处理 特征降维
对于字典类型的数据特征,例如 性别、城市、颜色这一类字典类型数据,通常在数据库中,会以一个数字编码标识,如 0:男,1:女 这样。但是,如果在机器学习中使用这样的数字编码,就会给学习过程造成误解。因为不同的字典值特性应该是完全“平等”,而如果是 0,1,2这样的数字,则可能给机器学习造成误解,觉得这些字典值是有大小关系的。所以,机器学习中常用的方式是把字典值处理成one-hot编码。
性别=男 | 性别=女 | one-hot编码 | |
---|---|---|---|
男 | 1 | 0 | (1,0) |
女 | 0 | 1 | (0,1) |
sklearn.feature_extraction.DictVectorizer(sparse=True,....)
sparse:稀疏矩阵。 稀疏矩阵只表明矩阵中非0数字的坐标,而非稀疏矩阵就是一个完整的矩阵。稀疏矩阵在字典值非常多时,能节省存储空间。
DicVectorizer.fit_transform(X) X:字典或者包含字典的迭代器。 返回sparse矩阵
DicVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格式。
DicVectorizer.get_feature_names() 返回类别名称
见spark官方Demo(在spark安装目录下)中 org.apache.spark.examples.ml.JavaOneHotEncoderExample
对于文本类型的数据,如一篇文章。在做机器学习时,最基础的处理方式是以文章中的单词出现次数作为特征。处理成 [(word1,count1),(word2,count2)…]这样的格式。这也是mapreduce、spark最经典的入门计算方式。
sklearn.feature_extraction.text.CountVectorizer(stop_words=[]) 返回词频矩阵
stop_words:停用词。可以选择不统计哪些词。比如 to is am the 这些
CountVectorizer.fit_transform(X) X:文本或者包含文本字符串的可迭代对象 返回sparse矩阵
CountVectorizer.inverse_transform(X) X:array数据或者sparse矩阵。 返回转换前的矩阵
CountVectorizer.get_feature_names(): 返回:单词列表
sklearn中的实现只按空格分隔,统计样本中词的出现次数。同时在统计时会将样本中标点符号以及单字母单词去掉
CountVectorizer ,示例见 org.apache.spark.examples.ml.JavaCountVectorizerExample
优点::快速,简单。
缺点:在文章分类等机器学习场景中,体现不出文章的重要特征。例如一般出现次数最多的一些词,如,这里、那里、我们、他们等,并不能体现文章的内容特征。
在对文本进行特征处理时,一般分词是个绕不开的坎。英文分词比较简单,按空格就行。而中文则麻烦得多。java里试过hanlp , python里试过jieba。尝试过分别用这两个包来拆分鹿鼎记,里面对于名字、武功等都要做很多特殊处理,如西奥图三世、白衣尼等,拆分的结果还是以jieba更为简单高效。而对于一些更为专业的文章,这些开源的中文分词工具就都表现不是很好了。
TF-IDF可以用来评估一个字词对于一个文件集合或者一个语料库中的其中一份文件的重要程度。例如,在对一大堆文章进行分类时,出现 计算机、软件、云、java这些词的次数比较多的文章更多可能归为科技类(在其他类中出现就比较少,这样的词才有重要性),而出现 银行、信贷、信用卡 这类词出现次数较多的文章更多可能归为金融类。而所有文章中出现次数都比较多的 我们、你们、这里、那里等这一类的词则对分类来说,意义不大。
· TF-IDF由TF和IDF两部分组成,
TF:词频 term frequency。某一个给定的词语在文章中出现的评率
IDF:逆向文档评率 inverse document frequency.是一个词语普遍重要性的度量。 为总文件数目 除以 包含该词语的文件的数量,再取 10为底对数。
最终 TF-IDF=TF*IDF
关键词:“经济”;语料库: 1000篇文章;10篇文章出现“经济”。
TF(经济) = 10/1000 = 0.01 ;IDF(经济)=lg(1000/10)=2
最终 TF-IDF(经济) = TF(经济)*IDF(经济) = 0.02
sklearn.feature_extraction.text.TfidfVectorizer(stop_words=None,....)
返回词的权重矩阵
TfidfVectorizer.fit_transform(X) X:文本或者包含文本字符串的可迭代对象 ; 返回sparse矩阵-可以用toarray方法返回完整矩阵。
TfidfVecotrizer.inverse_transform(X) 反向计算
TfidfVectorizer.get_feature_names(); 返回单词列表
spark中把Tfidf分为 HashingTF + IDF 两个部分。 见 org.apache.spark.examples.ml.JavaTfIdfExample
无量纲化:通过一些转换函数将不同量纲下的特征数据(不同范围,不同数量级)转换成更适合算法模型的特征数据。
目的:特征的单位或者大小相差较大,或者某些特征比其他特征要大出几个数量级时,这些大特征更容易影响支配目标结果,是的一些算法无法学习到数据整体的特征。 就是让不同单位的各个数据变得同样重要。
公式: X’ = (x-min)/(max-min); X’’ = X’*(mx-mi)
min: 样本集中的特征最小值;max:样本集中的特征最大值;mx mi分别为指定区间,默认值为 0,1
sklearn.preprocessing.MinMaxScaler(feature_range=(0,1),....)
MinMaxScalar.fit_transform(X)
X:numpy ndarray格式的数据[n_samples,n_features]
返回值: 转换后,形状相同的 array
MinMaxScalerModel 见 org.apache.spark.examples.ml.JavaMinMaxScalerExample
如果数据集中出现远离其他样本异常点,一般都会影响到最大值或者最小值(比整体数据大很多或者小很多),而这样就会影响到整个归一结果。因此,归一化只适合于传统精确的小数据场景。而在大数据场景,大都使用以下的 标准化处理。
标准化对元数据进行转换,将结果变换到均值为0,标准差为1的范围内。
公式: X’ = (x-mean)/std
mean为样本平均值,std为样本标准差
StandardScaler。API跟归一化差不多。
优点:少量的异常点对于样本整体的平均值和方差影响不会太大,从而对整个样本的结果影响也不会天大。适合于样本足够多的大数据场景。
降维概念:只对样本特征值(二维数组)减少特征个数。
特征选择: sklearn.feature_selection模块
Filter过滤式
1)方差选择法: 过滤低方差特征(过于集中的数据)
2)相关系数法:特征与特征之间的相关程度。例如 天气湿度 与 降雨量 一般就认为是相关性很强的特征。
Embeded嵌入式
1)决策树
2)正则化
3) 深度学习
方差选择法:特征方差太小,意味着这个特征的数据过于相近,学习分类的意义比较小。而方差选择法就是删除这一部分方差太小的特征。
### sklear API:
sklearn.feature_selection.VarianceThreshold(thredhold=0.0)
删除所有低方差特征
Variance.fit_transform(X)
X: numpay array格式的数据[n_samples,n_feature]
返回值: 训练集差异低于threshold的特征将被删除。默认值是保留所有非零方差特征。即删除所有样本中具有相同值的特征。
相关系数用来衡量特征之间的相关性。 有很多中方法。皮尔孙相关系数(Pearson Correlation Coefficient), 斯皮尔曼相关系数。
计算公式太过深奥,就不去管他了。
如皮尔孙相关系数 可以用API:scipy.pearsonr(x,y) 来计算
如果两个特征之间的相关性很强,一般有以下几种处理方式:
1)选取其中一个
2)加权求和,变成一个新特征
3)主成份分析
定义:一种将高维数据转换为低维数据的方法。保留对目标值结果影响较大的特征值,去掉相对影响较小的特征值。
作用:数据维度压缩,尽可能降低原数据的维数(特征个数),损失少量的信息。
作用:回归分析或聚类分析
理解:将高纬度数据投影到低纬度空间的过程。例如,一个(x,y)两维坐标点可以投影到一条y=f(x)的一维直线上,或者像皮影戏一样,将一个三维物体投影到一个二维平面上。高深的解释太复杂,最简单的理解就是特征个数太多,不好分析时,就可以用PCA来减少特征个数。
sklearn.decoposition.PCA(n_components=None)
将数据分解为低维数空间。
n_components:
小数:表示保留百分之多少的信息
整数:减少到多少个特征
PCA.fit_transform(X): X: numpay array格式的数据
返回值:转换后指定维度的array
sparkAPI:
PCAModel 见 org.apache.spark.examples.ml.JavaPCAExample
转换器(transformer)和预估器(estimator)是特征值处理中两个比较基础的概念,像上面很多操作都可以理解为是特定的转换器和预估器流程。在java中就可以理解为是两个父类。
1、实例化一个转换器类transformer
2、调用fit_transform进行数据转换。
实际上这可以分为两个步骤:fit()方法进行计算,确定转换器参数。 transform()方法进行最终的转换。
1、实例化一个estimator
2、estimator.fit(x_train,y_train) 计算 训练模型,调用完毕就会生成模型。
3、模型评估
1) 直接比对真实值和预测值
y_predict = estimator.predict(x_test) 生成预测值
y_test==y_predict 比对预测值与结果
2)计算准确率
accuracy = estimator.score(x_test,y_test)
以上为sklearn中的API总结。 spark中也有关于这两个概念的示例。 见 org.apache.spark.examples.ml.JavaEstimatorTransformerParamExample。
sklearn是python最经典的机器学习包,而spark是大数据领域最经典的一站式计算平台。但是,在机器学习中,sklearn是基于本地的numpy作为数据底层,而spark是基于分布式的RDD和DataFrame进行计算。虽然spark也有自己的python支持,但是封装感觉还是没有sklearn完善成熟。两者貌似不太好融合,而要结合两者的优势来进行机器学习,近期在github上有一个项目spark-sklearn就做了这样的事情,可以去参考一下。
pypi地址: https://pypi.org/project/spark-sklearn/
github地址: https://github.com/databricks/spark-sklearn