机器学习完整解决流程演练 part1

原文链接:网页链接

作者:William Koehrsen


在这个系列中,我们要完成一个完整的机器学习项目,关于“Data Science for Good”问题,这个问题目标是预测哥斯达黎加的家庭贫困情况。这是一个kaggle竞赛,完整代码见作者的githubJupyter notebook on Kaggle


Problem and Approach

这个竞赛的目标是使用个人和家庭社会经济指标来预测家庭贫困。美洲开发银行(IDB)开发了这一问题,并提供了数据,目的是改进确定需要援助的家庭的传统方法。


贫困的标签分为四个级别,使这个问题成为一个多分类问题。


解决机器学习问题的一般步骤如下:

  1. 理解问题描述与数据

  2. 数据清洗/探索/分析

  3. 特征工程

  4. 模型比较

  5. 模型优化

  6. 解释结果



虽然这些步骤看起来比较僵化,但处理机器学习问题不是线性的,随着对问题和数据理解的深入,我们需要经常返回查看那些步骤是否有效并进行合适修改。第一部分Part1介绍前四步,后两步见Part2。


Understanding the Problem and Data

在理想情况下,我们都是问题领域的专家,可以为构建机器学习项目提供经验。但是实际上,我们常常处理来自新领域的数据,并且要在短时间内获取数据代表什么以及如何收集数据的知识。


幸运的是,我们可以在Kaggle上使用其他数据科学家共享的工作来相对加快速度。而且Kaggle有专门讨论区,你可以在那里向竞赛组织者提问。可以提出一些比较好的问题如‘根据相关领域的专家,是否针对这个问题最重要的变量’,‘数据是否有问题,是否需要注意数据的某些值或异常值’,‘数据是如何收集的,是否有异常值,其原因是人为的错误还是仍被视为有效值’。


部分数据的理解要深入理解数据的定义。最有效的方式就是浏览数据的每一列,以确保你直到数据代表什么。我发现这有点沉闷,所以我喜欢将这个过程与数据探索混合,阅读列描述,然后使用统计数据和图标探索列。


例如,我们知道meaneduc是该家庭的平均教育数量,然后我们可以根据标签画出meandeuc的分布看它在不同贫困水平之间是否有明显的差异。

机器学习完整解决流程演练 part1

这表明,贫困风险最小的家庭 - 非弱势群体 - 的平均受教育水平往往高于风险最高的群体。稍后在特征工程中,我们可以通过这个教育属性构建新特征,因为它似乎显示了目标标签之间的差异。


数据集总共有143列特征, 如果完成一个实际应用,你希望能够通过专家来理解每一列。但是我并没有详尽地探索这些,我阅读了数据的定义和观察其他数据科学家的工作来理解大多数的列。


另一点需要从问题和数据理解阶段建立的就是如何构建训练数据。在这个问题中,我们给出了一个数据表,其中每一行代表一个人,而列是特征。如果我们阅读问题定义,我们被告知要为每个家庭做出预测,这意味着我们的最终训练数据(以及测试数据)每个家庭应该有一行

机器学习完整解决流程演练 part1


Determine the metric

最后,我们要确保理解标签和问题的评价标准。标签是我们想要预测的,而指标是我们如何评估这些预测。对于这个问题,标签是整数,1-4分别代表四个不同的贫困级别,评价标准是Macro F1 score,度量值在0-1之间,越高模型性能越好。F1 score是二分类问题的通用度量。Macro是多分类问题的average选项之一,另一个选项是Micro average。它俩的具体区别见网页链接


了解度量标准后,找出如何使用您使用的任何工具进行计算。对于Scikit-Learn和Macro F1得分,代码为:

from sklearn.metrics import f1_score
score = f1_score(y_true,y_prediction,average = 'macro')


了解度量标准允许我们在交叉验证中评估我们的预测并使用应用到测试集,因此我们知道我们的选择对性能有何影响(如果有的话)。在这个比赛中给出了度量指标,但是在实际应用中,我们需要自己选择合适的度量指标。


Data Exploration and Data cleaning

