机器学习特征工程方法的总结(持续更新……)

本文深入探讨特征工程的重要性,包括特征选择、特征缩放、互信息法、IV与WOE,以及递归特征消除等技术。同时,详细介绍了线性和非线性降维方法,如PCA、t-SNE、LLE和自编码器,帮助读者理解和应用这些方法提升机器学习模型性能。
摘要由CSDN通过智能技术生成

维度过高会造成数据稀疏,即所谓的“维灾难”,不利于模型的训练。我们在选取特征时需要遵守的一个准则就是:特征并非越多越好,而是越准确越好

特征缩放

特征缩放是对数据的大小进行调整。关于数据“标准化”、“归一化”的理解众说纷纭,对“normalization”的理解一直模糊不清。而且特征缩放也容易滥用,虽然特征缩放对大多数机器学习算法而言更加稳健,但是如果不了解数据,一上来就标准化有时会适得其反。
特征缩放主要分成两类:

  • 归一化(normalize):将数据视为向量,再将向量除以其范数(通常采用L2范数),有量纲,对应sklearn中normalize方法。针对数据集中单个样本进行缩放,适合依赖样本间相似性的算法。因会改变数据集中特征数值的分布,不适合依赖特征预测的算法。
  • 标准化(scale/standardize):对数据大小按照标准方法进行调整,使值位于特定范围内,无量纲。针对数据集中单个特征进行缩放。
    • Min-Max标准化方法:最大-最小值区间缩放,即减去最小值,再除以极差。标准化后数据位于[0,1]内,无量纲,对应sklearn中minmax_scale方法。
    • Z-score标准化方法:使用较多,通常直接称为标准化方法(standard),即减去均值,再除以标准差。标准化后数据均值为0,标准差为1,无量纲,对应sklearn中scale方法。

如何挑选标准化方法?

  • 一般概率模型(决策树等)不需要进行标准化,梯度优化模型需要(例如SVM)
  • 若度量样本距离方法采用二次型(例如内积),则可选择Normalization
  • 若需要特征集内特征拥有不同量纲,且部分“明显重要”的特征方差相对较小,可采用MinMaxScaler,可实现无量纲,且防止方差过小特征得不到有效利用
  • z-score与Min-Max一样可实现无量纲化,但若特征变量明显不符合正态分布,可能会造成较大偏差。
    注意:使用z-score前最好对特征变量可视化,观察变量是否服从正态分布。
from sklearn.preprocessing import scale, minmax_scale, normalize

Xn = normalize(X)  # 归一化,对应Normalizer类
Xs = scale(X)  # z-score标准化,对应StandardScaler
Xm = minmax_scale(X)  # min-max标准化,对应MinMaxScaler

挑选特征(filter)

机理分析

根据业务知识,进行机理分析,挑选对目标影响较大的特征。这一步尤为关键。

方差分析

方差一定程度上代表了该特征变异程度,方差过小的特征确定性高,不具分析价值,可考虑排除。

相关性分析

对特征与目标间以及特征间进行相关性分析、偏相关分析,排除冗余特征。需要注意的是很多传统统计检验方法(例如F检验)仅能发现线性相关关系

  1. 皮尔逊相关系数:适合定量特征的相关性分析。
  2. 偏相关分析:特征间可能存在复共线性关系,例如Fea1和Fea2都可由剩余特征线性表示,二者偏相关系数较小,那么Fea1和Fea2可能是冗余的。涉及多因变量问题时,可考虑典型相关分析
  3. 卡方检验:适合定性特征与定性目标的相关性分析。
from sklearn.feature_selection import SelectKBest, chi2
from sklearn.linear_model import LinearRegression
from sklearn.datasets import load_iris
import numpy as np


def partial_corr(y, x, z, normalize=False):
    """
    计算偏相关系数
    :param y: 考虑变量1
    :param x: 考虑变量2
    :param z: 其他所有变量
    :param normalize: 线性回归是否正则化
    :return: x与y的偏相关系数
    """
    reg1 = LinearRegression(normalize=normalize)
    reg2 = LinearRegression(normalize=normalize)
    reg1.fit(z, y)
    reg2.fit(z, x)
    residue1 = y - reg1.predict(z)
    residue2 = x - reg2.predict(z)
    return np.corrcoef(residue1.T, residue2.T)[0, 1]


data = load_iris()
X = data.data
y = data.target

