scikit-learn中的自动模型选择和复合特征空间

简介: scikit-learn中的自动模型选择和复合特征空间

有时,机器学习模型的可能配置即使没有上千种,也有数百种,这使得手工找到最佳配置的可能性变得不可能,因此自动化是必不可少的。在处理复合特征空间时尤其如此,在复合特征空间中,我们希望对数据集中的不同特征应用不同的转换。一个很好的例子是将文本文档与数字数据相结合,然而,在scikit-learn中,我找不到关于如何自动建模这种类型的特征空间的信息。

使用scikit-learn管道可以更有效地工作,而不是手动将文本转换成词袋,然后再手动添加一些数字列。这篇文章将告诉你如何去做。

使用管道允许你将一系列转换步骤和评估器(分类器或回归器)视为单个模型,称为复合评估器。这不仅使你的代码保持整洁并防止训练集和测试集之间的信息泄漏,而且还允许你将转换步骤视为模型的超参数,然后通过网格搜索在超参数空间中优化模型。这意味着你可以在文本数据的同时试验不同的数值特征组合,以及不同的文本处理方法,等等。

在接下来的内容中,你将看到如何构建这样一个系统:将带标签的文本文档集合作为输入;自动生成一些数值特征;转换不同的数据类型;将数据传递给分类器;然后搜索特征和转换的不同组合,以找到性能最佳的模型。

模型构建

我使用的是垃圾短信数据集,可以从UCI机器学习库下载,它包含两列:一列短信文本和一个相应的标签列,包含字符串' Spam '和' ham ',这是我们必须预测的。和往常一样,整个项目代码都可以在GitHub上找到(https://github.com/job9931/Blog-notebooks/tree/main/automated_model_selection)。

第一步是定义要应用于数据集的转换。要在scikit-learn管道中包含数据转换,我们必须把它写成类,而不是普通的Python函数;一开始这可能听起来令人生畏,但它很简单。另一种方法是简单地定义一个普通的Python函数,并将其传递给FunctionTransformer类,从而将其转换为一个scikit-learn transformer对象。然而,在这里,我将向你展示更多的手工方法,这样你就可以看到实际发生了什么,因为我认为它有助于理解scikit-learn是如何工作的。

你创建一个类,它继承了scikit-learn提供的BaseEstimator和TransformerMixin类,它们提供了创建与scikit-learn管道兼容的对象所需的属性和方法。然后,在init()方法中包含函数参数作为类属性,并使用将用于转换数据集的函数体覆盖transform()方法。我在下面提供了三个例子。

fromsklearn.baseimportBaseEstimator, TransformerMixinclassCountWords(BaseEstimator,TransformerMixin):
#createsadataframefromaseriesoftextdocumentsbycreatinganewcolumnnamedn_words,
#whichcontainsthenumberofwordsineachdocumentdef__init__(self,new_col_name):
self.new_col_name=new_col_namedeffit(self,series,y=None):
returnselfdeftransform(self,series):
n_words_col=series.apply(lambdax: len(x.split(' '))).rename(self.new_col_name)
returnpd.concat([series, n_words_col], axis=1)
classMeanWordLength(BaseEstimator,TransformerMixin):
#createsacolumnmeanlengthofwordsinmessagedef__init__(self,text_column):
self.text_column=text_columndeffit(self,dataframe,y=None):
returnselfdeftransform(self,dataframe):
dataframe['mean_word_length'] =dataframe[self.text_column].apply(lambdax:
sum(map(len,x.split(' ')
                                                                            ))/len(x.split(' ')))
returndataframeclassFeatureSelector(BaseEstimator,TransformerMixin):
#createsanewdataframeusingonlycolumnslistedinattribute_namesdef__init__(self,attribute_names):
self.attribute_names=attribute_namesdeffit(self, dataframe, y=None):
returnselfdeftransform(self, dataframe):
returndataframe[self.attribute_names].values

管道中使用的自定义转换器对象。在每个示例中,fit()方法不执行任何操作,所有工作都体现在transform()方法中。

前两个转换符用于创建新的数字特征,这里我选择使用文档中的单词数量和文档中单词的平均长度作为特征。由于我们的数据集只包含两列,文本和标签,我们的文本在分离标签列之后被存储为熊猫系列,我们应该在项目的一开始就这样做。因此,CountWords.transform()被设计为接受一个序列并返回一个数据流,因为我将使用它作为管道中的第一个转换器。

final transformer FeatureSelector将允许我们将各种特性作为模型的超参数。它的transform()方法接受列名列表,并返回一个仅包含这些列的DataFrame;通过向它传递不同的列名列表,我们可以在不同的特征空间中搜索以找到最佳的一个。这三个转换器提供了我们构建管道所需的所有附加功能。

构建管道

最终的管道由三个组件构成:初始管道对象、ColumnTransformer对象和估计器。第二个组件ColumnTransformer是0.20版本中引入的一个方便的类,它允许你对数据集的指定列应用单独的转换。在这里,我们将使用它将CountVectorizer应用到文本列,并将另一个管道num_pipeline应用到数值列,该管道包含FeatureSelector和scikit-learn的SimpleImputer类。整个管道结构如图所示:

管道示意图。整个对象(称为复合估计器)可以用作模型;所有的转换器和估计器对象以及它们的参数,都成为我们模型的超参数。

工作流程如下

  1. 一系列文档进入管道,CountWords和MeanWordLength在管道中创建两个名为n_words和mean_word_length的数字列。
  2. 文本列被传递给CountVectorizer,而n_words和mean_word_length首先通过FeatureSelector,然后是SimpleImputer。
  3. 转换后的数据集被传递给估计器对象。
fromsklearn.pipelineimportPipelinefromsklearn.composeimportColumnTransformerfromsklearn.imputeimportSimpleImputerfromsklearn.feature_extraction.textimportCountVectorizerfromsklearn.svmimportSVC#Definethenamesofthetextandnumericalfeaturestext_features='text'numerical_features= ['n_words','mean_word_length']
#Createtheinitialpipelinewhichgeneratesnumericalcolumnspipeline_1=Pipeline([('n_words',CountWords('n_words')),
                        ('mean_length',MeanWordLength('text'))])
