专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)

栏目: IT技术 · 发布时间: 5年前

内容简介:数据预处理后,我们生成了大量的新变量(比如独热编码生成了大量仅包含0或1的变量)。但实际上,部分新生成的变量可能是多余:一方面它们本身不一定包含有用的信息,故无法提高模型性能;另一方面过这些多余变量在构建模型时会消耗大量内存和计算能力。因此,我们应该进行特征选择并选择特征子集进行建模。项目地址:

数据预处理后,我们生成了大量的新变量(比如独热编码生成了大量仅包含0或1的变量)。但实际上,部分新生成的变量可能是多余:一方面它们本身不一定包含有用的信息,故无法提高模型性能;另一方面过这些多余变量在构建模型时会消耗大量内存和计算能力。因此,我们应该进行特征选择并选择特征子集进行建模。

项目地址:

https://github.com/YC-Coder-Chen/feature-engineering-handbook/blob/master/%E4%B8%AD%E6%96%87%E7%89%88.md

本文将介绍特征工程中的 Wrapper Methods 封装方法。

目录:

专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)

封装方法将特征选择问题视作搜索问题,即其目标为从特征子集集合中搜索出一个最佳的子集,而这一子集在模型中表现最佳。在每一步中,其在特征子集上训练模型,然后对其进行评估,并在下一步继续调整特征子集,重新训练评估,直到找到最佳子集或达到最大迭代次数为止。穷尽搜索在封装方法中为NP-Hard,故人们提出了一些方法来降低封装方法所需要的迭代次数,以便可以在有限的时间内达到一个较好的效果。

专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)

1.2.1 Deterministic Algorithms 确定性算法

在不考虑模型随机性的情况下,给定相同的数据输入,确定性算法将始终输出相同的最优特征子集。

顺序向前选择(SFS),顺序向后选择(SBS)均为确定性算法。顺序向前选择(SFS)方法将从最优单变量模型开始,然后在迭代中,其会在上一步变量子集的基础上,以穷举的方法在现有变量子集中增加一个新变量,使得新增一个变量后的变量子集可以获得最大的模型表现提升。迭代将持续直到所选变量的数量满足要求为止。

顺序向后选择(SBS)则从适合一个包含所有变量的模型开始,然后在迭代中,其会在上一步变量子集的基础上,以穷举的方法在现有变量子集中删除一个对模型负影响最低的变量,直到所选特征的数量满足要求为止。

但是顺序向前选择(SFS)方法和顺序向后选择(SBS)均为逐步(step-wise)的方法,都可能会陷入局部最优状态。

1.2.1.1 Recursive Feature Elimination (SBS) 递归式特征消除

在sklearn中,它仅实现递归特征消除(SBS)方法。其提供了两个函数来实现这一方法,一个是RFE,另一个是RFECV。与RFE函数相比,REFCV使用交叉验证的结果来选择最优的特征数量,而在RFE中,要选择的特征数量由用户预定义。

# RFE函数 演示
import numpy as np
from sklearn.feature_selection import RFE

# 直接载入数据集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 数据集来演示

# 选择前15000个观测点作为训练集
# 剩下的作为测试集
train_set = X[0:15000,:]
test_set = X[15000:,]
train_y = y[0:15000]

# 选择用于衡量子集表现的有监督的机器学习模型
from sklearn.ensemble import ExtraTreesRegressor # 使用ExtraTrees 模型作为示范
clf = ExtraTreesRegressor(n_estimators=25)
selector = RFE(estimator = clf, n_features_to_select = 4, step = 1) 
# 与RFECV不同,此处RFE函数需要用户定义选择的变量数量,此处设置为选择4个最好的变量,每一步我们仅删除一个变量

selector = selector.fit(train_set, train_y) # 在训练集上训练

transformed_train = train_set[:,selector.support_]  # 转换训练集
assert np.array_equal(transformed_train, train_set[:,[0,5,6,7]]) # 选择了第一个,第六个,第七个及第八个变量

transformed_test = test_set[:,selector.support_] # 转换训练集
assert np.array_equal(transformed_test, test_set[:,[0,5,6,7]]) # 选择了第一个,第六个,第七个及第八个变量
# RFECV 函数 演示
import numpy as np
from sklearn.feature_selection import RFECV

# 直接载入数据集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 数据集来演示

# 选择前15000个观测点作为训练集
# 剩下的作为测试集
train_set = X[0:15000,:]
test_set = X[15000:,]
train_y = y[0:15000]

# 选择用于衡量子集表现的有监督的机器学习模型
from sklearn.ensemble import ExtraTreesRegressor # 使用ExtraTrees 模型作为示范
clf = ExtraTreesRegressor(n_estimators=25)
selector = RFECV(estimator = clf, step = 1, cv = 5) # 使用5折交叉验证
# 每一步我们仅删除一个变量
selector = selector.fit(train_set, train_y)

transformed_train = train_set[:,selector.support_]  # 转换训练集
assert np.array_equal(transformed_train, train_set) # 选择了所有的变量