Xk = SelectKBest(chi2, k=3).fit_transform(X, y) # 依据卡方检验,挑选3个与target相关性最大的特征

print(partial_corr(X[:, 0], X[:, 1], X[:, 2:]))

互信息法

相比很多的统计检验(例如F检验),互信息能检测出任何的相关关系。
互信息原本是用于计算离散变量X,Y间得相关关系,定义如下: M I ( X , Y ) = H ( X ) − H ( X ∣ Y ) = H ( X ) + H ( Y ) − H ( X , Y ) = ∑ p ( x , y ) l o g p ( x , y ) p ( x ) p ( y ) MI(X, Y) = H(X)-H(X|Y)=H(X)+H(Y)-H(X,Y)=\sum{p(x,y)log\frac{p(x, y)}{p(x)p(y)}} MI(X,Y)=H(X)H(XY)=H(X)+H(Y)H(X,Y)=p(x,y)logp(x)p(y)p(x,y)即X的熵减去基于Y的X条件熵。
若直接采用上述方法计算连续变量间或离散变量与连续变量间的MI,会造成比较达的误差。需要将连续变量离散化,可采用"binning"(装箱)方法以及应用 k k k近邻方法。根据Brian的实验,采用"binning"方法时,MI值受样本个数的影响将很大。Alexander提出结合 k k k近邻方法来估算连续变量间的MI,定义如下(见参考资料Estimating mutual information):
X,Y为连续变量,计算 N N N个样本点的k近邻样本及相应的 k k kth距离(切比雪夫距离)。映射到X轴一维空间中,统计每个样本 k k kth距离内样本个数 N x i N^i_x Nxi, 同理计算得到 N y i N^i_y Nyi,则 M I ( X , Y ) = ψ ( N ) + ψ ( k ) − ⟨ ψ ( N x + 1 ) + ψ ( N y + 1 ) ⟩ MI(X,Y)=\psi(N)+\psi(k)-\langle \psi(N_x+1)+\psi(N_y+1)\rangle MI(X,Y)=ψ(N)+ψ(k)ψ(Nx+1)+ψ(Ny+1)⟩其中, ψ \psi ψ是digamma函数 ⟨ ⟩ \langle\rangle 代表求均值。
Brian基于上述思想给出离散变量X与连续变量Y间MI的计算公式(见参考资料Mutual Information between Discrete and Continuous Data Sets): M I ( X , Y ) = ψ ( N ) + ψ ( k ) − ⟨ ψ ( m ) ⟩ − ⟨ ψ ( N x ) ⟩ MI(X,Y)=\psi(N)+\psi(k)-\langle \psi(m) \rangle - \langle \psi(N_x)\rangle MI(X,Y)=ψ(N)+ψ(k)ψ(m)⟩ψ(Nx)⟩即先不考虑X,将所有样本映射到Y轴一维空间,统计每个样本 k k kth距离内样本个数 m m m, 再根据离散变量X的取值,将样本分成若干组,统计组内每个样本 k k kth距离内样本个数 N x N_x Nx

from sklearn.feature_selection import mutual_info_regression, mutual_info_classif
print(mutual_info_classif(X, y)) # 计算特征与离散目标的互信息值
print(mutual_info_regression(X, y)) # 计算特征与连续目标的互信息值

Information Value (IV) and Weight of Evidence (WOE)

对于二分类问题,可通过计算每个特征与目标之间的IV值筛选出重要特征。
定义:二分类问题有“正类”即“负类”,设正类样本总数 N g N_g Ng, 负类样本总数 N b N_b Nb。另假设根据特征Fea可将数据集分成k组,第 i i i组中含正类 N g i N^i_g Ngi,负类 N b i N^i_b Nbi,则: D G i = N g i N g D B i = N b i N b W O E i = l n ( D G i D B i ) I V = ∑ i = 1 k ( D G i − D B i ) ∗ W O E i DG^i = \frac{N^i_g}{N_g} \\ DB^i=\frac{N^i_b}{N_b} \\ WOE^i = ln(\frac{DG^i}{DB^i})\\ IV=\sum^k_{i=1}(DG^i-DB^i)*WOE^i DGi=NgNgiDBi=NbNbiWOEi=ln(DBiDGi)IV=i=1k(DGiDBi)WOEi
一般,可根据如下规则判定特征的重要性:

IV预测能力
<0.02几乎无用
0.02-0.1较弱
0.1-0.3中等
0.3-0.5较强