数据探索,也叫探索性数据分析(EDA),是一个我们弄清出数据能告诉我们什么的开放过程,总结数据的主要特点,通常会用到可视化方法。随着我们发现可用于特征工程或发现异常的有趣趋势/模式,我们开始广泛并逐步磨练我们的分析。数据清理与探索密切相关,因为在我们进行建模之前,我们需要解决缺失值或异常值问题。为了便于数据探索的第一步,我们可以可视化训练数据的标签分布(我们没有给出测试标签)。

机器学习完整解决流程演练 part1


现在我们能从图中看出,我们的数据有类别不均衡问题,这让机器学习模型很难学习代表性不足的类别。许多算法尝试解决这个问题,比如在sklearn的随机森林算法中使用‘class weight = balanced’,但是它的表现不尽如人意。当我们遇到不平衡的分类问题时,我们还要确保使用分层抽样(stratified sampling)进行交叉验证,以便在每个折叠中获得相同的标签平衡(确保每一折具有与完整数据集相同的每个目标类的样本百分比)。

注:stratified sampling当数据集的每个类别的样本数量都很多时,与random sampling几乎没什么区别。但是当样本类偏斜,strtified sampling能确保训练集和测试集中的类分布与整体样本的类分布相同


为了更加熟悉数据,区分每一列的数据属于什么统计数据类型是很有帮助的。


  • float : These usually are continuous numeric variables 

  • int : Usually are either Boolean or ordinal (discrete with an ordering)    

  • object or category : Usually strings or mixed data types that must be converted in some manner before machine learning   e.g. (red,bule,yellow)


我使用统计类型来表示数据表示的内容 ( 例如,布尔值只能是1或0 )。 数据类型表示值存储在Python中的实际方式,如整数或浮点数。统计类型告诉我们如何处理特征工程的列。

(我通常为每种数据类型和统计类型配对,因为你会发现往往统计类型被存储为错误的数据类型)


我们查看这个问题中的整数列,我们会发现它们大多代表布尔值,因为列中可能的值只有两个。

机器学习完整解决流程演练 part1


我们通过观察数据类型为‘object’的列,发现两个疑问:有两列是id变量,剩余3列看起来是数值。

# Train is pandas dataframe of training data
train.select_dtypes('object').head()

机器学习完整解决流程演练 part1

这就是我们早期的数据理解发挥作用的地方。对于这3列,一些条目是‘yes’,一些是‘no’,剩余的都是浮点数。我们进行了背景研究,因此直到yes是1,no是0。通过这个信息,我们能可视化这些变量分布。

机器学习完整解决流程演练 part1

这是数据探索和数据清洗同时进行的很好的例子。我们发现某些数据不正确,改正它,然后通过探索数据来确保我们的改正是合适的。


Missing Values

一个非常重要的数据清洗工作就是处理缺失值。在Pandas中计算缺失值的总量和占比是非常简单的。

import pandas as pd

missing = pd.DataFrame(data.isnull().sum().rename(column = {'0':'total'}))
missing['percent']=missing['total']/len(data)

机器学习完整解决流程演练 part1

很多情况下,缺失值有其原因:v2a1列代表每月的房租,它缺失的原因是因为很多家庭拥有自己的房子。我们提取出没有月租的家庭,探索它们的房屋拥有状态。

机器学习完整解决流程演练 part1

基于上图,我们将v2a1列中的缺失值对应为拥有房子的家庭改为0。我们再增加一个布尔列,指示月租值是否缺失。


这一列的其他缺失值可以用相同的方式处理:使用其他列中的信息或关于这个问题的信息来填充缺失值,或者保留它们为缺失值。添加布尔列以指示缺失值也很有用,因为有时缺少值的信息很重要。需要注意的另一个关键点是,对于缺失值,我们经常要考虑使用其他列中的信息来填充缺失值,例如我们处理房租列所用的方法。


一旦我们处理了缺失值,异常和不正确的数据类型,我们就可以继续进行特征工程。我经常把数据探索看作一个贯穿始终的持续过程,而不是这一个阶段做完就不做了。例如,当我们进入特征工程时,我们可能想要探索我们创建的新变量。


数据科学过程是非线性的:虽然我们有一个大致的步骤框架,但是当我们深入研究问题时,我们经常会回过头来重做前面的步骤。


Feature Engineering