#ThenuseColumnTransformertoprocessthenumericalcolumnsandthetextcolumnseparately.
#Wedefineandapplynum_pipelinetothenumericalcolumnsandCountVectorizertothetextcolumnnum_pipeline=Pipeline([('selector',FeatureSelector(numerical_features)),
                          ('imp',SimpleImputer())])
pipeline_2=ColumnTransformer([
        ("txt", CountVectorizer(), 'text'),
        ("num", num_pipeline,['n_words','mean_word_length']),
    ])
#Buildthefinalpipelineusingpipeline_1andpipeline_2andanestimator, inthiscaseSVC()
pipeline=Pipeline([('add_numerical',pipeline_1),
                      ('transform',pipeline_2),
                      ('clf',SVC())])

最终的管道由初始化对象、ColumnTransformer对象和估计器对象组成。注意,ColumnTransformer可以将整个管道应用于某些列。

在上面的代码示例中,我们使用CountVectorizer和SimpleImputer的默认参数,同时保留数字列,并使用支持向量分类器作为估计器。这最后一个管道是我们的复合估计器,它里面的每个对象,以及这些对象的参数,都是一个超参数,我们可以自由地改变它。这意味着我们可以搜索不同的特征空间、不同的向量化设置和不同的估计器对象。

通过网格搜索选择最佳模型

使用复合估计器设置,很容易找到最佳执行模型;你所需要做的就是创建一个字典,指定想要改变的超参数和想要测试的值。然后将其传递给scikit-learn的GridSearchCV类,该类对每个超参数值组合使用交叉验证来评估模型,然后返回最好的。

fromsklearn.model_selectionimportGridSearchCV#paramsisadictionary, thekeysarethehyperparameterandthevaulesarealistofvalues#tosearchover.
params= [
    {'transform__txt__max_features':[None,100,10],
'transform__num__selector__attribute_names': [['n_words'],
                                                  ['mean_word_length'],
                                                  ['n_words','mean_word_length']]}
]
#GridSearchCVbydefaultstratifiesourcross-validation#andretrainsmodelonthebestsetofhyperparametersmodel=GridSearchCV(pipeline,params,scoring='balanced_accuracy',cv=5)
model.fit(X_train, y_train)
#displayalloftheresultsofthegridsearchprint(model.cv_results_)
#displaythemeanscoresforeachcombinationofhyperparametersprint(model.cv_results_[model.cv_results_['mean_test_score']])


参数网格被定义为一个字典,键是超参数,值是要搜索的值的列表。然后将其与复合估计数器一起传递给GridSearchCV,并将其与训练数据相匹配。

我们的复合估计器总共有65个可调参数,但是,这里只改变了两个参数:使用的数字列和CountVectorizer的max_features参数,该参数设置词汇表中使用的单词的最大数量。在代码中,你可以看到如何获得所有可用超参数的列表。下面是绘制在超参数空间上的平均平衡精度的可视化图。

当我们只使用一个数字列n_words并使用词汇表中的所有单词(即max_features = None)时,可以获得最佳性能。在交叉验证期间,该模型的平衡精度为0.94,在测试集上评估时为0.93。注意,如果你自己运行笔记本,确切的数字可能会改变。