0.5|无法判定,可能很强也可能很弱

def cal_iv(df, target, features=None):
    # 传入DataFrame, 根据某个字段计算iv值
    if features is None:
        features = list(df.columns)
        features.remove(target)
    from collections import Counter
    labels = Counter(df[target])  # 统计两类总数
    b, g = labels.keys()
    res_all = []
    for fea in features:
        split_points = df[fea].unique()
        res = pd.DataFrame(columns=['db', 'dg'])
        for i, p in enumerate(split_points):
            tp = df[df[fea] == p]
            tp_db = tp[tp[target] == b].shape[0] / labels[b]
            tp_dg = tp[tp[target] == g].shape[0] / labels[g]
            res.loc[i] = [tp_db, tp_dg]
        res['woe'] = np.log(res['dg'] / res['db'])
        res['iv'] = (res['dg'] - res['db']) * res['woe']
        res_all.append(res.iv.sum())
    ivs = pd.Series(res_all, index=features)
    ivs.sort_values(ascending=False, inplace=True)
    return ivs

递归特征消除(RFE)

选取一个估计器(例如GBDT),赋予每个特征权重,逐步从特征集合中删除权重最小的特征,直到特征集合中特征的数量达到目标值。示例如下:

from sklearn.feature_selection import RFECV
from sklearn.svm import SVC

svc = SVC()
rfe = RFECV(estimator=svc, step=1, min_features_to_select=3) # 根据svc赋予特征权重,每步删除权重最小的一个特征,最终保留3格特征

降维方法(dimension reduction)

将原始样本高维空间X映射到低维空间Y。

线性降维

可表示为 Y = W T X Y=W^TX Y=WTX
多维缩放(MDS):原始样本空间X有m个样本,特征维度为d0,变换后空间Y的特征维度为d1。在两个空间中,样本距离矩阵是一致的。由此计算得到,Y空间内样本的内积矩阵B与X空间一致,通过特征值分解B即得到Z空间内样本坐标。
主成分分析(PCA):映射到低维空间Z后,样本沿Z空间各个坐标轴的方差最大。
因子分析(FA):可以看作是主成分分析的推广,抽出的因子能更好地解释目标,因子往往具有明显的实际意义。该方法更加适合于特征存在异方差性
线性判别分析(LDA):LDA适合于监督学习中数据的降维。核心思想就是挑选出能够很好解释类间方差的主成分,相比PCA充分考虑了类标记的信息。

from sklearn.decomposition import FactorAnalysis, PCA
pca = PCA(n_components=2)
fa = FactorAnalysis(n_components=2, max_iter=1000)

非线性降维

可表示为 Y = Φ ( X ) Y=\Phi(X) Y=Φ(X)
核主成分分析(KPCA):通常运用核技巧(进行隐式非线性变化,因为在D和Z空间仅需要样本内积)的主成分分析方法。

流形学习(manifold learning)

流形就是连接在一起的区域。在机器学习领域,倾向于松散地定义为一组点,且只需要考虑少数嵌入在高维空间中的维度就能很好地近似。某点的维度指该点可局部变化方向的个数。例如一组点在高维空间种呈“8”字形分布,那么除了中间的交叉点维度是2之外,其他全是1。

t-SNE(t-Distributed Stochastic Neighbor Embedding)

