特征工程
1.定义
1.1为什么需要特征工程
- 样本数据中的特征有可能会存在缺失值,重复值,异常值等,需要对特征中的相关的噪点数据进行处理
- 处理目的:有一个更纯净的样本集,让模型基于这组数据可以有更好的预测能力…
1.2什么是特征工程
- 特征工程是将原始数据转换为更好的代表预测模型的潜在问题的特征过程,从而提高对未知数据预测的准确性
- 比如:AlphaGo学习的数据中既有棋谱,又有食谱和歌词,一些干扰数据绝对会影响AlphaGo的学习
1.3特征工程的意义
- 直接会影响模型预测的结果
1.4实现特征工程
- 工具:
sklearn
sklearn
介绍- 是python语言中的机器学习工具,包含了很多知名的机器学习算法的实现,其文档完善,容易上手
- 功能
- 分类模型
- 回归模型
- 聚类模型
- 特征工程
2.特征提取
2.1目的
-
采集到的样本中的特征数据往往很多时候为字符串或者其他类型的数据,电脑只可以识别二进制数值型的数据,如果把字符串给电脑,电脑不能识别【如果不是数值型数据,识别不了】
-
效果演示【将字符串转换为数字】
from sklearn.feature_extraction.text import CountVectorizer vector=CountVectorizer() res=vector.fit_transform(['lift is short,I love python','lift is too long,I hate python']) print(res.toarray()) # [[0 1 1 0 1 1 1 0] # [1 1 1 1 0 1 0 1]]
-
结论
- 特征抽取对文本等数据进行特征值化【将数据转为数值型数据】,特征值化是为了让机器更好的理解数据
2.2特征提取的方式
2.2.1字典特征提取
- 作用:对字典数据进行特征值化
from sklearn.feature_extraction import DictVectorizer
fit_transform(X) #X为字典或者包含字典的迭代器,返回值为sparse矩阵
inverse_transform(X) #X为sparse矩阵或者array数组,返回值为转换之前的数据格式
transform(X) #按照原先的标准转换
get_feature_names() #返回类别名称
- 示例代码
from sklearn.feature_extraction import DictVectorizer
alist=[
{"city":'AHui','temp':33},
{'city':'GZ','temp':42},
{'city':'SH','temp':40}
]
d=DictVectorizer() #实例化一个工具类对象
feature=d.fit_transform(alist) #返回一个sparse矩阵(存储的就是特征值化之后的结果)
print(feature)
# (0, 0) 1.0
# (0, 3) 33.0
# (1, 1) 1.0
# (1, 3) 42.0
# (2, 2) 1.0
# (2, 3) 40.0
print(d.get_feature_names())
# ['city=AHui', 'city=GZ', 'city=SH', 'temp']
print(feature.toarray())
# [[ 1. 0. 0. 33.]
# [ 0. 1. 0. 42.]
# [ 0. 0. 1. 40.]]
-
补充,sparse矩阵的理解
- 在
DictVectorizer
类的构造方法中设定sparse=False,则返回的就不是sparse矩阵,而是一个数组 - sparse矩阵就是一个变相的数组或者列表,目的是为了节省内存
- 在
-
示例代码
from sklearn.feature_extraction import DictVectorizer
alist=[
{"city":'AHui','temp':33},
{'city':'GZ','temp':42},
{'city':'SH','temp':40}
]
d=DictVectorizer(sparse=False)
#返回一个二维列表
fature=d.fit_transform(alist)
print(d.get_feature_names()) # ['city=AHui', 'city=GZ', 'city=SH', 'temp']
print(feature)
#输出结果:1为是,0为不是
# [[ 1. 0. 0. 33.]
# [ 0. 1. 0. 42.]
# [ 0. 0. 1. 40.]]
2.2.2 文本特征提取
-
作用:对文本数据进行特征值化
from sklearn.feature_extraction.text import CountVectorizer fit_transform(X) #X为文本或者包含文本字符串的可迭代对象,返回sparse矩阵 inverse_transform(X) #X为sparse矩阵或者array数组,返回值为转换之前的数据格式 toarray() #将sparse矩阵转化为数组
-
示例代码
from sklearn.feature_extraction.text import CountVectorizer vector=CountVectorizer() res=vector.fit_transform(['lift is is short,I love python','lift is too long,I hate python']) print(res)#sparse矩阵 # (0, 2) 1 # (0, 1) 2 # (0, 6) 1 # (0, 4) 1 # (0, 5) 1 # (1, 2) 1 # (1, 1) 1 # (1, 5) 1 # (1, 7) 1 # (1, 3) 1 # (1, 0) 1 print(vector.get_feature_names()) #['hate', 'is', 'lift', 'long', 'love', 'python', 'short', 'too'] print(res.toarray())#将sparse矩阵转换成数组 # [[0 2 1 0 1 1 1 0] # [1 1 1 1 0 1 0 1]] #注意:单字母不统计(因为单个字母代表不了实际含义),然后每个数字表示的是单词出现的次数
-
-
中文文本特征提取【对有标点符号的中文文本进行特征提取】
from sklearn.feature_extraction.text import CountVectorizer vector=CountVectorizer() res=vector.fit_transform(['人生苦短 我用python','人生满长,不用python']) print(res) # (0, 2) 1 # (0, 3) 1 # (1, 1) 1 # (1, 0) 1 print(vector.get_feature_names()) ['不用python', '人生满长', '人生苦短', '我用python'] print(res.toarray()) # [[0 0 1 1] # [1 1 0 0]]
-
中文文本特征提取【对有标点符合且有空格分隔的中文文本进行特征提取】【注意:单个汉字不统计】
from sklearn.feature_extraction.text import CountVectorizer vector=CountVectorizer() res=vector.fit_transform(['人生 苦短, 我 用python','人生 漫长, 不用 python']) print(res) # (0, 2) 1 # (0, 5) 1 # (0, 4) 1 # (1, 2) 1 # (1, 3) 1 # (1, 1) 1 # (1, 0) 1 print(vector.get_feature_names()) # ['python', '不用', '人生', '漫长', '用python', '苦短'] print(res.toarray()) # [[0 0 1 0 1 1] # [1 1 1 1 0 0]]
-
目前
CountVectorizer
只可以对有标点符号和用分隔符对应的文本进行特征提取,满足不了需求【在自然语言处理中,我们是需要将一段中文文本中相关的词语,成语,形容词…都要进行提取的】
2.2.3jieba分词
-
对中文文章进行分词处理
-
使用
#基本使用:对文章进行分词 import jieba jb = jieba.cut('我是一个好人') content = list(jb) ct = ' '.join(content) print(ct) #返回空格区分的词语
import jieba from sklearn.feature_extraction.text import CountVectorizer jb1=jieba.cut('人生苦短,我用python,你觉得我说的对吗?') ct1=" ".join(list(jb1)) print(ct1) # 人生 苦短 , 我用 python , 你 觉得 我 说 的 对 吗 ? jb2=jieba.cut('人生满长,不用python,你说我说的对不对?') ct2=" ".join(list(jb2)) print(ct2) # 人生 满长 , 不用 python , 你 说 我 说 的 对 不 对 ? vector=CountVectorizer() res=vector.fit_transform([ct1,ct2]) print(res) # (0, 2) 1 # (0, 5) 1 # (0, 3) 1 # (0, 0) 1 # (0, 6) 1 # (1, 2) 1 # (1, 0) 1 # (1, 4) 1 # (1, 1) 1 print(vector.get_feature_names()) # ['python', '不用', '人生', '我用', '满长', '苦短', '觉得'] print(res.toarray()) # [[1 0 1 1 0 1 1] # [1 1 1 0 1 0 0]]
2.3onhot编码
-
sparse矩阵中的0和1就是
onehot
编码[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dF8vyrS3-1643612347729)(assets/1.PNG)]
-
为什么需要
onehot
编码-
特征抽取主要目的就是对非数值型的数据进行特征值化!如果现在需要对下图中的human和alien进行手动特征值化Alien为4,human为1。则1和4有没有优先级或者权重大小之分呢?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P7c3FYns-1643612347731)(assets/2
.PNG)] -
就需要用
onehot
编码[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-11SUV0vP-1643612347732)(asset
s/3.PNG)] -
基于
pandas
实现onehot
编码【pd.get_dummies(df['col']
】import pandas as pd df=pd.DataFrame([ ['green','M',20,'class1'], ['red','L',21,"class2"], ['blue','XL',30,'class3'] ]) df.columns=['color','size','weight','class label'] #将color这一列变成one-hot编码 pd.get_dummies(df['color']) # blue green red # 0 0 1 0 # 1 0 0 1 # 2 1 0 0
-
3.特征值的预处理
-
对数值型数据进行处理
-
预处理就是用来实现无量钢化的方式
-
无量钢化:
- 在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布的需求,这种需求统称为将数据"无量纲化"
- 例如:
- 梯度和矩阵为核心的算法中;逻辑回归,支持向量机,神经网络,无量钢化可以加快求解速度;
- 在距离类模型,譬如K近邻,K-Means聚类中,无量钢化可以帮我们提升模型精度,避免某一个取值范围特别大的特征对距离计算造成的影响(一个特例是决策树和树的集成算法,对决策树不需要无量钢化,决策树可以把任意数据都处理的很好)
-
含义:特征抽取后我们就可以获取对应的数值型的样本数据,然后进行数据处理
-
概念:通过特定的统计方式(数学方法),将算法转换成算法要求的数据
-
方式
- 归一化
- 标准化
-
案例分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S30Zty3d-1643612347734)(as
sets/4.PNG)]- 如果认为每一个特征具有同等大小的权重都同等重要,则必须要对其进行归一化处理
- 可以使用KNN算法对特征影响进行说明。
3.1归一化实现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wBAaUL3l-1643612347734
)(assets/5.PNG)]
- 归一化后的数据服从正态分布
from sklearn.preprocessing import MinMaxScaler
参数:feature_range表示缩放范围,通常使用(0,1)
作用:使得某一个特征对最终结果不会造成很大的影响
from sklearn.preprocessing import MinMaxScaler
mm=MinMaxScaler(feature_range=(0,1)) #每个特征缩放的范围
data=[[90,2,10,40],[60,5,15,45],[73,3,13,45]]
data=mm.fit_transform(data)#data需要归一化的特征
print(data)
# [[1. 0. 0. 0. ]
# [0. 1. 1. 1. ]
# [0.43333333 0.33333333 0.6 1. ]]
-
问题:如果数据中存在的异常值比较多,会有什么影响?
- 结合着归一化计算的公式,异常值对原始特征中的最大值和最小值的影响很大,因此也会影响对归一化的值,这个也是归一化的一个弊端,无法很多好的处理异常值
-
归一化总结:
- 在特定场景下最大值和最小值是变化的,另外最大最小值很容易受到异常值的影响,所以这种归一化的方式具有一定的局限性。因此引出了一种更好的方式叫做:标准化!!!
3.2标准化处理
-
当数据按均值中心化后,再按标准差缩放,数据就会服从为均值为0,方差为1的正态分布(即标准正态分布),而这个过程,就叫做数据标准化(Standardization,又称Z-score normalization),公式如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-86191hYD-1643612347735)(assets/6.P
NG)] -
从公式可以看出,异常值对均值和标准差的影响不大
-
API
-
处理后,每列所有的数据都聚集在均值为0,标准差为1范围附近
-
标准化API:
from sklearn.preprocessing import StandardScaler fit_transform(X) #对X标准化 mean_#均值 var_ #方差
-
示例
from sklearn.preprocessing import StandardScaler ss=StandardScaler() data=[[90,2,10,40],[60,5,15,45],[73,3,13,45]] ss.fit_transform(data) # array([[ 1.27540458, -1.06904497, -1.29777137, -1.41421356], # [-1.16685951, 1.33630621, 1.13554995, 0.70710678], # [-0.10854507, -0.26726124, 0.16222142, 0.70710678]]) ss.mean_ #array([74.33333333, 3.33333333, 12.66666667, 43.33333333]) ss.var_ #array([150.88888889, 1.55555556, 4.22222222, 5.55555556])
-
3.3 归一化和标准化总结
- 归一化,如果出现了异常值则会影响特征的最大值最小值,那么最终结果会受到比较大影响
- 标准化,如果出现异常点,由于具有一定的数据量,少量的异常点对于平均值的影响并不大,从而标准差改变比较少
3.4StandardScaler
和MinMaxSclaer
选哪个?
- 大多数机器学习算法中,会选择
StandardSclaer
来进行特征缩放,因为MinMaxSclaer
对异常值非常敏感。在CPA,聚类,逻辑回归,支持向量机,神经网络这些算法中,StandardSclaer
往往是最好的选择。 MinMaxScaler
在不涉及距离度量,梯度,协方差计算以及数据需要被压缩到特定区间时,使用广泛,比如数字图像处理中量化像素强度时,都会使用MinMaxScaler
将数据压缩于[0,1]区间之中- 建议先用
StandardScaler
,效果不好换MinMaxScaler
4.特征选择
4.1定义
-
从特征中选择出有意义对模型有帮助的特征作为最终的机器学习输入的数据
-
注意
- 在做特征选择之前,有三件非常重要的事:
- 跟数据提供者联系
- 跟数据提供者沟通
- 跟数据提供者开会
- 一定要抓住给你提供数据的人,尤其是理解业务和数据含义的人,跟他们聊一段时间,技术能够让模型起飞,前提是你和业务员一样理解数据。所以特征选择是第一步,根据目标,用业务常识来选择特征
- 在做特征选择之前,有三件非常重要的事:
4.2特征选择的原因
- 冗余:部分特征的相关度高,容易消耗计算机的性能【数据相似度高】【例如:房价预测数据中有楼层和高度,这两个特征相关度高】
- 噪点:部分特征对预测结果有偏执影响【预测无关的数据】【例如:房价预测,数据中有购买房子的人的身高,跟预测无关的数据】
4.3特征选择的实现
-
人为对不相关的特征进行主关舍弃
-
在真正的数据应用领域,比如:金融,医疗,电商,我们得数据特征非常多,这样明显,如果遇见极端的情况,我们无法依赖对业务的理解来选则特征怎么办?
- 在已有特征和对应预测结果的基础上,使用相关的工具过滤一些无用或权重较低的特征
- 工具
- Filter(过滤式)
- Embedded(嵌入式):决策树模型会自己选择出对其重要的特征
- PCA降维
- 工具
- 在已有特征和对应预测结果的基础上,使用相关的工具过滤一些无用或权重较低的特征
4.4特征选择工具
4.4.1Filter过滤式(方差过滤):
-
原理:这是通过特征本身的方差来筛选特征的类,比如:一个特征本身的方差很小,就表示样本在这个特征上基本没有差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本区分没有作用,所以无论接下来特征工程要做什么,都要优先消除方差为0或方差较低的特征
-
API
from sklearn.feature_selection import VarianceThreshold VarianceThreshold(threshold=x) #threshold为方差的值,删除所有方差低于x的特征,默认为0表示保留所有方差为非0的特征 fit_transform(X) #X为特征
-
示例
from sklearn.feature_selection import VarianceThreshold #threshold方差的值,threshold=1,删除所有方差低于1的特征,默认为0,宝石保留所有方差为非0的特征 v=VarianceThreshold(threshold=1) v.fit_transform([[0,2,4,3],[0,3,7,3],[0,9,6,3]])#X为特征【数据为特征】
-
-
如果将方差为0或方差极低的特征取出后,剩余特征还有很多且模型的效果没有显著提升,则可以用方差将特征选择【一步到位】。留下一半的特征,那可以设定一个让特征总数减半的方差阈值,即找到特征方差的中位数,将中位数作为参数threshold的值即可
from sklearn.feature_selection import VarianceThreshold #threshold方差的值,threshold=1,删除所有方差低于1的特征,默认为0,宝石保留所有方差为非0的特征 v=VarianceThreshold(threshold=np.median(X.var().values)) v.fit_transform(X)## X为样本数据中的特征列
-
方差过滤对模型的影响
-
例如:KNN在方差过滤前和方差过滤后运行的效果和运行时间的对比。KNN是K近邻算法中的分类算法,其原理非常简单,是利用每个样本到其他样本点的距离来判断每个样本点的相似度,然后对样本进行分类。KNN必须遍历每个特征和每个样本,因而特征越多,KNN的计算也就会越缓慢,以下是代码运行时间对比。
-
方差过滤前
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qh2RdtJB-1643612347736)(assets/7.PNG
)] -
方差过滤后
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pulauHV2-1643612347737)(assets/
8.PNG)] -
可以看出,对于KNN,过滤后的效果十分明显:准确率稍有提升,但平均运行时间减少了10分钟,特征选择过后算 法的效率上升了1/3.
-
注意:方差过滤主要服务对象是:需要遍历特征的算法模型,而过滤的主要目的是在维持算法表现的前提下,帮助算法降低计算成本
-
4.4.2PCA降维(主成分分析)
-
定义
- PCA降维(主成分分析):是一种分析,简化数据集的技术
-
降维的维度值就是特征的种类
-
思想:如何跟好的对一个立体的物体用二维表示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y6mqK5jn-1643612347738)(assets/
9.PNG)] -
当然,第四张二维图片可以比较好的标识一个立体三维的水壶。但是也要清楚,用一个低纬度去表示高纬度的物体时,一定会造成一些信息的差异。可以让低纬度也可以能正确的表示高纬度的事物,或者信息差异最小。
-
目的:特征数量达到上百,上千的时候,考虑数据的优化。使数据维度压缩,尽可能降低源数据的维度(复杂度),损失少量信息。
-
作用:可以削减回归分析或者聚类分析中特征的数量
-
PCA大致原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SQLcSFQY-1643612347739)(assets/1
0.PNG)] -
红色为原始的样本特征,为二维的特征,如果降为一维,则可以将5个红色的原始特征,映射到一维的线段上就变成了4个特征。
-
PCA语法
from sklearn.decomposition import PCA pca=PCA(n_components=None) # n_components可以为小数(保留特征的百分比),整数(减少到的特征数量) pca.fit_transform(X)
-
示例
from sklearn.decomposition import PCA #将数据分解为较低维度的空间 #n_components可以为小数(保留特征的百分比),整数(减少到的特征数量)【保留几个特征值】 pca=PCA(n_components=2) pca.fit_transform([[0,2,4,3],[0,3,7,3],[0,9,6,3]])