在超参数网格上绘制了平衡精度图,显示了模型性能如何在超参数空间上变化。

总结

我们已经讨论了很多,特别是,如何通过设置一个复合评估器来自动化整个建模过程,复合评估器是包含在单个管道中的一系列转换和评估器。这不仅是一个很好的实践,而且是搜索大型超参数空间的唯一可行方法,在处理复合特征空间时经常出现这种情况。我们看到了将文本数据与数字数据组合在一起的示例,但是对于任何数据类型都可以很容易地遵循相同的过程,从而使你能够更快、更有效地工作。

目录
相关文章
|
8月前
|
机器学习/深度学习 数据采集 数据挖掘
基于 GARCH -LSTM 模型的混合方法进行时间序列预测研究(Python代码实现)
基于 GARCH -LSTM 模型的混合方法进行时间序列预测研究(Python代码实现)
289 2
|
7月前
|
机器学习/深度学习 数据采集 并行计算
多步预测系列 | LSTM、CNN、Transformer、TCN、串行、并行模型集合研究(Python代码实现)
多步预测系列 | LSTM、CNN、Transformer、TCN、串行、并行模型集合研究(Python代码实现)
830 2
|
10月前
|
存储 机器学习/深度学习 人工智能
稀疏矩阵存储模型比较与在Python中的实现方法探讨
本文探讨了稀疏矩阵的压缩存储模型及其在Python中的实现方法,涵盖COO、CSR、CSC等常见格式。通过`scipy.sparse`等工具,分析了稀疏矩阵在高效运算中的应用,如矩阵乘法和图结构分析。文章还结合实际场景(推荐系统、自然语言处理等),提供了优化建议及性能评估,并展望了稀疏计算与AI硬件协同的未来趋势。掌握稀疏矩阵技术,可显著提升大规模数据处理效率,为工程实践带来重要价值。
494 58
|
7月前
|
算法 安全 新能源
基于DistFlow的含分布式电源配电网优化模型【IEEE39节点】(Python代码实现)
基于DistFlow的含分布式电源配电网优化模型【IEEE39节点】(Python代码实现)
599 0
|
10月前
|
机器学习/深度学习 人工智能 PyTorch
200行python代码实现从Bigram模型到LLM
本文从零基础出发,逐步实现了一个类似GPT的Transformer模型。首先通过Bigram模型生成诗词,接着加入Positional Encoding实现位置信息编码,再引入Single Head Self-Attention机制计算token间的关系,并扩展到Multi-Head Self-Attention以增强表现力。随后添加FeedForward、Block结构、残差连接(Residual Connection)、投影(Projection)、层归一化(Layer Normalization)及Dropout等组件,最终调整超参数完成一个6层、6头、384维度的“0.0155B”模型
562 11
200行python代码实现从Bigram模型到LLM
|
8月前
|
机器学习/深度学习 算法 调度
【切负荷】计及切负荷和直流潮流(DC-OPF)风-火-储经济调度模型研究【IEEE24节点】(Python代码实现)
【切负荷】计及切负荷和直流潮流(DC-OPF)风-火-储经济调度模型研究【IEEE24节点】(Python代码实现)
379 0
|
11月前
|
机器学习/深度学习 人工智能 算法
Python+YOLO v8 实战:手把手教你打造专属 AI 视觉目标检测模型
本文介绍了如何使用 Python 和 YOLO v8 开发专属的 AI 视觉目标检测模型。首先讲解了 YOLO 的基本概念及其高效精准的特点,接着详细说明了环境搭建步骤,包括安装 Python、PyCharm 和 Ultralytics 库。随后引导读者加载预训练模型进行图片验证,并准备数据集以训练自定义模型。最后,展示了如何验证训练好的模型并提供示例代码。通过本文,你将学会从零开始打造自己的目标检测系统,满足实际场景需求。
11630 1
Python+YOLO v8 实战:手把手教你打造专属 AI 视觉目标检测模型
|
Python
Python音频处理-图解傅里叶分析
傅里叶分析是一种将函数表示为周期成分之和的方法,并通过离散傅里叶变换(DFT)将信号从时域转换到频域,提取频率特征。通过快速傅里叶变换(FFT),我们可分析方波的主要频率成分,并利用这些成分重建波形,直观展示频率域对原始信号的影响。
316 0
|
7月前
|
数据采集 机器学习/深度学习 人工智能
Python:现代编程的首选语言
Python:现代编程的首选语言
1143 102

热门文章

最新文章

推荐镜像

更多
下一篇
开通oss服务