transformed_test = test_set[:,selector.support_] # 转换训练集
assert np.array_equal(transformed_test, test_set) # 选择了所有的变量

1.2.2 Randomized Algorithms 随机方法

与确定性算法相比,随机方法在搜索最佳特征子集时引入了一定程度的随机性。因此,在相同数据输入的情形下,它可能会输出不同的最优特征子集结果,但此方法中的随机性将有助于避免模型陷入局部最优结果。

1.2.2.1 Simulated Annealing (SA) 基于模拟退火特征选择

模拟退火是一种随机最优化方法,近年来被引入到特征选择领域。在每一步中,我们将根据当前的最优特征子集随机选择一个特征子集。若新的特征子集效果更好,那么我们将采用它并更新当前最优特征子集。若新特征子集的表现不佳,我们仍会以一定的概率接受它,这个接受概率取决于当前的状态(温度)。

以一定的概率接受变现不佳的特征子集对于模拟退火算法至关重要,因为这有助于算法避免陷入局部最优状态。随着迭代的进行,模拟退火算法可收敛为良好且稳定的最终结果。

由于未发现能较好实现SA算法的函数,因此我编写了一个 python 脚本来实现SA算法,以供您参考。其能够很好地兼容sklearn中的模型,支持分类及回归问题。它还提供了内置交叉验证方法。

公式:

在每一步中,接受表现不佳的特征子集的概率为:

专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)

Prob为接受表现不佳的特征子集的概率, 为新特征子集的损失(loss), 为新特征子集创建前的最优(最低)损失(loss), _ 为当前的温度。模拟退火的伪代码为:

专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)

回归问题演示

import sys 
sys.path.append("..") 
from SA import Simulated_Annealing # 导入我们撰写的模块

# 直接载入数据集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 数据集来演示

# 选择前15000个观测点作为训练集
# 剩下的作为测试集
train_set = X[0:15000,:]
test_set = X[15000:,]
train_y = y[0:15000]

# 选择用于衡量子集表现的有监督的机器学习模型
from sklearn.ensemble import ExtraTreesRegressor # 使用ExtraTrees 模型作为示范

# 选择模拟退火中评价特征子集的的损失函数
from sklearn.metrics import mean_squared_error # 回归问题我们使用MSE

clf = ExtraTreesRegressor(n_estimators=25)
selector = Simulated_Annealing(loss_func = mean_squared_error, estimator = clf, 
                               init_temp = 0.2, min_temp = 0.005, iteration = 10, alpha = 0.9)
# 在训练集中训练
# SA.py中有具体每个参数的含义,此处不赘述

selector.fit(X_train = train_set, y_train = train_y, cv = 5) # 使用5折交叉验证

transformed_train = selector.transform(train_set) # 转换训练集
transformed_test = selector.transform(test_set)  # 转换测试集
selector.best_sol # 返回最优特征的索引
selector.best_loss; # 返回最优特征子集对应的损失

分类问题演示

import sys 
sys.path.append("..") 
import numpy as np
import random
from SA import Simulated_Annealing # 导入我们撰写的模块

from sklearn.datasets import load_iris  # 利用iris数据作为演示数据集

# 载入数据集
iris = load_iris()
X, y = iris.data, iris.target

# iris 数据集使用前需要被打乱顺序
np.random.seed(1234)
idx = np.random.permutation(len(X))
X = X[idx]
y = y[idx]

# 选择前100个观测点作为训练集
# 剩下的前20个观测点作为验证集,剩下的30个观测作为测试集
train_set = X[0:100,:]
val_set = X[100:120,:]
test_set = X[120:,:]

train_y = y[0:100]
val_y = y[100:120]
test_y = y[120:]

# 重制随机种子 
# 随机方法需要随机性的存在
random.seed()
np.random.seed()

# 选择用于衡量子集表现的有监督的机器学习模型
from sklearn.ensemble import ExtraTreesClassifier # we use extratree as predictive model

# 选择模拟退火中评价特征子集的的损失函数
from sklearn.metrics import log_loss # 回归问题中,我们使用交叉熵损失函数

clf = ExtraTreesClassifier(n_estimators=25)
selector = Simulated_Annealing(loss_func = log_loss, estimator = clf, 
                               init_temp = 0.2, min_temp = 0.005, iteration = 10, 
                               alpha = 0.9, predict_type = 'predict_proba')
# 在训练集中训练
# SA.py中有具体每个参数的含义,此处不赘述

selector.fit(X_train = train_set, y_train = train_y, X_val = val_set, 
             y_val = val_y, stop_point = 15) 
# 此函数允许用户导入自己定义的验证集,此处尝试一下

transformed_train = selector.transform(train_set)  # 转换训练集
transformed_test = selector.transform(test_set)  # 转换测试集
selector.best_sol # 返回最优特征的索引
selector.best_loss; # 返回最优特征子集对应的损失

1.2.2.2 Genetic Algorithm (GA) 基于基因算法特征选择