t-SNE是最好的非线性降维算法之一,基本原理是将原始高维空间中的数据点之间的关系表示为联合概率 p i j p_{ij} pij,在低维空间中表示为 q i j q_{ij} qij,用KL散度(即损失函数)来衡量两个概率分布之间的距离。
p i j p_{ij} pij计算方法如下: p j ∣ i = e − ∣ ∣ x i − x j ∣ ∣ 2 / 2 σ 2 ∑ k = i̸ e − ∣ ∣ x i − x k ∣ ∣ 2 / 2 σ 2 p i j = p j ∣ i + p i ∣ j 2 n p_{j|i}=\frac{e^{-||x_i-x_j||^2/2\sigma^2}}{\sum_{k =\not i}e^{-||x_i-x_k||^2/2\sigma^2}} \\ p_{ij}=\frac{p_{j|i}+p_{i|j}}{2n} pji=k=ie∣∣xixk2/2σ2e∣∣xixj2/2σ2pij=2npji+pij式中, σ \sigma σ需要根据困惑度(perplexity) 确定,该值决定了以某个样本为中心,对其起作用得近邻数,因此 σ \sigma σ是一个n_sample维向量。
q i j q_{ij} qij计算方法如下: q i j = ( 1 + ∣ ∣ y i − y j ∣ ∣ 2 ) − 1 ∑ k = l̸ ( 1 + ∣ ∣ y k − y l ∣ ∣ 2 ) − 1 q_{ij}=\frac{(1+||y_i-y_j||^2)^{-1}}{\sum_{k =\not l}(1+||y_k-y_l||^2)^{-1}} qij=k=l(1+∣∣ykyl2)1(1+∣∣yiyj2)1
几点需要注意的地方(见参考资料6):

  1. perplexity:越大,算法越注重全局结构,故一般样本越多该值越大;过小的困惑度经常过度挖掘局部结构,导致没有意义的团簇;一般取值5-50之间。
  2. 当低维图像呈现"pinched"形状,建议延长迭代次数。
  3. 低维图像中团簇的大小是没有意义的,因为算法中的“距离”反映的是局部相对密度变化;同样团簇间的距离也没有重要参考意义,毕竟perplexity是一个全局参数。
  4. t-SNE是一个非常灵活的算法,建议多试验几个参数值。

等度量映射(Isomap)

Isomap可以视作MDS的一个延申。在高维空间中MDS直接根据点坐标计算点之间的距离有时不合理,例如计算位于曲面上两点距离。Isomap通过寻找两点之间的最短距离(例如Dijkstra算法),并以此作为两点之间的距离,从而构建样本距离矩阵,具体步骤有:

  1. 确定每个样本的最近邻样本点(方便寻找最短距离的下一个节点)
  2. 计算最短距离
  3. 采用MDS输出低维坐标

将训练样本高维坐标作为输入,低维坐标作为输出,构建非线性回归模型,则可将新样本的高维坐标转化为低维坐标。

局部线性嵌入(LLE)

故名思意,LLE尽量保持映射前后样本与其局部邻域内样本间距离不变。所谓"线性"是指在高维空间中将样本 x i x_i xi表示为邻域 Q i Q_i Qi内样本的线性组合 ∑ j ∈ Q i w i j x j \sum_{j \in Q_i}w_{ij}x_j jQiwijxj,则通过求解: m i n ∣ ∣ x i − ∑ j ∈ Q i w i j x j ∣ ∣ 2 2 s . t . ∑ w i j = 1 min\quad ||x_i-\sum_{j \in Q_i}w_{ij}x_j||_2^2 \\ s.t.\quad \sum w_{ij}=1 min∣∣xijQiwijxj22s.t.wij=1即得系数矩阵 w i j w_{ij} wij,然后特征值分解 ( I − W ) T ( I − W ) (I-W)^T(I-W) (IW)T(IW),选取前 d ′ d' d小个特征值对应特征向量,即为低维空间 Y T Y^T YT

谱嵌入(Spectral Embedding)

聚类分析中,谱聚类将原始样本空间映射到拉普拉斯空间可以视为一种降维方法。

# skleran中流形学习算法示例
from sklearn.manifold import TSNE, Isomap, LocallyLinearEmbedding, SpectralEmbedding
from sklearn.datasets import load_digits

tsne = TSNE(n_components=2,  # 低维空间维度
            perplexity=30,  # 困惑度
            early_exaggeration=12,  # 控制低维空间中团簇间的距离
            learning_rate=100,  # 学习率
            n_iter=2000)  # 迭代训练次数

isomap = Isomap(n_components=2, tol=1e-7)

lle = LocallyLinearEmbedding(n_neighbors=100, max_iter=5000, method='modified')

spe = SpectralEmbedding(n_neighbors=30)

if __name__ == '__main__':
    X, _ = load_digits(return_X_y=True)
    Y = tsne.fit_transform(X)

    import matplotlib.pyplot as plt

    plt.scatter(Y[:, 0], Y[:, 1])
    plt.show()

自编码器降维

见另一篇博客《自编码器、变分自编码器(VAE)简介以及Python实现》。

参考资料

  1. 《机器学习》周志华
  2. Estimating mutual information
  3. Mutual Information between Discrete and Continuous Data Sets
  4. http://ucanalytics.com/blogs/information-value-and-weight-of-evidencebanking-case/
  5. Visualizing Data using t-SNE
  6. How to Use t-SNE Effectively
  7. sklearn官方指导文档

注:如有不当之处,请指正。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值