一、什么是特征工程
“数据决定了机器学习的上限,而算法只是尽可能逼近这个上限”,这里的数据指的就是经过特征工程得到的数据。特征工程是将原始数据转换为更好地代表预测模型的潜在问题的特征的过程,目的是最大限度地从原始数据中提取特征以供算法和模型使用,从而提高了对未知数据的模型准确性。
二、特征工程的意义
特征工程将直接影响模型的预测结果
三、Scikit-learn
大部分直接拿过来的数据都是特征不明显的、没有经过处理的或者说是存在很多无用的数据,那么需要进行一些特征处理,特征的缩放等等,满足训练数据的要求。这里,我们使用Scikit-learn进行处理。
Scikit-learn:
Python语言的机器学习工具
所有人都适用,可在不同的上下文中重用
基于NumPy、SciPy和matplotlib构建
开源、商业可用 - BSD许可
安装:
(建议创建虚拟环境)
pip3 install Scikit-learn
通过import sklearn导入
(注:安装scikit-learn需要numpy,pandas等库)
四、数据的特征抽取
案例一:字典特征抽取
类:sklearn.feature_extraction.DictVectorizer
作用:对字典数据进行特征值化
DictVectorizer语法:
DictVectorizer(sparse=True,…) sparse:以sparse矩阵展示结果
DictVectorizer.fit_transform(X) X:字典或者包含字典的迭代器 返回值:返回sparse矩阵
DictVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格式
DictVectorizer.get_feature_names() 返回类别名称
DictVectorizer.transform(X) 按照原先的标准转换
fit、transform、fit_transform区别
fit():就是求得训练集的均值,方差,最大值,最小值,这些训练集的固有属性。
transform():在fit的基础上,进行标准化,降维,归一化等操作。
fit_transform():fit_transform是fit和transform的组合,既包括了训练又包含了转换。transform()和fit_transform()二者的功能都是对数据进行某种统一处理(比如标准化~N(0,1),将数据缩放(映射)到某个固定区间,归一化,正则化等)
实例化
from sklearn.feature_extraction import DictVectorizer
#实例化
DV = DictVectorizer()
data = DV.fit_transform([{'city':'上海','temperature':30},{'city':'北京','temperature':25}])
print(data)
(0, 0) 1.0
(0, 2) 30.0
(1, 1) 1.0
(1, 2) 25.0
解释:
上面输出结果中,括号内的第一个值代表第几条数据,第二个值代表在已分类的词组(调用get_feature_names查询)的位置,1.0代表对应的值(如:上海、北京),30、25代表temperature。更多详情请自行了解sparse矩阵
sparse设为False
from sklearn.feature_extraction import DictVectorizer
#实例化
DV = DictVectorizer(sparse=False)
data = DV.fit_transform([{'city':'上海','temperature':30},{'city':'北京','temperature':25}])
print(data)
[[ 1. 0. 30.]
[ 0. 1. 25.]]
解释:
上面输出结果中,有两组数据,每一组数据都是三个值,代表上海、北京、temperature,1.表示这一组数据出现该值(如:第一组数据1.代表出现上海这个数据),0.代表无此数据,更多详情请自行了解one-hot编码
from sklearn.feature_extraction import DictVectorizer
#实例化
DV = DictVectorizer() #sparse默认为True
data = DV.fit_transform([{'city':'上海','temperature':30},{'city':'北京','temperature':25}])
# print(data)
print(DV.inverse_transform(data)) #转换之前的数据
print(DV.get_feature_names()) #返回分类名称
[{'city=上海': 1.0, 'temperature': 30.0}, {'city=北京': 1.0, 'temperature': 25.0}]
['city=上海', 'city=北京', 'temperature']
案例二:文本特征抽取
类:sklearn.feature_extraction.text.CountVectorizer
作用:对文本数据进行特征值化
CountVectorizer语法:
CountVectorizer(max_df=1.0,min_df=1,…)返回词频矩阵
CountVectorizer.fit_transform(X) X:文本或者包含文本字符串的可迭代对象 返回值:返回sparse矩阵
CountVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格式
CountVectorizer.get_feature_names() 返回值:单词列表
实例化
from sklearn.feature_extraction.text import CountVectorizer
CV = CountVectorizer()
data = CV.fit_transform(['i love python','i dislike python'])
print(data)
(0, 1) 1
(0, 2) 1
(1, 2) 1
(1, 0) 1
解释:
上面的输出结果中,四组数据代表四个单词,i为单个字母,不计入单词中。
toarray()将sparse矩阵转换成array数组
from sklearn.feature_extraction.text import CountVectorizer
CV = CountVectorizer()
data = CV.fit_transform(['i love python','i dislike python'])
print(data.toarray()) #toarray将sparse矩阵转换成array数组
[[0 1 1]
[1 0 1]]
案例三:中文文本特征值化
下载jieba,对中文进行分词
pip3 install jieba
测试(返回值:词语生成器)
import jieba
text1 = jieba.cut('人生苦短,我用python')
print(text1)
print(list(text1))
<generator object Tokenizer.cut at 0x7ffa26b68bd0>
['人生', '苦短', ',', '我用', 'python']
提取中文文本特征值
import jieba
from sklearn.feature_extraction.text import CountVectorizer
text1 = jieba.cut('人生苦短,我用python')
text2 = jieba.cut('人生漫长,不用python')
text_handle1 = ' '.join(text1) #使用空格分隔
text_handle2 = ' '.join(text2)
CV = CountVectorizer()
data = CV.fit_transform([text_handle1,text_handle2])
print(data)
print(CV.get_feature_names())
(0, 2) 1
(0, 5) 1
(0, 3) 1
(0, 0) 1
(1, 2) 1
(1, 0) 1
(1, 4) 1
(1, 1) 1
['python', '不用', '人生', '我用', '漫长', '苦短']
解释:
上面的代码中,中文词与词之间需要通过空格分隔,单个汉字不提取。
案例四:TF-IDF
前言:如果我们想要提取一篇文章的关键词作为文章的标签,我们可以通过这些词在文章出现的频率抽取出代表文章的关键词,但是这容易受一些无关词(我们、你们、大家)频率的影响,为此我们可以使用TF-IDF更完美的解决此问题。
TF-IDF的主要思想:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
TF-IDF作用:用以评估一个词对于一个文件集或一个语料库中的其中一份文件的重要程度。
类:sklearn.feature_extraction.text.TfidfVectorizer
TfidfVectorizer语法:
TfidfVectorizer(stop_words=None,…)返回词的权重矩阵
TfidfVectorizer.fit_transform(X) X:文本或者包含文本字符串的可迭代对象 返回值:返回sparse矩阵
TfidfVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格式
TfidfVectorizer.get_feature_names() 返回值:单词列表
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer
text1 = ' '.join(jieba.cut('我们热爱科学,科学改变世界'))
text2 = ' '.join(jieba.cut('我们热爱艺术,艺术改变世界'))
text3 = ' '.join(jieba.cut('我们热爱音乐,音乐改变世界'))
TF_IDF = TfidfVectorizer()
data = TF_IDF.fit_transform([text1,text2,text3])
print(data.toarray())
print(TF_IDF.get_feature_names())
[[0.25427116 0.25427116 0.25427116 0.25427116 0.861037 0.
0. ]
[0.25427116 0.25427116 0.25427116 0.25427116 0. 0.861037
0. ]
[0.25427116 0.25427116 0.25427116 0.25427116 0. 0.
0.861037 ]]
['世界', '我们', '改变', '热爱', '科学', '艺术', '音乐']
解释:
上面输出的结果中,取第一组数据做解析,0.861037对应’科学‘,0.,0.对应’艺术’, ‘音乐’,而其它无关词在多篇文章出现,所以其频率将下降,从而更加精确的获取第一篇文章的关键词’科学‘。
五、数据特征预处理
特征处理是什么:通过特定的统计方法(数学方法)将数据转换成算法要求的数据
数值型数据:标准缩放(归一化 、标准化 、缺失值)
类别型数据:one-hot编码
时间类型:时间的切分
API:sklearn. preprocessing
归一化:
特点:通过对原始数据进行变换将数据映射到某个区间(默认为[0,1])
意义:
使不同特征对结果的影响程度相同。举个栗子,现在有两组数据(男士的财富(元)和体重(kg)),[10000,50],[5000,60],女士将通过这两组数据的两个特征选择男友,很明显,财富的差距对判断造成的影响远大于体重,但我们要做的是让这两个特征对结果的影响程度相同,因此需要将两个特征的数据都统一到某个区间,为此可使用归一化。
缺点:
最大值与最小值非常容易受异常点影响,所以这种方法鲁棒性较差,容易导致结果产生巨大变化
适用场景:
适合传统精确小数据场景。
公式:
𝑋′= (𝑥−𝑚𝑖𝑛)/(𝑚𝑎𝑥−𝑚𝑖𝑛)
𝑋′′=𝑋′∗(𝑚𝑥−𝑚𝑖)+𝑚𝑖
【注:作用于每一列(每一列代表一个特征),max为一列的最大值,min为一列的最小值,X"为最终结果,mx,mi分别为指定区间值(默认mx为1,mi为0)】
sklearn归一化API: sklearn.preprocessing.MinMaxScaler
MinMaxScaler语法:
MinMaxScalar(feature_range=(0,1)…) 每个特征缩放到给定范围(默认[0,1])
MinMaxScalar.fit_transform(X) X:numpy array格式的数据[n_samples,n_features] 返回值:转换后的形状相同的array
from sklearn.preprocessing import MinMaxScaler
MinMax = MinMaxScaler()
data = MinMax.fit_transform([[85,4,10,41],[62,2,16,45],[70,3,13,46]])
print(data)
[[1. 1. 0. 0. ]
[0. 0. 1. 0.8 ]
[0.34782609 0.5 0.5 1. ]]
标准化:
特点:通过对原始数据进行变换把数据变换到均值为0,方差为1范围内
优点:
相对于归一化,如果出现异常点,由于具有一定数据量,少量的异常点对 于平均值的影响并不大,从而方差改变较小。
公式:
𝑋^′= (𝑥−mean)/𝜎
std = [(x1-mean)2 + (x2-mean)2 + …] / n (std:方差,n:每个特征的样本总数)
𝜎 = √std
【注:作用于每一列,mean为平均值,𝜎为标准差(考量数据的稳定性)】
sklearn特征化API: scikit-learn.preprocessing.StandardScaler
StandardScaler语法:
StandardScaler(…) 处理之后每列来说所有数据都聚集在均值0附近方差为1
StandardScaler.fit_transform(X,y) X:numpy array格式的数据[n_samples,n_features] 返回值:转换后的形状相同的array
StandardScaler.mean_ 原始数据中每列特征的平均值
StandardScaler.var_ 原始数据每列特征的方差
StandardScaler.scale_ 原始数据缩放比例、标准差
from sklearn.preprocessing import StandardScaler
Stan = StandardScaler()
data = Stan.fit_transform([[85,4,10,41],[62,2,16,45],[70,3,13,46]])
print(data)
print(Stan.mean_) #每个特征的平均值
print(Stan.var_) #每个特征的方差
print(Stan.scale_) #缩放比例、标准差
[[ 1.32863884 1.22474487 -1.22474487 -1.38873015]
[-1.08388958 -1.22474487 1.22474487 0.46291005]
[-0.24474926 0. 0. 0.9258201 ]]
[72.33333333 3. 13. 44. ]
[90.88888889 0.66666667 6. 4.66666667]
[9.53356643 0.81649658 2.44948974 2.1602469 ]
缺失值处理
处理方法:
删除:如果每列或者行数据缺失值达到一定的比例,建议放弃整行或者整列
插入:可以通过缺失值每行或者每列的平均值、中位数来填充
sklearn缺失值API: sklearn.preprocessing.Imputer
Imputer语法:
Imputer(missing_values=‘NaN’, strategy=‘mean’, axis=0) 完成缺失值插补,missing_values 指定缺失值,strategy 指定替换后的值(mean代表均值),axis 指定处理行或列(0表示列)
Imputer.fit_transform(X) X:numpy array格式的数据[n_samples,n_features] 返回值:转换后的形状相同的array
关于np.nan(np.NaN):
1、 numpy的数组中可以使用np.nan/np.NaN来代替缺失值,属于float类型
2、如果是文件中的一些缺失值,可以替换成nan,通过np.array转化成float 型的数组即可
from sklearn.preprocessing import Imputer
import numpy as np
Im = Imputer() #missing_values:缺失值,strategy=:替换值,axis:指定行列
data = Im.fit_transform([[1, 2], [np.nan, 3], [7, 6]])
print(data)
[[1. 2.]
[4. 3.]
[7. 6.]]
解释:
上面的输出结果中,np.nan被替换成均值4 = (1+7)/2
六、特征选择
特征选择是什么:从提取到的所有特征中选择部分特征作为训练集特征
主要方法:
Filter(过滤式):VarianceThreshold
Embedded(嵌入式):正则化、决策树
Wrapper(包裹式)
VarianceThreshold:
类:sklearn.feature_selection.VarianceThreshold
VarianceThreshold语法:
VarianceThreshold(threshold = 0.0) 删除所有低方差特征 ,默认值是保留所有非零方差特征,即删除所有样本中所有特征值都相同的特征。
Variance.fit_transform(X,y) X:numpy array格式的数据[n_samples,n_features] 返回值:训练集差异低于threshold的特征将被删除。
from sklearn.feature_selection import VarianceThreshold
VT = VarianceThreshold(threshold=5) #删除所有低方差特征
data = VT.fit_transform([[0,10,2,3],[1,0,20,5],[0,20,-15,4]])
print(data)
[[ 10 2]
[ 0 20]
[ 20 -15]]
解释:
上面输出的结果中,从纵向看,方差小于5的特征被删除。
其他特征选择方法:
神经网络(以后介绍)
七、特征降维
特征降维是什么:将高维度(维度是指特征数)特征降成低维度,损失少量数据,降维后值一般改变,比如:原始特征中有个特征的值是10,那么降维后对应的值可能是5。
【通过降维,将二维数据降到一维,并且保证了每个点尽可能不重复(如上图)】
降维原因:特征太多(上百)需要简化。
PCA是什么:
本质:PCA是一种分析、简化数据集的技术。
目的:是数据维数压缩,尽可能降低原数据的维数(复杂度),损失少量信息。
作用:可以削减回归分析或者聚类分析中特征的数量。
sklearn降维API:
sklearn. decomposition
PCA语法:
PCA(n_components=None) 将数据分解为较低维数空间
PCA.fit_transform(X) X:numpy array格式的数据[n_samples,n_features] 返回值:转换后指定维度的array
from sklearn.decomposition import PCA
pca = PCA(n_components=1)
data = pca.fit_transform([[4,5,6],[7,8,9],[6,11,4]])
print(data)
[[-2.78946146]
[-0.94036353]
[ 3.72982499]]
解释:
上面的输出结果中,从纵向看,数据由原先的三维(三个特征)降成一维(数据量一般损失少量或不损失)
其它降维方法:
线性判别分析LDA
特征选择和特征降维的区别:
特征选择就是单纯地从提取到的所有特征中选择部分特征作为训练集特征,比如:从1000个特征中抽取500个作为训练集,其它500个特征就置之不理,而特征降维是将高维度特征转化成低维度,本质上是从一个维度空间映射到另一个维度空间,比如:将1000个特征降成500个,原始数据中的1000个特征,每一个都对应着降维后的500维空间中的一个值,假设原始特征中有个特征的值是10,那么降维后对应的值可能是5。