遗传算法是一种基于进化生物学概念的最优化搜索算法。它借鉴了自然界中的进化过程,并通过允许个体候选解通过“交叉”和“变异”来进化得到更优的候选解及种群。其还结合了自然界中的竞争理念,即仅允许最合适或最优的几个候选解“生存”下来并“繁殖”其后代。经过种群及个体候选解的持续迭代,基因算法(GA)会收敛到优化解决方案。

与模拟退火类似,我也编写了一个python脚本来实现GA算法,以供您参考。它提供了两种算法,包括“one-max”和“ NSGA2”。“one-max”为传统的单目标GA算法,“NSGA2”则为一个多目标GA算法。在特征选择中,“one-max”的目标是减少模拟在验证集上的损失,而“NSGA2”的目标一是减少损失,二是同时要最小化特征子集中特征的数量。

此python脚本能够很好地兼容sklearn中的模型,支持分类及回归问题。它还提供了内置交叉验证方法。

基因算法的伪代码如下:

专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)

回归问题演示

import sys 
sys.path.append("..") 
from GA import Genetic_Algorithm # 导入我们撰写的模块

# 直接载入数据集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 数据集来演示

# 选择前15000个观测点作为训练集
# 剩下的作为测试集
train_set = X[0:15000,:]
test_set = X[15000:,]
train_y = y[0:15000]

# 选择用于衡量子集表现的有监督的机器学习模型
from sklearn.ensemble import ExtraTreesRegressor # 使用ExtraTrees 模型作为示范

# 选择模拟退火中评价特征子集的的损失函数
from sklearn.metrics import mean_squared_error # 回归问题我们使用MSE

clf = ExtraTreesRegressor(n_estimators=25)
selector = Genetic_Algorithm(loss_func = mean_squared_error, estimator = clf, 
                             n_gen = 10, n_pop = 20, algorithm = 'NSGA2')
# 在训练集中训练
# GA.py中有具体每个参数的含义,此处不赘述

selector.fit(X_train = train_set, y_train = train_y, cv = 5) # 使用5折交叉验证

transformed_train = selector.transform(train_set) # 转换训练集
transformed_test = selector.transform(test_set)  # 转换测试集
selector.best_sol # 返回最优特征的索引
selector.best_loss; # 返回最优特征子集对应的损失

分类问题演示

import sys 
sys.path.append("..") 
import numpy as np
import random
from GA import Genetic_Algorithm # 导入我们撰写的模块

from sklearn.datasets import load_iris  # 利用iris数据作为演示数据集

# 载入数据集
iris = load_iris()
X, y = iris.data, iris.target

# iris 数据集使用前需要被打乱顺序
np.random.seed(1234)
idx = np.random.permutation(len(X))
X = X[idx]
y = y[idx]

# 选择前100个观测点作为训练集
# 剩下的前20个观测点作为验证集,剩下的30个观测作为测试集
train_set = X[0:100,:]
val_set = X[100:120,:]
test_set = X[120:,:]

train_y = y[0:100]
val_y = y[100:120]
test_y = y[120:]

# 重制随机种子 
# 随机方法需要随机性的存在
random.seed()
np.random.seed()

# 选择用于衡量子集表现的有监督的机器学习模型
from sklearn.ensemble import ExtraTreesClassifier # we use extratree as predictive model

# 选择模拟退火中评价特征子集的的损失函数
from sklearn.metrics import log_loss # 回归问题中,我们使用交叉熵损失函数

clf = ExtraTreesClassifier(n_estimators=25)
selector = Genetic_Algorithm(loss_func = log_loss, estimator = clf, 
                             n_gen = 15, n_pop = 10, predict_type = 'predict_proba')
# 在训练集中训练
# GA.py中有具体每个参数的含义,此处不赘述

selector.fit(X_train = train_set, y_train = train_y, X_val = val_set, 
             y_val = val_y, stop_point = 15) 
# 此函数允许用户导入自己定义的验证集,此处尝试一下

transformed_train = selector.transform(train_set)  # 转换训练集
transformed_test = selector.transform(test_set)  # 转换测试集
selector.best_sol # 返回最优特征的索引
selector.best_loss; # 返回最优特征子集对应的损失

基于 Jupyter 的特征工程手册:特征选择:

专栏 | 基于 Jupyter 的特征工程手册:特征选择(一)

专栏 | 基于 Jupyter 的特征工程手册:特征选择(二)

专栏 | 基于 Jupyter 的特征工程手册:特征选择(三)

中文版 Jupyter 地址:

https://github.com/YC-Coder-Chen/feature-engineering-handbook/tree/master/%E4%B8%AD%E6%96%87%E7%89%88

本文首发于公众号:AI有道(ID: redstonewill),欢迎关注!

专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Numerical Recipes 3rd Edition

Numerical Recipes 3rd Edition

William H. Press、Saul A. Teukolsky、William T. Vetterling、Brian P. Flannery / Cambridge University Press / 2007-9-6 / GBP 64.99

Do you want easy access to the latest methods in scientific computing? This greatly expanded third edition of Numerical Recipes has it, with wider coverage than ever before, many new, expanded and upd......一起来看看 《Numerical Recipes 3rd Edition》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试