如果您关注我的工作,您就会知道我相信自动化功能工程 - 具有领域专业知识 - 将取代传统的手动特征工程。对于这个问题,我将使用这两种方法,不出所料,自动特征工程花费手动特征工程十分之一的时间并且取得更好的性能。这里我展示手工版本,但是Featuretools是一个可以学习的很好的工具。


在这个问题中,我们的主要目标是汇总所有个人层面数据为家庭层面数据。这意味着将一个房子的个人组合在一起,然后计算统计数据,例如最大年龄,平均教育水平或家庭拥有的手机总数。


幸运的是,一旦我们将单个数据分离(进入ind DataFrame),执行这些聚合实际上就是Pandas中的一行(idhogar是用于分组的家庭标识符):


# Aggregate individual data for each household
ind_agg = ind.groupby('idhogar').agg(['min', 'max', 'mean', 'sum'])


重命名列后,我们有许多看起来像这样的特征:

机器学习完整解决流程演练 part1

这种方法的好处是能快速产生大量特征,缺点是产生的很多特征没用或者高度相关,所以我们要用到特征选择。

聚合的另一种方法是使用领域知识一次一个地计算特征,基于哪些特征可能对预测贫困有用。例如,在家庭数据中,我们创建了一个名为warning的特征,它会添加许多家庭“警告标志”(house是家庭变量的DataFrame):

# No toilet, no electricity, no floor, no water service, no ceiling
house['warning'] = 1 * (house['sanitario1'] + 
                         (house['elec'] == 0) + 
                         house['pisonotiene'] + 
                         house['abastaguano'] + 
                         (house['cielorazo'] == 0))


机器学习完整解决流程演练 part1


我们还可以通过将一个值除以另一个值来计算“人均”特征(tamviv是家庭成员的数量)


# Per capita features for household data
house['phones-per-capita'] = house['qmobilephone'] / house['tamviv']
house['tablets-per-capita'] = house['v18q1'] / house['tamviv']
house['rooms-per-capita'] = house['rooms'] / house['tamviv']
house['rent-per-capita'] = house['v2a1'] / house['tamviv']


在手动与自动化功能工程方面,我认为最佳答案是两者的结合。作为人类,我们通过创造力构建的功能受到限制 - 我们可以想到的功能有限 - 还有时间 - 我们只有有限时间来编写代码。我们可以手动制作一些上述功能,但自动化功能工程优秀的是在进行可以自动构建在其他特征之上的特征。


最好的方法是花一些时间使用领域知识手动创建一些功能,然后将流程切换到自动化功能工程,以生成数百或数千个。


Featuretools是用于自动化功能工程的最先进的开源Python库。这篇文章将在大约10分钟内让你上手。)


Feature Selection

一旦我们耗尽了时间和耐心来构造特征,我们使用特征选择来移除一些特征,试着只保留下来那些对问题有用的特征。有用”没有设定定义,但我们使用一些启发式(经验法则)来选择特征。


一种方法是计算特征之间的相关性(correlations)。Two variables that are highly correlated with one another are called collinear. 这是机器学习中的一个问题,因为这些变量会降低模型训练速度,产生更加难以解释的模型,可能在训练数据中造成过拟合从而降低模型性能。


关于删除相关特征的棘手部分是确定两个变量过于相关的阈值。我通常保持保守,使用0.95或者更大的相关系数(correlation coefficient)。一旦我们确定阈值,我们就利用以下代码移除每对相关系数超过0.95的变量中的一个变量。


import numpy as np

threshold = 0.95

# Create correlation matrix
corr_matrix = data.corr()

# Select upper triangle of correlation matrix
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))

# Find index of feature columns with correlation greater than 0.95
to_drop = [column for column in upper.columns if any(abs(upper[column]) > threshold)]

data = data.drop(columns = to_drop)


我们只移除彼此相关的特征,我们想要只与标签相关的特征(而与标签相关系数大于0.95的特征过于好了,也要删掉)。


有许多特征选择方法(我们将在本文末尾的实验部分中看到另一个方法)。这些可以是单变量的 - 一次测量一个变量与标签的相关性 - 或多变量 - 评估多个特征的影响。我还倾向于使用基于模型的特征重要性来进行特征选择,例如来自随机森林的特征选择。


