在机器学习中有一个不成文的说法(数据不给力,再厉害的算法也白搭)首先说明这句话是我编的。但是我主要是想表达一下数据在算法中的重要性,所以我们在拿到数据时,我们首先应该观察数据,对数据进行一系列的数据预处理。我们在演示的时候,很多时候用的是sklearn包中的数据(那些是很完美的数据)但是我们在实际生产中不可能拿到这么完美的数据(算了,不这么说)但是我们的实际生产中很大可能不会拿到这么完美的数据,经常拿到的数据是有缺失,有异常,有噪音,或者需要处理的数据。如果我们把数据处理的很好也能提高算法的能力。
接下里我们来学习一下简单的特征工程:
在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布的需求,这种需求统称为将数据“无量纲化”。譬如梯度和矩阵为核心的算法中,譬如逻辑回归,支持向量机,神经网络,无量纲化可以加快求解速度;而在距离类模型,譬如K近邻,K-Means聚类中,无量纲化可以帮我们提升模型精度,避免某一个取值范围特别大的特征对距离计算造成影响。但是特此说明在树模型中不需要“无量纲化”也可以把数据处理得很好。具体原因后面在树模型里面详细说明。
对于数值类数据
preprocessing.MinMaxScaler
当数据(x)按照最小值中心化后,再按极差(最大值 - 最小值)缩放,数据移动了最小值个单位,并且会被收敛到[0,1]之间,而这个过程,就叫做数据归一化(Normalization,又称Min-Max Scaling)。这里贴上scikit-learn的官网(https://scikit-learn.org/)
以下是官网解释:
源码:
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
data = [[-2, 3], [1, 4], [0, 8], [-1, 17],[2,5],[6,1]]
data=pd.DataFrame(data)
scaler = MinMaxScaler() #实例化MIN_MAX_SCALER对象
scaler = scaler.fit(data) #训练,在这里本质是生成min(x)和max(x)
result = scaler.transform(data) #归一化数据
result #在Pycharm中使用 print(result)
data_org = scaler.inverse_transform(result) #逆转结果
data_org #在Pycharm中使用 print(data_org)
#使用源码计算方式计算
import numpy as np
X = np.array([[-2, 3], [1, 4], [0, 8], [-1, 17],[2,5],[6,1]])
X_1 = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0)) #归一化
X_1 #在Pycharm中使用 print(X_1)
X_inverse = X_1 * (X.max(axis=0) - X.min(axis=0)) + X.min(axis=0)
X_inverse #在Pycharm中使用 print(X_inverse)
preprocessing.StandardScaler
当数据(x)按均值(μ)中心化后,再按标准差(σ)缩放,数据就会服从为均值为0,方差为1的正态分布(即标准正态分布),而这个过程,就叫做数据标准化(Standardization,又称Z-score normalization)
源码:
from sklearn.preprocessing import StandardScaler
data = [[-2, 3], [1, 4], [0, 8], [-1, 17],[2,5],[6,1]]
data=pd.DataFrame(data)
scaler = StandardScaler() #实例化StandardScaler对象
scaler = scaler.fit(data) #训练,在这里本质是生成min(x)和max(x)
result = scaler.transform(data) #归一化数据
###上面忘记说了 fit和transform 可以一步
result = scaler.fit_transform(data)
result #在Pycharm中使用 print(result)
result_inverse=scaler.inverse_transform(result)
result_inverse #在Pycharm中使用 print(result_inverse )
result.mean() #在Pycharm中使用 print(result.mean() )
result.std() #在Pycharm中使用 print(result.std())
preprocessing.MaxAbsScaler
MaxAbsScaler:转换由向量列组成的数据集,将每个特征调整到[-1,1]的范围,它通过每个特征内的最大绝对值来划分。
源码:
from sklearn.preprocessing import MaxAbsScaler
data = [[-2, 3], [1, 4], [0, 8], [-1, 17],[2,5],[6,1]]
data=pd.DataFrame(data)
scaler = MaxAbsScaler() #实例化MaxAbsScaler对象
###上面忘记说了 fit和transform 可以一步
result = scaler.fit_transform(data)
result #在Pycharm中使用 print(result)
data_org = scaler.inverse_transform(result)
data_org #在Pycharm中使用 print(data_org)
剩下的还有很多具体官网查看(https://scikit-learn.org/stable/modules/classes.html#module-sklearn.preprocessing)
2.类别类型数据
对于数据来讲可能会出现类别数据,遇到这样的数据我们怎么去处理呢?例如:对于我们的出生地信息来自全国各市,如何我们用地级市来表示就会出现这样的情况:A->巴中市,B->成都市,C->上海市,D->北京市。这时候有人会说:那我们人为的显式去指定 巴中市=1,成都市=2,上海市=3,北京市=4。这样是能区分各个省市,但是给算法带来了很多麻烦,我们人为的可以这样显式认为这样的对应关系,但是对于计算机来讲1+2=3,那么对于计算机来讲就会存在这样的问题:巴中市+成都市=上海市,或者22=4 成都市成都市=北京市。这样的数字之间的关系,这样的情况会大大影响算法的效果,所以对于这样的类别的数据,我们就需要单独的用其他的处理方式去处理。这些特征值并不是连续的,而是离散的,无序的。通常我们需要对其进行特征数字化。
OneHotEncoder
它可以实现将分类特征的每个元素转化为一个数字数组(来源于官网)。
对于onehot编码来讲他的作用就是将类别数据转化为数字数组(并且只有0和1)。我们将所有的类别(去重)排列,所有的类别长度就是onehot数组长度。例如[[“巴中市”],[“成都市”],[“上海市”],[“北京市”]],对于出现的位置我们在数组对应的位置赋值为1,不出现的位置为0.那么对于以上数据"巴中市"而言它所对于的onehot编码就是[1,0,0,0],同理对于"上海市"而言;对于的onehot编码就是[0,0,1,0]。用以下一张图来展示:
原理大家都明白了,现在上代码:
但是对于onehot编码来讲存在一个问题:
每种表达每次只有1个位于高位为1,其余均位于低位为0。这造成了独热表示具有高稀疏的特性。例如一个很多的类别那么这个编码后的数组很长,但是里面只有一个位置的数为1,其余全部为0,意义不大而且造成了高维稀疏的特性。
2.LabelEncoder
LabelEncoder:将n个类别编码为0~n-1之间的整数[0,n-1]
源码:
from sklearn.preprocessing import LabelEncoder
X = np.array([["巴中市"],["成都市"],["上海市"],["北京市"]])
lableEncoder = LabelEncoder()
res = lableEncoder.fit_transform(X)
lableEncoder.inverse_transform([0])
lableEncoder.inverse_transform([1])
lableEncoder.inverse_transform([2])
lableEncoder.inverse_transform([3])
3.OrdinalEncoder
OrdinalEncoder:将类别特征编码为整数数组
处理连续型特征:二值化与分段
1.Binarizer
根据阈值将数据二值化(将特征值设置为0或1),用于处理连续型变量。大于阈值的值映射为1,而小于或等于阈值的值映射为0。默认阈值为0时,特征中所有的正值都映射到1。二值化是对文本计数数据的常见操作,分析人员可以决定仅考虑某种现象的存在与否。它还可以用作考虑布尔随机变量的估计器的预处理步骤(例如,使用贝叶斯设置中的伯努利分布建模)。
2.KBinsDiscretizer
KBinsDiscretizer:这是将连续型变量划分为分类变量的类,能够将连续型变量排序后按顺序分箱后编码。
文章最后:感谢大家关注我的公众号:
知乎:算法小佩奇