机器学习第三周 简单的数据预处理和特征工程
一、学习目标
🔽无量纲化:最值归一化、均值方差归一化及sklearn中的Scaler
🔽缺失值处理
🔽处理分类型特征:编码与哑变量
🔽处理连续型特征:二值化与分段
二、参考资料
关于最值归一化、均值方差归一化及sklearn中的Scaler方面的学习,可以参考:《机器学习的敲门砖:归一化与KD树》及《特征工程系列:特征预处理(上)》)中相关部分。
推荐博文:https://www.cnblogs.com/juanjiang/archive/2019/05/30/10948849.html
https://mp.weixin.qq.com/s/RkenakI_DSXoMLwNNvUAAw 《机器学习的敲门砖:归一化与KD树》
https://mp.weixin.qq.com/s/qWO9zgKyntvyWfftpGqrHQ 《特征工程系列:特征预处理(上)》
三、学习记录
-
特征工程:
下面开始特征工程内容,觉得https://mp.weixin.qq.com/s/qWO9zgKyntvyWfftpGqrHQ 居士说的 “数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已”这句话 应该是一条定律。给定的数据和选定的特征,可以认为这已经在潜在确定了一个上限,虽然这个上限我们可能无法找出,但是我们可以不断逼近。在前提条件给定的状况下,结果最佳也就是已经确定,无论我们模拟的结果是什么,都不会超出这个。
**特征工程:**利用数据领域的相关知识来创建能够使机器学习算法达到最佳性能的特征的过程。
特征工程包含内容:DataPreProcessing数据预处理、Feature Extraction 特征提取 、Feature Selection特征选择 和Feature Construction特征构造等。
数据预处理则包括数据清洗和特征预处理等问题。
(1)数据型特征无量纲化
在实际常常使用数据中一般都是带有单位的,无量纲化就是将他们变得没有单位。可以使用标准化或者归一化。
-
最值归一化和均值方差归一化
在数据做训练前,由于数据大小的差异,或者数据单位量纲的不同,导致运算结果差异较大。这就需要在模型的开始对数据进行归一化操作normalize。在常用的数据归一化有两种:
最值归一化normalization和均值方差归一化standardization
**最值归一化normalization:**把所有数据映射到0,1之间。其特征是具有明显边界,但受outlier影响较大
x s c a l e = x − x m i n x m a x − x m i n x_{scale}=\frac{x-x_{min}}{x_{max}-x_{min}} xscale=xmax−xminx−xmin
**均值方差归一化:**把所有数据归一到均值为0方差为1的分布中。适用于数据中没有明显的边界,有可能存在极端数据值的情况
x s c a l e = x − x m e a n S x_{scale}=\frac{x-x_{mean}}{S} xscale=Sx−xmeanimport numpy as np x = np.random.randint(0,100,size=100) #最值归一化 (x--np.min(x))/(np.max(x)-np.min(x))
#最值归一化矩阵 X = np.random.randint(0,100,(50,2)) #将矩阵改为浮点型 X = np.array(X, dtype = float) #对其每一维度进行归一化 X[:,0] = (X[:,0] - np.min(X[:,0])) /(np.max(X[:,0])-np.min(X[:,0])) X[:,0] X[:,1] = (X[:,1] - np.min(X[:,1])) /(np.max(X[:,1])-np.min(X[:,1])) X[:,1]
在均一化后可以通过绘制图形显示具体分布情况。
均值方差归一化实现:
X2 = np.random.randint(0,100,[50,2]) X2 = np.array(X2 , dtype = float) for i in range(0,2): X2[:,i] = (X2[:,i]-np.mean(X2[:,i]))/np.std(X2[:,i]) plt.scatter(X2[:,0],X2[:,1]) plt.show()
随机函数:np.random.randint()
最小值:np.min()
最大值:np.max()
均值np.mean()
方差:np.std()
调整数组数值类型:np.array(data, dtype=’’)
-
Sklearn中的归一化
在划分训练数据集和测试数据集,训练数据集进行归一化处理,计算了训练数据集的均值和方差,在对测试数据集时使用的均值仍然是训练集的,方差也是。归一化:(x_test-mean_train)/std_train
sklearn中数据归一化的方法:StandardScaler
import numpy as np from sklearn import datasets from sklearn.model_selection import train_test_split iris = datasets.load_iris() X = iris.data y = iris.target X_train, X_test ,y_train ,y_test = train_test_split(X,y,test_size = 0.2 ,random_state = 2)
from sklearn.preprocessing import StandardScaler import matplotlib.pyplot as plt standardScaler = StandardScaler() #求得均值和方差 standardScaler.fit(X_train) standardScaler.mean_ standardScaler.scale_ #归一化 X_train_standard = standardScaler.transform(X_train) X_test_standard = standardScaler.transform(X_test) plt.scatter(X_test[:,0],X_test[:,2]) plt.show()
求出每个列的均值:
self.mean_ = np.array([np.mean(X[:,i] for i in range(X.shape[1]))])
self.scale_ = np.array([np.std(X[:,i] for i in range(X.shape[1])])
创建一个空的浮点型矩阵,大小和X相同
np.empty(shape=X.shape, dtype= float)
计算每一列都计算
for col in range(X.shape[1]):
X[:,col] = (X[:,col]-self.mean[col])/self.scale_[col]
数据标准化原因:a. 算法要求数据是均值为0,方差为1;b. 消除样本不同属性具有不同量级时的影响。
数据标准化:条件:特征服从正态分布,标准化后转换为标准正态分布
数据标准化定义:基于原始数据的均值和标准差,进行数据标准化。相当于对数据做变换,变换公式如下:
x
′
=
x
−
μ
σ
,
μ
是
均
值
,
σ
是
标
准
差
x^{'}=\frac{x-\mu}{\sigma},\mu是均值,\sigma是标准差
x′=σx−μ,μ是均值,σ是标准差
注:这里均值和标准差是针对整个样本集上的,而不是某个样本。
这里类似下面所说的均值归一化(代码实现也如下)。
优点:计算简单;缺点:总体均值和方差获得不方便,常使用样本均值与标准差;要求正态分布;存在异常值时无法保证结果。
MinMax归一化
优缺点:当有新数据时需要重新计算最大最小值,更新数值,同时对异常值敏感。
MaxAbs归一化:将数据转换为[-1,1]区间,且最大绝对值为1.
x
′
=
x
∣
M
a
x
∣
x^{'}=\frac{x}{|Max|}
x′=∣Max∣x
MaxAbs也要与MinMax归一化相类似问题。
3.正态分布化Normalization
定义:将每个样本缩放到单位范数。对每个样本计算其p范数,然后对该样本中每个元素除以该范数,结果是使每个处理后样本的p-范数等于1.
在文本分析和聚类分析中常使用的向量空间模型常使用此内容。
p-范数:P-2 I2-norm:
x
=
x
∑
j
d
(
x
j
)
2
x=\frac{x}{\sqrt{\sum_{j}^{d}(x_j)^2}}
x=∑jd(xj)2x
归一化与标准化对比(以后补上)
(2)数值型特征分享-数据离散化(连续值特征离散化)
1.无监督分箱法
自定义分箱:根据业务经验或常识等自行设定划分的区间,然后将原始数据划分到各个区间中。
等距分箱:根据相同宽度将数据分成几等份。类似频率分布直方图,等间距,宽度相同。
pandas.cut可以吧一组数据分割成离散的区间
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates=‘raise’) #0.23.4
x必须是一维的数据,不能用DataFrame,可以取dataframe里面的一列;bins被切割后的区间,一个int型的标量、标量序列(数组)或者pandas.IntervalIndex 。
-
一个int型的标量
当bins为一个int型的标量时,代表将x平分成bins份。x的范围在每侧扩展0.1%,以包括x的最大值和最小值。import numpy as np import pandas as pd ages = np.array([1,5,10,40,36,12,58,62,77,89,100,18,20,25,30,32]) df_ages = pd.cut(ages, 5) display(df_ages)
[(0.901, 20.8], (0.901, 20.8], (0.901, 20.8], (20.8, 40.6], (20.8, 40.6], ..., (0.901, 20.8], (0.901, 20.8], (20.8, 40.6], (20.8, 40.6], (20.8, 40.6]] Length: 16 Categories (5, interval[float64]): [(0.901, 20.8] < (20.8, 40.6] < (40.6, 60.4] < (60.4, 80.2] < (80.2, 100.0]]
很明显,等距分箱极易受到异常值的影响。
等频分箱:将数据分成几等份,每等分中数据的个数相同。
pd.qcut(df[‘age’],3) 可以实现。
**聚类分箱:**K均值聚类法,将在聚类过程中保证分箱有序性,第一个分箱中所有观测值都要小于第二个分箱中观测值,第二个分箱中观测值都要小于第三个分箱中观测值
**二值化:**将数值feature进行阈值化得到boolean型数据。
x ′ = 1 , x > t h r e s h o l d ; 0 , x ≤ t h r e s h o l d x^{'}=1 ,x>threshold;0,x\le threshold x′=1,x>threshold;0,x≤thresholdfrom sklearn.preprocessing import Binarizer # Binarizer函数也可以设定一个阈值,结果数据值大于阈值的为1,小于阈值的为0 binarizer = Binarizer(threshold=5).fit(ages.reshape(-1,1)) binarizer.transform(ages.reshape(-1,1))
array([[0], [0], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1], [1]])
preprocessing.KBinsDiscretizer 这是将连续型变量划分为分类变量的类,能够将连续型变量排序后按顺序分箱后编码
2.有监督分箱法
卡方分箱:
定义:自底向上的数据离散化方法。它依赖于卡方检验:具有最小卡方值的相邻区间合并在一起,直到满足确定的停止准则。如果两个相邻的区间具有非常类似的分布,则这两个区间可以合并;否则他们应当保持分开。
最小熵法分箱
这两个概念有点难懂…
3.sklearn
摘自:https://www.cnblogs.com/juanjiang/archive/2019/05/30/10948849.html
模块preprocessing 几乎包含数据预处理的所有内容
模块Impute填补缺失值专用
模块feature_selection 包含特征选择的各种方法的实践
模块decomposition 包含降维算法
**缺失值:**当用于训练的数据中含有缺失值时,可以通过
impute.SimpleImputer进行填补
class sklearn.impute.SimpleImputer
(missing_values=nan, strategy=’mean’, fill_value=None, verbose=0, copy=True)
missing_values :默认缺失值为np.nan
stratepy填补缺失值的策略,默认为均值mean ;median中值;most_frequent众数,constant参考fill_value中的值(配合fill_value使用)
copy默认为True,将创建特征矩阵的副本,反之将缺失值填补到原本的特征矩阵中去。
注:sklearn中特征矩阵必须是二维的
Age = data.loc[:,"Age"].values.reshape(-1,1) #sklearn当中特征矩阵必须是二维
Age[:20]
from sklearn.impute import SimpleImputer
imp_mean = SimpleImputer() #实例化,默认均值填补
imp_median = SimpleImputer(strategy="median") #用中位数填补
imp_0 = SimpleImputer(strategy="constant",fill_value=0) #用0填补
imp_mean = imp_mean.fit_transform(Age) #fit_transform一步完成调取结果
imp_median = imp_median.fit_transform(Age)
imp_0 = imp_0.fit_transform(Age)
imp_mean[:20]
imp_median[:20]
imp_0[:20]
#在这里我们使用中位数填补Age
data.loc[:,"Age"] = imp_median
data.info()
#使用众数填补Embarked
Embarked = data.loc[:,"Embarked"].values.reshape(-1,1)
imp_mode = SimpleImputer(strategy = "most_frequent")
data.loc[:,"Embarked"] = imp_mode.fit_transform(Embarked)
data.info()
使用pandas numpy 进行填补
#参考:
import pandas as pd
data = pd.read_csv(r"行行行ata.csv",index_col=0)
data.head()
data.loc[:,"Age"] = data.loc[:,"Age"].fillna(data.loc[:,"Age"].median())
#.fillna 在DataFrame里面直接进行填补
data.dropna(axis=0,inplace=True)
#.dropna(axis=0)删除所有有缺失值的行,.dropna(axis=1)删除所有有缺失值的列
#参数inplace,为True表示在原数据集上进行修改,为False表示生成一个复制对象,不修改原数据,默认False
处理分类型特征:编码和哑变量
编码:即将数据进行编码,可以将文字型数据转换为数值型,方便只能处理数值型的算法进行运算。
preprocessing.LabelEncoder :标签专业,能够将分类转换为分类数值
一般的使用方法:先实例化,在fit导入数据,在调用transform接口调取结果,最终查看结果。
#举例如下:
le = LabelEncoder() #实例化
le = le.fit(y) #导入数据
label = le.transform(y) #transform接口调取结果
le.classes_ #属性.classes_查看标签中究竟有多少类别
label #查看获取的结果label
le.fit_transform(y) #也可以直接fit_transform一步到位
from sklearn.preprocessing import OrdinalEncoder
能够将分类特征转换为分类数值
preprocessing.OneHotEncoder :独热编码,创建哑变量
哑变量这个概念…解决分类数据转化为数值后,能够体现其中逻辑,不丢失信息的一种表示。
上图参考自:https://www.cnblogs.com/juanjiang/archive/2019/05/30/10948849.html