特征工程
- 特征抽取
- 数据特征的预处理
特征选择
为什么需要特征工程
- 样本数据中的特征有可能会出现缺失值、重复值、异常值等,那么我们需要对特征中的噪点数据进行处理,处理的目的就是为了得到更加纯净的样本集,让模型基于这组数据可以有更好的预测能力。
什么是特征工程?
- 特征工程就是将原始数据转换为更好的代表预测模型的潜在问题的特征的过程,从而提高对未知数据预测的准确性:
- 比如如果AlphaGO学习的数据中既有棋谱,又有食谱,还有歌词,那么这些干扰的数据肯定会影响AlphaGo的学习。
- 特征工程就是将原始数据转换为更好的代表预测模型的潜在问题的特征的过程,从而提高对未知数据预测的准确性:
特征工程的意义:
- 特征工程会直接影响模型预测的结果
如何实现特征工程:
- 工具:sklearn
sklearn介绍
- Python中机器学习工具,包含了很多机器学习算法的实现;
- 功能:
- 分类模型
- 回归模型
- 聚类模型
- 特征工程
特征抽取
目的:
- 我们所采集到样本的特征数据很多时候为字符串或者其他类型的数据,我们知道电脑只可以识别二进制数值型的数据。所以,如果不是数值型的数据,机器学习苏算法是识别不了的。
效果演示:
- 将字符串转换成数字
from sklearn.feature_extraction.text import CountVectorizer
vector= CountVectorizer()
res= vector.fit_transform(['lift is short, i love python', 'I love Python'])
print(res.toarray())
[[1 1 1 1 1]
[0 0 1 1 0]]
演示后的结论:
- 特征抽取对文本等数据进行特征值化,特征值化是为了让机器更好的理解数据。
字典特征抽取
- 对字典数据进行特征值化
- API: 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': 'Beijing', 'temp': 12},
{
'city': 'Chengdu', 'temp': 11},
{
'city': 'Chongqin', 'temp': 34}
]
# 实例化一个工具类对象
d= DictVectorizer()
# 返回的是一个sparse矩阵(存储的是特征值化之后的结果)
feature= d.fit_transform(alist)
print(feature)
(0, 0) 1.0
(0, 3) 12.0
(1, 1) 1.0
(1, 3) 11.0
(2, 2) 1.0
(2, 3) 34.0
- 什么是sparse矩阵,如何理解?
- 在DictVectorizer类构造的方法中设定
sparse=False
则返回的就不是sparse矩阵,而是一个array数组;- get_feature_names():返回类别名称
- sparse矩阵就是一个变相的数组或者李彪,目的是为了节省内存;
- 对比下面的onehot编码,(0,0) 1.0 表示 0 行 0 列 的值为 1.0 ; (1,1) 1.0表示 1行1列的值为1.0;
- 在DictVectorizer类构造的方法中设定
from sklearn.feature_extraction import DictVectorizer
alist= [
{
'city': 'Beijing', 'temp': 12},
{
'city': 'Chengdu', 'temp': 11},
{
'city': 'Chongqin', 'temp': 34}
]
# 实例化一个工具类对象
d= DictVectorizer(sparse= False) # sparse= False
# 返回的是一个sparse矩阵(存储的是特征值化之后的结果)
feature= d.fit_transform(alist)
print(d.get_feature_names())
print(feature)
['city=Beijing', 'city=Chengdu', 'city=Chongqin', 'temp']
[[ 1. 0. 0. 12.]
[ 0. 1. 0. 11.]
[ 0. 0. 1. 34.]]
one-hot编码
- sparse矩阵中的
0
和1
就是onehot编码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3W0CQxLE-1628110524140)(attachment:image.png)]
- sparse矩阵中的
为什么需要onehot编码呢?
- 特征抽取主要目的就是对非数值型数据进行特征值化! 如果现在需要对下图中的human和alien进行手动特征值化为4, human为1.则1和4有没有优先级或者权重大小呢?
Sample | Category | Numerical |
---|---|---|
1 | Human | 1 |
2 | Human | 1 |
3 | Penguin | 2 |
4 | Octopus | 3 |
5 | Alien | 4 |
- 则需要对其进行One-Hot编码:
Human | Panguln | Octopus | Alien |
---|---|---|---|
1 | 0 | 0 | 0 |
1 | 0 | 0 | 0 |
0 | 1 | 0 | 0 |
0 | 0 | 1 | 0 |
- 基于pandas实现one-hot编码:
- pd.get_dummies(df['col'])
import pandas as pd
df= pd.DataFrame([
['green', 'M', 20, 'class1'],
['red', 'F', 23, 'class2'],
['blue', 'M', 21, 'class3']
])
df.columns= ['name', 'gender', 'age', 'class']
df
name
gender
age
class
0
green
M
20
class1
1
red
F
23
class2
2
blue
M
21
class3
pd.get_dummies(df['name'])
blue
green
red
0
0
1
0
1
0
0
1
2
1
0
0
文本特征抽取
- 作用:对文本进行特征值化
- API:from sklearn.feature_extraction import CountVectorizer
- fit_transform(X):X为文本或者文本字符串的可迭代对象,返回sparse矩阵;
- inverse_transform(X):X为array或者sparse矩阵,返回转换之前的格式的数据
- get_geature_names():
- toarray():将sparse矩阵转换为数据
from sklearn.feature_extraction.text import CountVectorizer
vector= CountVectorizer()
res= vector.fit_transform(['Python is good', 'But Go is better, and I love Go'])
print(res) # sparse矩阵
print(vector.get_feature_names())
print(res.toarray()) # 将sparse矩阵转换为数组
# 注意:单字母不统计(因为单字母代表不了实际含义), 然后每个数字表示的是单词出现的次数
(0, 7) 1
(0, 5) 1
(0, 4) 1
(1, 5) 1
(1, 2) 1
(1, 3) 2
(1, 1) 1
(1, 0) 1
(1, 6) 1
['and', 'better', 'but', 'go', 'good', 'is', 'love', 'python']
[[0 0 0 0 1 1 0 1]
[1 1 1 2 0 1 1 0]]
- 中文文本特征抽取
- 对有标点符号的中文文本进行特征处理
from sklearn.feature_extraction.text import CountVectorizer
vector= CountVectorizer()
res= vector.fit_transform(['人生苦短,我用Python', '人生苦短,我用Go'])
print(res)
print(vector.get_feature_names())
print(res.toarray())
# 注意:单个汉字不统计
(0, 0) 1
(0, 2) 1
(1, 0) 1
(1, 1) 1
['人生苦短', '我用go', '我用python']
[[1 0 1]
[1 1 0]]
- 对有标点符号且含有分隔符的中文文本进行特征处理
from sklearn.feature_extraction.text import CountVectorizer
vector= CountVectorizer()
res= vector.fit_transform(['人生 苦短, 我 用Python', '人生苦短,我更 喜欢用 Go'])
print(res)
print(vector.get_feature_names())
print(res.toarray())
(0, 1) 1
(0, 6) 1
(0, 5) 1
(1, 2) 1
(1, 4) 1
(1, 3) 1
(1, 0) 1
['go', '人生', '人生苦短', '喜欢用', '我更', '用python', '苦短']
[[0 1 0 0 0 1 1]
[1 0 1 1 1 0 0]]
-目前CountVextorizer只可以对有标点符号和用分隔符对应的文本进行特征抽取,显然这是满足不了我们的日常需求的:
- 因为在自然语言处理中,我们是需要将一段中文文本中的相关的词语、成语、形容词....进行抽取
- jieba分词
- 对中文文章进行分词处理
- jieba分词的基本使用
# jieba的基本使用:对文章进行分词
import jieba
jb= jieba.cut('我一定会回来的')
content= list(jb)
ct= ' '.join(content)
print(ct) # 返回空格分隔的词语
我 一定 会 回来 的
jb1= jieba.cut('人生苦短,我用Go!')
jb2= jieba.cut('人生漫长,我用Python!')
ct1= ' '.join(list(jb1))
ct2= ' '.join(list(jb2))
print(ct1, ct2)
人生 苦短 , 我用 Go ! 人生 漫长 , 我用 Python !
# 中文文本特征提取
from sklearn.feature_extraction.text import CountVectorizer
vector= CountVectorizer()
res= vector.fit_transform([ct1, ct2])
print(res)
print(vector.get_feature_names())
print(res.toarray())
# 注意:单个汉字不统计
(0, 2) 1
(0, 5) 1
(0, 3) 1
(0, 0) 1
(1, 2) 1
(1, 3) 1
(1, 4) 1
(1, 1) 1
['go', 'python', '人生', '我用', '漫长', '苦短']
[[1 0 1 1 0 1]
[0 1 1 1 1 0]]
特征的预处理:对数值型的数据进行处理
无量纲化:
- 在机器学习算法实践中,往往有着将不同规格的数据转换到同一规格,或将不同分布的数据转换到特定分布,这种需求统称为“无量纲化”。例如在逻辑回归、支持向量机、神经网络等算法中,无量纲化可以加快求解速度;在K近邻、K-Means聚类中,无量纲化可以提升模型精度,避免将某一个取值范围特别大的特征对距离计算造成影响。(但是在决策树算法中,我们无需无量纲化,因为决策树算法可以将任意数据都处理的很好)
- 预处理就是用来实现无量纲化的方式
含义: 特征抽取后我们就可以获取对应的数值型的样本数据了,之后就可以进行数据处理;
概念: 通过特定的统计方法(数学方法),将数据转换成算法要求的数据
方式:
- 归一化
- 标准化
归一化的实现:
- 特点: 通过对原始数据进行变换吧数据映射到(默认为[0,1])之间
- 公式:
$$X\prime = \frac{x-min}{max-min}$$
$$X\prime \prime=X\prime * (mx-mi)+mi$$
注:作用于每一列,max为列最大值,min为列最小值,$X\prime \prime$为最终结果,$mx$,$mi$为指定区间范围[mi,mx],默认$mx$为1$mi$为0。
- 归一后的数据服从正态分布
- API: from sklearn.preprocessing import MinMaxScaler
- 参数:feature_range表示缩放范围,通产使用(0,1)
- 作用:使得摸一个特征对最终结果不会造成很大的影响
# 示例
from sklearn.preprocessing import MinMaxScaler
mm= MinMaxScaler(feature_range= (0,1)) # 每个特征缩放范围
data= [[34,6,76,98],[6,57,5,43],[12,54,76,12]]
data= mm.fit_transform(data) # 归一化
print(data)
[[1. 0. 1. 1. ]
[0. 1. 0. 0.36046512]
[0.21428571 0.94117647 1. 0. ]]
- 问题:如果数据中存在的异常值较多,会对结果造成什么影响?
- 异常值对原始特征值中的最大值和最小值影响很大,因此会影响归一化之后的值。这也是归一化的一个弊端,无法很好的处理异常值;
- 归一化总结:
- 在特定场景下,最大值和最小值是变化的,且最大值和最小值容易受到异常值的影响,所以归一化操作具有一定的局限性,因此引出一种更好的方式:标准化。
标准化的处理
- 将数据按均值去中心化后,再按照标准差缩放,数据就会服从N(0,1)正态分布,这个过程就叫做数据标准化。
- 公式:
$$X \prime = \frac{x-mean}{\sigma}$$
注:作用于每一列,mean为平均值,$\sigma$为标准差
- 从公式中可以看出,异常值对均值和标准差的影响不大
- API:from sklearn.preprocessing import StandardScaler
- fit_transform(X):对X进行标准化
- mean_:均值
- var_:标准差
from sklearn.preprocessing import StandardScaler
ss= StandardScaler()
data= [[34,6,76,98],[6,57,5,43],[12,54,76,12]]
data= ss.fit_transform(data) # 标准化操作
print(data)
# ss.mean_
# ss.var_
[[ 1.38462194 -1.41226963 0.70710678 1.3216298 ]
[-0.94154292 0.77032889 -1.41421356 -0.22495826]
[-0.44307902 0.64194074 0.70710678 -1.09667153]]
特征选择
特征选择:从特征选择出有意义对模型有帮助的特征作为最终的机器学习输入的数据!
特征选择的原因:
- 冗余:部分特征的相关度高,容易消耗计算机的性能;
- 噪点:部分特征对预测结果有偏执影响
特征选择的实现:
- 人为对不相关的特征进行主观舍弃
- 在已有特征和对应预测结果的基础上,使用相关的工具过滤掉一些无用或者权重较低的特征
- 工具:
- Filter(过滤式)
- Embedded(嵌入式):决策树模型会自己选择出对其重要的特征
- PCA降维
Filter过滤式(方差过滤):
- 原理:这是通过特征本身的方差来筛选特征的类。比如一个特征本身的方差很小,表示样本在这个特征上基本没有什么差异,可能特征中的大多数值都一样,甚至整个特征的取值都相同,那这个特征对于样本没有什么作用。所以特征工程需要优先消除方差为0或者方差极低的特征。
- API:from sklearn.feature_selection import VarianceThreshold
- VarianceThreshold(threshodl=x):threshold=x表示删除所有方差低于x的特征,默认值为0表示保留所有方差为非0的特征;
- fit)transform(X):X为特征
from sklearn.feature_selection import VarianceThreshold
# threshold方差的值,删除所有方差低于x的特征
v= VarianceThreshold(threshold= 3)
v.fit_transform([[0,1,2,3], [0, 3, 5, 3], [0, 9, 3, 15]])
array([[ 1, 3],
[ 3, 3],
[ 9, 15]])
- 如果将方差为0或者方差极低的特征去除后,剩余特征还有很多且模型的效果没有显著提升。将所有特征中特征方差的中位数作为参数传为threshold的可以只保留一半的特征;
- VarianceThreshold(threshold= np.median((X.var().values()).fit_transform(X)
- X为样本数据中的特征列
- VarianceThreshold(threshold= np.median((X.var().values()).fit_transform(X)
import numpy as np
feature= np.random.randint(0, 100, size= (5, 10))
feature
array([[98, 10, 38, 6, 48, 38, 36, 22, 99, 29],
[80, 81, 20, 56, 5, 22, 76, 34, 90, 80],
[67, 1, 64, 86, 6, 97, 76, 2, 79, 70],
[98, 94, 7, 4, 78, 36, 66, 19, 84, 76],
[91, 39, 33, 24, 96, 1, 72, 30, 38, 61]])
med= np.median(feature.var(axis= 1))
med
937.64
v= VarianceThreshold(threshold= med)
v.fit_transform(feature)
array([[10, 6, 48, 38],
[81, 56, 5, 22],
[ 1, 86, 6, 97],
[94, 4, 78, 36],
[39, 24, 96, 1]])
- 方差过滤影响
提高算法模型训练效率和准确率。
PCA大致原理
- PCA(主成分分析)大致原理
- API: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= 3)
pca.fit_transform([[1,2,3,4], [4,1,4,5],[5,4,2,1]])
array([[-1.73205081e+00, 1.73205081e+00, 2.22044605e-16],
[-1.73205081e+00, -1.73205081e+00, 2.22044605e-16],
[ 3.46410162e+00, -5.43895982e-16, 2.22044605e-16]])