在选择特征之后,我们可以对最终的变量集进行一些探索,包括制作a correlation heatmap and a pairsplot机器学习完整解决流程演练 part1


我们从探索中得到的一点是教育与贫困之间的关系:随着家庭教育程度的增加(平均值和最大值),贫困的严重程度趋于下降(1是最严重的):

机器学习完整解决流程演练 part1


另一方面,随着过度拥挤程度 - 每个房间的人数 - 增加,贫困的严重程度增加:

机器学习完整解决流程演练 part1


这是本次比赛的两个通过行动得到的观点,甚至在我们使用机器学习算法之前可以猜测到:受教育程度较高的家庭往往贫困程度较低,每个房间人口较多的家庭往往贫困程度较高。除了技术方面,我喜欢思考数据科学项目的影响和更远大的图景。它很可能被细节淹没,让你忘记从事于这整个项目的原因——该项目的最终目标是弄清楚如何预测贫困,以最有效地帮助那些有需要的人。


Model Comparation

下图是我最喜欢的一个机器学习成果之一。它显示了几种机器学习模型在许多数据集上的性能表现,百分比表示一种模型打败其他模型的次数。(This is from a highly readable paper by Randal Olson.)

机器学习完整解决流程演练 part1

从上图我们会发现:即使最简单的逻辑回归也能击败随机森林和梯度提升机。尽管GBT通常性能最好,但这并不表示它是最优选择。因此,当我们遇到新问题,最好的办法是尝试几种不同的办法而不是依赖于某一种算法。我过去总使用相同的模型(随机森林),但请记住:没有一个模型总是最好的。


幸运的是,使用Scikit-Learn,可以使用相同的语法轻松评估许多机器学习模型。虽然我们不会对每个参数进行超参数调整,但我们可以将模型与默认的超参数进行比较,以便选择最有希望的优化模型。


在notebook中,我们尝试了六种模型,涵盖从简单 - 高斯朴素贝叶斯到复杂 - 随机森林和梯度增强机器的复杂范围。虽然Scikit-Learn确实有GBM实现,但速度相当慢,更好的选择是使用XGBoost或LightGBM等专用库。对于这个notebook,我使用Light GBM并根据过去运行良好的内容选择超参数。


为了比较模型,我们使用交叉验证计算了5到10折的训练数据的性能。下图表示几种模型的比较结果。条形的高度是模型的the average Macro F1 score,黑条是表示标准差:

机器学习完整解决流程演练 part1

虽然这不完全是一个水平的比较 - 我没有使用梯度增强机的默认超参数 - 一般结果表明:GBM是一个很大的最佳模型。这反映了大多数其他数据科学家的发现。


请注意,我们在特征选择之前和之后交叉验证数据,以查看其对性能的影响。机器学习在很大程度上仍然是一个经验领域,了解方法是否有效的唯一方法是尝试一下然后测量性能。测试管道中步骤的不同选择(例如特征选择的相关阈值)以确定它们是否有用非常重要。请记住,我们也希望避免过多地考虑交叉验证结果,因为即使有很多折叠,我们仍然可能过度拟合训练数据。最后,即使GBM最适合这个数据集,但情况并非总是如此!


基于这些结果,我们可以选择梯度增强机作为我们的模型(记住这是一个我们可以回去修改的决定!)。一旦我们决定了模型,下一步就是充分利用它,这个过程称为模型超参数优化。


认识到不是每个人都有时间在一次会议上有30分钟的文章(甚至是数据科学),我将其分为两部分。第二部分包括模型优化,解释和实验部分。


Conclusions

到目前为止,我们可以看到机器学习的所有不同部分如何组合在一起形成一个解决方案:我们首先必须了解问题,然后我们挖掘数据,根据需要进行清理,然后我们为机器学习模型构造特征,最后我们评估了几种不同的模型。


我们已经介绍了许多技术并且拥有一个不错的模型(虽然F1得分相对较低,但却排在提交给比赛的前50名模型中)。尽管如此,我们仍然只剩下几个步骤:通过优化,我们可以改进我们的模型,然后我们必须解释我们的结果,因为在我们传达我们的工作之前没有完成分析。


下一步,请参阅第二部分,查看笔记本(也在GitHub上),或者开始自己解决问题。



评论

Live Sex Cams Free