本文简要的总结了特征对齐和对特征进行编码的一些方法。



数据对齐

Z分数标准化

    将数据转换成服从标准正太分布的数据

    $$

    \hat x = \frac{x-\mu}{\sigma}

    $$

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

scaler.fit_transform(data)


归一化

    将数据缩放到0-1之间,注意对于稀疏数据,最好不要使用归一化,因为稀疏数据大部分是由0构成,归一化之后,反而将数据变得稠密了

    $$

    \hat x = \frac{x-min(x)}{max(x)-min(x)}

    $$

from sklearn.preprocessing import MinMaxScaler
mms = MinMaxScaler(feature_range=[5,10]) #设置归一化区间
result = mms.fit_transform(data)

data = mms.inverse_transform(result) #反向推理


行归一化

行归一化不是计算每列的统计值(均值、最小值、最大值等),而是会保证每行有单位范数(unit norm),意味着每行的向量长度相同。x=( x1, x2,…, xn) 那么行归一化算法如下所示:

\(x_{new} = \frac{x}{||x||}\)

from sklearn.preprocessing import Normalizer
normalize = Normalizer()
data = pd.DataFrame(normalize.fit_transform(data)

#行归一化的平均范数是1
np.sqrt((data**2).sum(axis=1)).sum()


默认使用的是L2范数,其中:


\[||x|| = \sqrt{(x_1^2+x_2^2+...+x_n^2)}\]


用途

有一些算法会容易受到数据尺度的影响

KNN——因为依赖欧几里得距离, 所以要对特征进行归一化

K均值聚类——和KNN的原因一样;

逻辑回归、支持向量机、神经网络——如果使用梯度下降来学习权重,归一化之后可以增加收敛速度。

主成分分析——特征向量将偏向较大的列,所以最好也进行归一化。

数据编码

离散型数据

(1) LabelEncoder

将文本型标签变成数字型,主要针对于类别数据,例如数据集的标签,可以进行数字化。

from sklearn.preprocessing import LabelEncoder

from sklearn.preprocessing import LabelEncoder
data.iloc[:,-1] = LabelEncoder().fit_transform(data.iloc[:,-1])

#属性
.classes_ #属性.classes_查看标签中究竟有多少类别

inverse_transform(label) #使用inverse_transform可以逆转


(2) OrdinalEncoder

能够将文本型分类特征转换为浮点数字,例如 A,B,C转换成了0.0 , 1.0 , 2.0,

OrdinalEncoder可以用来处理有序变量,例如体重,数字的大小是有关系的,所以使用OrdinalEncoder

from sklearn.preprocessing import OrdinalEncoder
data_.iloc[:,1:-1] = OrdinalEncoder().fit_transform(data_.iloc[:,1:-1])

#接口categories_对应LabelEncoder的接口classes_,一模一样的功能
OrdinalEncoder().fit(data_.iloc[:,1:-1]).categories_


(3) OneHotEncoder

one-hot只要用于名义变量,也就是有我 没有你的变量,这类变量直接没有明确的计算关系,都是独立的,所以使用one-hot最为合适

from sklearn.preprocessing import OneHotEncoder
X = data.iloc[:,1:-1]

enc = OneHotEncoder(categories='auto').fit(X)


连续性数据

(1) Binarizer

根据阈值将数据二值化(将特征值设置为0或1),用于处理连续型变量。大于阈值的值映射为1,而小于或等于阈值的值映射为0。默认阈值为0时,特征中所有的正值都映射到1。二值化是对文本计数数据的常见操作,分析人员可以决定仅考虑某种现象的存在与否。它还可以用作考虑布尔随机变量的估计器的预处理步骤(例如,使用贝叶斯设置中的伯努利分布建模)

data_2 = data.copy()

from sklearn.preprocessing import Binarizer
X = data_2.iloc[:,0].values.reshape(-1,1) #类为特征专用,所以不能使用一维数组
transformer = Binarizer(threshold=30).fit_transform(X)

transformer


(2) KBinsDiscretizer

主要是对连续数据进行分段处理, 可以通过参数进行比较灵活的分段

from sklearn.preprocessing import KBinsDiscretizer

X = data.iloc[:,0].values.reshape(-1,1)
est = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform')
est.fit_transform(X)

#查看转换后分的箱:变成了一列中的三箱
set(est.fit_transform(X).ravel())

est = KBinsDiscretizer(n_bins=3, encode='onehot', strategy='uniform')
#查看转换后分的箱:变成了哑变量
est.fit_transform(X).toarray()


参数:

n_bins: 分箱的个数,默认为5

encode:编码方式,分箱之后使用什么方式进行编码,有几种常见的可选项,"one-hot", "ordinal", "onehot-dense" 等。

strategy: 如何分箱,分箱的宽度等,有几种方式

  • "uniform": 按照等宽进行分箱,箱子最大宽度为 ( f.max() - f.min() ) / ( n_bings) f为特征。
  • "quantile": 等位分箱,每个箱子里面样本量相同。
  • "kmeans": 表示按照聚类分箱

(3) 树模型

可以构建一个树模型,然后通过树的分支来对模型进行分箱,这个没有具体操作过,所以简单提一下。

Entity Embedding

Entity Embedding 可以将变量直接编码成一个向量,如果想要用基于神经网络的方法去训练离散型数据的话,这个方法非常建议使用。

(1) 离散变量

本质上就等价于一个全连接层神经网络作为编码,举个例子:

数据的特征首先进行one-hot 然后假设有三个类别,N个样本的话,就可以的到一个 N*3 的one-hot表征,这个时候,可以定义一个Embedding 尺寸为(3,M), M 表示要转换的维度,于是,特征通过相乘就转换为了

(N,3)x (3,M) -> (N,M)

具体怎么实现,两种方法,第一是直接通过标签训练这个矩阵,第二是直接加入一个Embedding层,然后和其他特征一起训练就可以了 , 其实也可以理解为NLP中的词嵌入层,直接加入一个nn.Embedding() 层就可以了。

(2) 连续变量

针对于连续型变量,想要进行Entity Embedding的话,可以进行分箱操作。 如下图所示,首先,是对连续型变量进行分组,分组后对应一个值,例如均值或者中值,用这个值\(c_i\)表示。 之后来了新值之后,可以先和\(c_i\)做求距离操作,然后进行softmax,这样可以得到一个权重w,用来表示这个值和各个箱子的距离。然后权重w在和Embedding() 层相乘,就可以得到最终的表征了。

举个例子:

首先 Embedding层尺寸为: (N , M )

x 为输入,尺寸为 ( B, 1), 这里B 是batch的数量, x 是一个连续型的变量,输入是一个浮点型数据。之后,x 和每一个 分箱的中心代表值\(c_i\) 做求距离操作,距离越近,表示这个值越应该属于这个箱子,这个时候,对距离做softmax操作,可以得到一个权重w, 尺寸为( B, N) , 注意这里分母加了一项防止除0


\[w = softmax(\frac{1}{|x_b-c_i|+\epsilon}|)\]


最后,得到的权重和Embedding相乘就可以得到最终的表征了, 最后输出的是 (B,M) 维度的表征。((B, N ) * (N, M ) = (B ,M))

    $$

    r_x = w * Embeeding()

    $$

参考

《特征工程入门与实践》

《精通特征工程》

《菜菜sklearn》