项目2: 为CharityML寻找捐献者

来源:互联网 发布:知乎搞笑的事情 编辑:程序博客网 时间:2024/05/01 03:58

机器学习纳米学位

监督学习

项目2: 为CharityML寻找捐献者

欢迎来到机器学习工程师纳米学位的第二个项目!在此文件中,有些示例代码已经提供给你,但你还需要实现更多的功能让项目成功运行。除非有明确要求,你无须修改任何已给出的代码。以'练习'开始的标题表示接下来的代码部分中有你必须要实现的功能。每一部分都会有详细的指导,需要实现的部分也会在注释中以'TODO'标出。请仔细阅读所有的提示!

除了实现代码外,你还必须回答一些与项目和你的实现有关的问题。每一个需要你回答的问题都会以'问题 X'为标题。请仔细阅读每个问题,并且在问题后的'回答'文字框中写出完整的答案。我们将根据你对问题的回答和撰写代码所实现的功能来对你提交的项目进行评分。

提示:Code 和 Markdown 区域可通过Shift + Enter快捷键运行。此外,Markdown可以通过双击进入编辑模式。

开始

在这个项目中,你将使用1994年美国人口普查收集的数据,选用几个监督学习算法以准确地建模被调查者的收入。然后,你将根据初步结果从中选择出最佳的候选算法,并进一步优化该算法以最好地建模这些数据。你的目标是建立一个能够准确地预测被调查者年收入是否超过50000美元的模型。这种类型的任务会出现在那些依赖于捐款而存在的非营利性组织。了解人群的收入情况可以帮助一个非营利性的机构更好地了解他们要多大的捐赠,或是否他们应该接触这些人。虽然我们很难直接从公开的资源中推断出一个人的一般收入阶层,但是我们可以(也正是我们将要做的)从其他的一些公开的可获得的资源中获得一些特征从而推断出该值。

这个项目的数据集来自UCI机器学习知识库。这个数据集是由Ron Kohavi和Barry Becker在发表文章"Scaling Up the Accuracy of Naive-Bayes Classifiers: A Decision-Tree Hybrid"之后捐赠的,你可以在Ron Kohavi提供的在线版本中找到这个文章。我们在这里探索的数据集相比于原有的数据集有一些小小的改变,比如说移除了特征'fnlwgt' 以及一些遗失的或者是格式不正确的记录。


探索数据

运行下面的代码单元以载入需要的Python库并导入人口普查数据。注意数据集的最后一列'income'将是我们需要预测的列(表示被调查者的年收入会大于或者是最多50,000美元),人口普查数据中的每一列都将是关于被调查者的特征。

In [3]:
# 为这个项目导入需要的库import numpy as npimport pandas as pdfrom time import timefrom IPython.display import display # 允许为DataFrame使用display()# 导入附加的可视化代码visuals.pyimport visuals as vs# 为notebook提供更加漂亮的可视化%matplotlib inline# 导入人口普查数据data = pd.read_csv("census.csv")# 成功 - 显示第一条记录display(data.head(n=1))
 ageworkclasseducation_leveleducation-nummarital-statusoccupationrelationshipracesexcapital-gaincapital-losshours-per-weeknative-countryincome039State-govBachelors13.0Never-marriedAdm-clericalNot-in-familyWhiteMale2174.00.040.0United-States<=50K

练习:数据探索

首先我们对数据集进行一个粗略的探索,我们将看看每一个类别里会有多少被调查者?并且告诉我们这些里面多大比例是年收入大于50,000美元的。在下面的代码单元中,你将需要计算以下量:

  • 总的记录数量,'n_records'
  • 年收入大于50,000美元的人数,'n_greater_50k'.
  • 年收入最多为50,000美元的人数 'n_at_most_50k'.
  • 年收入大于50,000美元的人所占的比例, 'greater_percent'.

提示: 您可能需要查看上面的生成的表,以了解'income'条目的格式是什么样的。

In [4]:
# TODO:总的记录数n_records = data.shape[0]# TODO:被调查者的收入大于$50,000的人数n_greater_50k = data[data.income.str.contains('>50K')].shape[0]# TODO:被调查者的收入最多为$50,000的人数n_at_most_50k = data[data.income.str.contains('<=50K')].shape[0]# TODO:被调查者收入大于$50,000所占的比例greater_percent = np.divide(n_greater_50k, float(n_records)) * 100# 打印结果print "Total number of records: {}".format(n_records)print "Individuals making more than $50,000: {}".format(n_greater_50k)print "Individuals making at most $50,000: {}".format(n_at_most_50k)print "Percentage of individuals making more than $50,000: {:.2f}%".format(greater_percent)
Total number of records: 45222Individuals making more than $50,000: 11208Individuals making at most $50,000: 34014Percentage of individuals making more than $50,000: 24.78%

准备数据

在数据能够被作为输入提供给机器学习算法之前,它经常需要被清洗,格式化,和重新组织 - 这通常被叫做预处理。幸运的是,对于这个数据集,没有我们必须处理的无效或丢失的条目,然而,由于某一些特征存在的特性我们必须进行一定的调整。这个预处理都可以极大地帮助我们提升几乎所有的学习算法的结果和预测能力。

转换倾斜的连续特征

一个数据集有时可能包含至少一个靠近某个数字的特征,但有时也会有一些相对来说存在极大值或者极小值的不平凡分布的的特征。算法对这种分布的数据会十分敏感,并且如果这种数据没有能够很好地规一化处理会使得算法表现不佳。在人口普查数据集的两个特征符合这个描述:'capital-gain''capital-loss'

运行下面的代码单元以创建一个关于这两个特征的条形图。请注意当前的值的范围和它们是如何分布的。

In [5]:
# 将数据切分成特征和对应的标签income_raw = data['income']features_raw = data.drop('income', axis = 1)# 可视化原来数据的倾斜的连续特征vs.distribution(data)

对于高度倾斜分布的特征如'capital-gain''capital-loss',常见的做法是对数据施加一个对数转换,将数据转换成对数,这样非常大和非常小的值不会对学习算法产生负面的影响。并且使用对数变换显著降低了由于异常值所造成的数据范围异常。但是在应用这个变换时必须小心:因为0的对数是没有定义的,所以我们必须先将数据处理成一个比0稍微大一点的数以成功完成对数转换。

运行下面的代码单元来执行数据的转换和可视化结果。再次,注意值的范围和它们是如何分布的。

In [6]:
# 对于倾斜的数据使用Log转换skewed = ['capital-gain', 'capital-loss']features_raw[skewed] = data[skewed].apply(lambda x: np.log(x + 1))# 可视化经过log之后的数据分布vs.distribution(features_raw, transformed = True)

规一化数字特征

除了对于高度倾斜的特征施加转换,对数值特征施加一些形式的缩放通常会是一个好的习惯。在数据上面施加一个缩放并不会改变数据分布的形式(比如上面说的'capital-gain' or 'capital-loss');但是,规一化保证了每一个特征在使用监督学习器的时候能够被平等的对待。注意一旦使用了缩放,观察数据的原始形式不再具有它本来的意义了,就像下面的例子展示的。

运行下面的代码单元来规一化每一个数字特征。我们将使用sklearn.preprocessing.MinMaxScaler来完成这个任务。

In [7]:
# 导入sklearn.preprocessing.StandardScalerfrom sklearn.preprocessing import MinMaxScaler# 初始化一个 scaler,并将它施加到特征上scaler = MinMaxScaler()numerical = ['age', 'education-num', 'capital-gain', 'capital-loss', 'hours-per-week']features_raw[numerical] = scaler.fit_transform(data[numerical])# 显示一个经过缩放的样例记录display(features_raw.head(n = 1))
 ageworkclasseducation_leveleducation-nummarital-statusoccupationrelationshipracesexcapital-gaincapital-losshours-per-weeknative-country00.30137State-govBachelors0.8Never-marriedAdm-clericalNot-in-familyWhiteMale0.021740.00.397959United-States

练习:数据预处理

从上面的数据探索中的表中,我们可以看到有几个属性的每一条记录都是非数字的。通常情况下,学习算法期望输入是数字的,这要求非数字的特征(称为类别变量)被转换。转换类别变量的一种流行的方法是使用独热编码方案。独热编码为每一个非数字特征的每一个可能的类别创建一个“虚拟”变量。例如,假设someFeature有三个可能的取值AB或者C,。我们将把这个特征编码成someFeature_AsomeFeature_BsomeFeature_C.

 一些特征 特征_A特征_B特征_C0B 0101C----> 独热编码 ---->0012A 100

此外,对于非数字的特征,我们需要将非数字的标签'income'转换成数值以保证学习算法能够正常工作。因为这个标签只有两种可能的类别("<=50K"和">50K"),我们不必要使用独热编码,可以直接将他们编码分别成两个类01,在下面的代码单元中你将实现以下功能:

  • 使用pandas.get_dummies()'features_raw'数据来施加一个独热编码。
  • 将目标标签'income_raw'转换成数字项。
    • 将"<=50K"转换成0;将">50K"转换成1
In [8]:
# TODO:使用pandas.get_dummies()对'features_raw'数据进行独热编码features = pd.get_dummies(features_raw)# TODO:将'income_raw'编码成数字值income = income_raw.replace(['>50K', '<=50K'], [1, 0])# 打印经过独热编码之后的特征数量encoded = list(features.columns)print "{} total features after one-hot encoding.".format(len(encoded))# 移除下面一行的注释以观察编码的特征名字# print encoded
103 total features after one-hot encoding.

混洗和切分数据

现在所有的 类别变量 已被转换成数值特征,而且所有的数值特征已被规一化。和我们一般情况下做的一样,我们现在将数据(包括特征和它们的标签)切分成训练和测试集。其中80%的数据将用于训练和20%的数据用于测试。

运行下面的代码单元来完成切分。

In [9]:
# 导入 train_test_splitfrom sklearn.model_selection import train_test_split# 将'features'和'income'数据切分成训练集和测试集X_train, X_test, y_train, y_test = train_test_split(features, income, test_size = 0.2, random_state = 0)# 显示切分的结果print "Training set has {} samples.".format(X_train.shape[0])print "Testing set has {} samples.".format(X_test.shape[0])
Training set has 36177 samples.Testing set has 9045 samples.

评价模型性能

在这一部分中,我们将尝试四种不同的算法,并确定哪一个能够最好地建模数据。这里面的三个将是你选择的监督学习器,而第四种算法被称为一个朴素的预测器

评价方法和朴素的预测器

CharityML通过他们的研究人员知道被调查者的年收入大于$50,000最有可能向他们捐款。因为这个原因*CharityML*对于准确预测谁能够获得$50,000以上收入尤其有兴趣。这样看起来使用准确率作为评价模型的标准是合适的。另外,把没有收入大于$50,000的人识别成年收入大于$50,000对于CharityML来说是有害的,因为他想要找到的是有意愿捐款的用户。这样,我们期望的模型具有准确预测那些能够年收入大于$50,000的能力比模型去查全这些被调查者更重要。我们能够使用F-beta score作为评价指标,这样能够同时考虑查准率和查全率:

Fβ=(1+β2)precisionrecall(β2precision)+recall

尤其是,当β=0.5的时候更多的强调查准率,这叫做F0.5 score (或者为了简单叫做F-score)。

通过查看不同类别的数据分布(那些最多赚$50,000和那些能够赚更多的),我们能发现:很明显的是很多的被调查者年收入没有超过$50,000。这点会显著地影响准确率,因为我们可以简单地预测说“这个人的收入没有超过$50,000”,这样我们甚至不用看数据就能做到我们的预测在一般情况下是正确的!做这样一个预测被称作是朴素的,因为我们没有任何信息去证实这种说法。通常考虑对你的数据使用一个朴素的预测器是十分重要的,这样能够帮助我们建立一个模型的表现是否好的基准。那有人说,使用这样一个预测是没有意义的:如果我们预测所有人的收入都低于$50,000,那么CharityML就不会有人捐款了。

问题 1 - 朴素预测器的性能

如果我们选择一个无论什么情况都预测被调查者年收入大于$50,000的模型,那么这个模型在这个数据集上的准确率和F-score是多少?
注意: 你必须使用下面的代码单元将你的计算结果赋值给'accuracy' 和 'fscore',这些值会在后面被使用,请注意这里不能使用scikit-learn,你需要根据公式自己实现相关计算。

In [10]:
# TODO: 计算准确率accuracy = np.divide(n_greater_50k, float(n_records))# TODO: 使用上面的公式,并设置beta=0.5计算F-scorerecall = np.divide(n_greater_50k, n_greater_50k)precision = np.divide(n_greater_50k, float(n_records))fscore = (1 + np.power(0.5, 2)) * np.multiply(precision, recall) / (np.power(0.5, 2) * precision + recall)# 打印结果print "Naive Predictor: [Accuracy score: {:.4f}, F-score: {:.4f}]".format(accuracy, fscore)
Naive Predictor: [Accuracy score: 0.2478, F-score: 0.2917]

监督学习模型

下面的监督学习模型是现在在 scikit-learn 中你能够选择的模型

  • 高斯朴素贝叶斯 (GaussianNB)
  • 决策树
  • 集成方法 (Bagging, AdaBoost, Random Forest, Gradient Boosting)
  • K近邻 (KNeighbors)
  • 随机梯度下降分类器 (SGDC)
  • 支撑向量机 (SVM)
  • Logistic回归

问题 2 - 模型应用

列出从上面的监督学习模型中选择的三个适合我们这个问题的模型,你将在人口普查数据上测试这每个算法。对于你选择的每一个算法:

  • 描述一个该模型在真实世界的一个应用场景。(你需要为此做点研究,并给出你的引用出处)
  • 这个模型的优势是什么?他什么情况下表现最好?
  • 这个模型的缺点是什么?什么条件下它表现很差?
  • 根据我们当前数据集的特点,为什么这个模型适合这个问题。

回答: 

- 选择的算法:决策树、集成方法、支撑向量机

  • 决策树

    • 模型在真实世界中也应用场景

      • 在金融方面使用决策树建模分析,用于评估用户的信用、贷款违约率等;在电子商务中,可以根据用户的以往的交易种类、时间、价格建立商品推荐体统等。

      • 引用连接: 信贷方面的应用 电商推荐系统

    • 这个模型的优势是什么?

      • 决策树易于实现和理解;
      • 对于决策树,数据的准备工作一般比较简单;
      • 能够同时处理多种数据类型
      • 给定一个决策树模型,可以根据产生的决策树推出相应的逻辑表达式;
      • 通过静态测试来对模型的表现进行评价;
      • 在相对较短的时间内可以对大量的数据做出非常好的结果;
      • 决策树可以很好地扩展到大型数据中,同时决策树的大小独立于数据库的大小;
      • 计算复杂度相对较低,结果的输出易于理解,对部分的数据缺失不敏感。
    • 他什么情况下表现最好?

      • 实例是由“属性-值”对表示的;
      • 目标函数具有离散的输出值;
      • 训练数据集包含部分错误(决策树对错误有适应性);
      • 训练数据缺少少量属性的实例。
    • 这个模型的缺点是什么?

      • 易于出现过拟合问题;
      • 忽略了数据集中属性之间的相关性;
      • 对于类比不一致的样本,决策树的信息增益倾向于那些数据值较多的特征
    • 什么条件下它表现很差?

      • 决策树匹配的数据过多时;
      • 分类的类别过于复杂;
      • 数据的属性之间具有非常强的关联。
    • 根据我们当前数据集的特点,为什么这个模型适合这个问题。

      • 不需要准备太多的训练数据,不需要对数据过多的处理如删除空白值等;
      • 易于编码;
      • 该问题是非线性问题,决策树能够很好地解决非线性问题;
      • 算法的执行效率高,对机器的要求较小。

  • 支撑向量机

    • 模型在真实世界中也应用场景
      • 支撑向量机用于文本和超文本的分类;
      • 用于图像分类;
      • 用于手写体识别;
      • Kecman, Vojislav; Learning and Soft Computing — Support Vector Machines, Neural Networks, Fuzzy Logic Systems, The MIT Press, Cambridge, MA, 2001.
      • Barghout, Lauren. "Spatial-Taxon Information Granules as Used in Iterative Fuzzy-Decision-Making for Image Segmentation." Granular Computing and Decision-Making. Springer International Publishing, 2015. 285-318. 
    • 这个模型的优势是什么?

      • 分类效果好;
      • 可以有效地处理高维空间的数据;
      • 可以有效地处理变量个数大于样本个数的数据;
      • 只是使用了一部分子集来进行训练模型,所以SVM模型不需要太大的内存;
      • 可以提高泛化能力; 
      • 无局部极小值问题;
    • 他什么情况下表现最好?

      • 数据的维度较高;
      • 需要模型具有非常强的泛化能力;
      • 样本数据量较小时;
      • 解决非线性问题; 
    • 这个模型的缺点是什么?

      • 无法处理大规模的数据集,因为该算法需要较长的训练时间;
      • 无法有效地处理包含噪声太多的数据集;
      • SVM模型没有直接给出概率的估计值,而是利用交叉验证的方式估计,这种方式耗时较长;
      • 对缺失数据非常敏感;
      • 对于非线性问题,有时很难找到一个合适的核函数。
    • 什么条件下它表现很差?

      • 数据集的数据量过大;
      • 数据集中的含有噪声;
      • 数据集中的缺失较多的数据;
      • 对算法的训练效率要求较高; 
    • 根据我们当前数据集的特点,为什么这个模型适合这个问题。
      • 该项目所提供的样本数据相对较少;
      • 该问题是属于非线性问题;
      • 数据集经过“独热编码”后,维度较高;
      • SVM可以指定不同的核函数,用于提高分类器的准确性。 

  • 集成方法(AdaBoost)
    • 模型在真实世界中也应用场景
      • 用于二分类或多分类问题;
      • 用于特征选择;
      • 多标签问题;
      • 回归问题; 引用
    • 这个模型的优势是什么?
      • AdaBoost是一种精度非常高的分类器;
      • 可以与各种方法构建子分类器,AdaBoost算法提供一种计算框架;
      • 弱分类器的构造方法比较简单;
      • 算法易于理解,不用做特征筛选;
      • 不易发生过拟合。
      • 易于编码;
    • 他什么情况下表现最好?
      • 用于解决二分类问题;
      • 解决大类单标签问题;
      • 处理多类单标签问题;
      • 处理回归相关的问题。
    • 这个模型的缺点是什么?
      • AdaBoost算法的迭代次数不好设定,需要使用交叉验证的方式来进行确定;
      • 数据集的不平衡分布导致分类器的分类精度下降;
      • 训练比较耗费时间;
      • 对异常值比较敏感;
    • 什么条件下它表现很差?
      • 数据集分布非常不均匀;
      • 数据集中含有较多的异常值;
      • 对算法的训练的效率要求较高;
    • 根据我们当前数据集的特点,为什么这个模型适合这个问题。
      • 该数据集可以归属为多标签分类问题;
      • 数据集中异常值较少;
      • 对算法模型的准确率要就较高;

练习 - 创建一个训练和预测的流水线

为了正确评估你选择的每一个模型的性能,创建一个能够帮助你快速有效地使用不同大小的训练集并在测试集上做预测的训练和测试的流水线是十分重要的。 你在这里实现的功能将会在接下来的部分中被用到。在下面的代码单元中,你将实现以下功能:

  • sklearn.metrics中导入fbeta_scoreaccuracy_score
  • 用样例训练集拟合学习器,并记录训练时间。
  • 用学习器来对训练集进行预测并记录预测时间。
  • 在最前面的300个训练数据上做预测。
  • 计算训练数据和测试数据的准确率。
  • 计算训练数据和测试数据的F-score。
In [11]:
# TODO:从sklearn中导入两个评价指标 - fbeta_score和accuracy_scorefrom sklearn.metrics import fbeta_score, accuracy_scoredef train_predict(learner, sample_size, X_train, y_train, X_test, y_test):     '''    inputs:       - learner: the learning algorithm to be trained and predicted on       - sample_size: the size of samples (number) to be drawn from training set       - X_train: features training set       - y_train: income training set       - X_test: features testing set       - y_test: income testing set    '''        results = {}        # TODO:使用sample_size大小的训练数据来拟合学习器    # TODO: Fit the learner to the training data using slicing with 'sample_size'    start = time() # 获得程序开始时间    learner = learner.fit(X_train[: sample_size], y_train[: sample_size])    end = time() # 获得程序结束时间        # TODO:计算训练时间    results['train_time'] = end - start        # TODO: 得到在测试集上的预测值    #       然后得到对前300个训练数据的预测结果    start = time() # 获得程序开始时间    predictions_test = learner.predict(X_test)    predictions_train = learner.predict(X_train[: 300])    end = time() # 获得程序结束时间        # TODO:计算预测用时    results['pred_time'] = end - start                # TODO:计算在最前面的300个训练数据的准确率    results['acc_train'] = accuracy_score(y_train[: 300], predictions_train)            # TODO:计算在测试集上的准确率    results['acc_test'] = accuracy_score(y_test, predictions_test)        # TODO:计算在最前面300个训练数据上的F-score    results['f_train'] = fbeta_score(y_train[: 300], predictions_train, beta=0.5)            # TODO:计算测试集上的F-score    results['f_test'] = fbeta_score(y_test, predictions_test, beta=0.5)           # 成功    print "{} trained on {} samples.".format(learner.__class__.__name__, sample_size)            # 返回结果    return results

练习:初始模型的评估

在下面的代码单元中,您将需要实现以下功能:

  • 导入你在前面讨论的三个监督学习模型。 
  • 初始化三个模型并存储在'clf_A''clf_B''clf_C'中。 
    • 如果可能对每一个模型都设置一个random_state。 
    • 注意:这里先使用每一个模型的默认参数,在接下来的部分中你将需要对某一个模型的参数进行调整。 
  • 计算记录的数目等于1%,10%,和100%的训练数据,并将这些值存储在'samples'中 

注意:取决于你选择的算法,下面实现的代码可能需要一些时间来运行!

In [12]:
# TODO:从sklearn中导入三个监督学习模型from sklearn import tree, svm, ensemble# TODO:初始化三个模型clf_A = tree.DecisionTreeClassifier()clf_B = svm.SVC()clf_C = ensemble.AdaBoostClassifier()# TODO:计算1%, 10%, 100%的训练数据分别对应多少点samples_1 = int(X_train.shape[0] * 0.01)samples_10 = int(X_train.shape[0] * 0.1)samples_100 = int(X_train.shape[0] * 1)print [samples_1, samples_10, samples_100]# 收集学习器的结果results = {}for clf in [clf_A, clf_B, clf_C]:    clf_name = clf.__class__.__name__    results[clf_name] = {}    for i, samples in enumerate([samples_1, samples_10, samples_100]):        results[clf_name][i] = \        train_predict(clf, samples, X_train, y_train, X_test, y_test)# 对选择的三个模型得到的评价结果进行可视化vs.evaluate(results, accuracy, fscore)
[361, 3617, 36177]DecisionTreeClassifier trained on 361 samples.DecisionTreeClassifier trained on 3617 samples.DecisionTreeClassifier trained on 36177 samples.
/Users/shahao/anaconda/lib/python2.7/site-packages/sklearn/metrics/classification.py:1113: UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 due to no predicted samples.  'precision', 'predicted', average, warn_for)
SVC trained on 361 samples.SVC trained on 3617 samples.SVC trained on 36177 samples.AdaBoostClassifier trained on 361 samples.AdaBoostClassifier trained on 3617 samples.AdaBoostClassifier trained on 36177 samples.

提高效果

在这最后一节中,您将从三个有监督的学习模型中选择最好的模型来使用学生数据。你将在整个训练集(X_trainy_train)上通过使用网格搜索优化至少调节一个参数以获得一个比没有调节之前更好的F-score。

问题 3 - 选择最佳的模型

基于你前面做的评价,用一到两段向CharityML解释这三个模型中哪一个对于判断被调查者的年收入大于$50,000是最合适的。
提示:你的答案应该包括关于评价指标,预测/训练时间,以及该算法是否适合这里的数据的讨论。

回答:

通过上面的运算结果表明,AdaBoost算法的比较适用于判断被调查者的年收入。

  1. 在训练训集上,虽然决策树的表现比较好,是因为训练时用到了测试所使用的数据,在测试集上决策树的表现明显不如AdaBoost和SVM,SVM和AdaBoost在使用accuracy_score和fbeta_score时的表现,AdaBoost相对来说效果要好一些。
  2. 训练和预测时间,决策树和AdaBoost相差不大,但是svm使用的时间过长。
  3. 数据集属于多标签问题,比较易于使用AdaBoost来进行处理。 

因此使用AdaBoost可以取得跟好的预测结果。

问题 4 - 用通俗的话解释模型

用一到两段话,向CharityML用外行也听得懂的话来解释最终模型是如何工作的。你需要解释所选模型的主要特点。例如,这个模型是怎样被训练的,它又是如何做出预测的。避免使用高级的数学或技术术语,不要使用公式或特定的算法名词。

回答: AdaBoost(Adaptive Boost)是一种自适应的学习算法,该算法在前一个基本分类器分错的样本会得到加权,加权后的全体样本再次被用来训练下一个基本分类器。同时,每一轮中都会加入一个新的弱分类器,直到该算法的效果达到某个预定的足够小的错误或达到预先指定的最大的迭代次数。

算法步骤:

1. 初始化训练数据的权值分布。如果有N个样本,每一个样本开始时被赋相同的权值:1/N。2. 训练弱分类器。训练过程中,假如某个样本点已经被准确的分类,那么构造下一个训练集时,该数据的权值会被降低;相反,某个样本点没有被准确的分类,那么该数据的权值就会增加。然后将权值更新后的样本数据用于训练下一个分类器,整个的训练过程将会如此的迭代下去。3. 将各个训练获得的弱分类器组合成强分类器。各个弱分类器的训练过程结束后,加大分类误差率小的弱分类器的权重,是该分类器最终的分类函数中起到较大的作用,降低误差率较大的弱分类器的权重,使其在最终的分类器占得权重较小。

练习:模型调优

调节选择的模型的参数。使用网格搜索(GridSearchCV)来至少调整模型的重要参数(至少调整一个),这个参数至少需给出并尝试3个不同的值。你要使用整个训练集来完成这个过程。在接下来的代码单元中,你需要实现以下功能:

  • 导入sklearn.model_selection.GridSearchCVsklearn.metrics.make_scorer.
  • 初始化你选择的分类器,并将其存储在clf中。
    • 如果能够设置的话,设置random_state
  • 创建一个对于这个模型你希望调整参数的字典。
    • 例如: parameters = {'parameter' : [list of values]}。
    • 注意: 如果你的学习器(learner)有 max_features 参数,请不要调节它!
  • 使用make_scorer来创建一个fbeta_score评分对象(设置β=0.5)。
  • 在分类器clf上用'scorer'作为评价函数运行网格搜索,并将结果存储在grid_obj中。
  • 用训练集(X_train, y_train)训练grid search object,并将结果存储在grid_fit中。

注意: 取决于你选择的参数列表,下面实现的代码可能需要花一些时间运行!

In [21]:
# TODO:导入'GridSearchCV', 'make_scorer'和其他一些需要的库from sklearn.model_selection import GridSearchCV, KFoldfrom sklearn.metrics import make_scorerfrom sklearn.ensemble import AdaBoostClassifier# TODO:初始化分类器clf = AdaBoostClassifier(random_state=0)# TODO:创建你希望调节的参数列表parameters = {'n_estimators': [50, 100, 200]}# TODO:创建一个fbeta_score打分对象scorer = make_scorer(fbeta_score, beta=0.5)# TODO:在分类器上使用网格搜索,使用'scorer'作为评价函数kfold = KFold(n_splits=10)grid_obj = GridSearchCV(clf, parameters, scorer, cv=kfold)# TODO:用训练数据拟合网格搜索对象并找到最佳参数grid_fit = grid_obj.fit(X_train, y_train)# 得到estimatorbest_clf = grid_obj.best_estimator_# 使用没有调优的模型做预测predictions = (clf.fit(X_train, y_train)).predict(X_test)best_predictions = best_clf.predict(X_test)# 汇报调参前和调参后的分数print "Unoptimized model\n------"print "Accuracy score on testing data: {:.4f}".format(accuracy_score(y_test, predictions))print "F-score on testing data: {:.4f}".format(fbeta_score(y_test, predictions, beta = 0.5))print "\nOptimized Model\n------"print "Final accuracy score on the testing data: {:.4f}".format(accuracy_score(y_test, best_predictions))print "Final F-score on the testing data: {:.4f}".format(fbeta_score(y_test, best_predictions, beta = 0.5))
Unoptimized model------Accuracy score on testing data: 0.8576F-score on testing data: 0.7246Optimized Model------Final accuracy score on the testing data: 0.8651Final F-score on the testing data: 0.7396

问题 5 - 最终模型评估

你的最优模型在测试数据上的准确率和F-score是多少?这些分数比没有优化的模型好还是差?你优化的结果相比于你在问题 1中得到的朴素预测器怎么样?
注意:请在下面的表格中填写你的结果,然后在答案框中提供讨论。

结果:

评价指标基准预测器未优化的模型优化的模型准确率0.24780.85760.8651F-score0.29170.72460.7396

回答: 通过对AdaBoost中的弱分类器的数量进行网格搜索和交叉验证,得出的优化后的模型要比没有基准去测器的准确率和f-score高得多,比未优化的模型也稍微高了一些。没有高出很多的原因可能是因为AbaBoost算法的自适应性已经非常强大了,增加弱学习器的数量并不能大幅度的提升算法的accuracy和f-score。


特征的重要性

在数据上(比如我们这里使用的人口普查的数据)使用监督学习算法的一个重要的任务是决定哪些特征能够提供最强的预测能力。通过专注于一些少量的有效特征和标签之间的关系,我们能够更加简单地理解这些现象,这在很多情况下都是十分有用的。在这个项目的情境下这表示我们希望选择一小部分特征,这些特征能够在预测被调查者是否年收入大于$50,000这个问题上有很强的预测能力。

选择一个有feature_importance_属性(这是一个根据这个选择的分类器来对特征的重要性进行排序的函数)的scikit学习分类器(例如,AdaBoost,随机森林)。在下一个Python代码单元中用这个分类器拟合训练集数据并使用这个属性来决定这个人口普查数据中最重要的5个特征。

问题 6 - 观察特征相关性

探索数据的时候,它显示在这个人口普查数据集中每一条记录我们有十三个可用的特征。
在这十三个记录中,你认为哪五个特征对于预测是最重要的,你会怎样对他们排序?理由是什么?

回答:

  1. education_level
    学位较高的人,更加容易获得高的收入;
  2. occupaiton
    收入与所从事的职业密切相关;
  3. hours_per_week
    工作时间的长短与收入是正相关的关系;
  4. age
    当前社会,一般来说随着年龄的增长,经验增加,收入也会越来越高;
  5. workclass
    工作层次相对来说也是决定收入高低的一个重要的原因。

练习 - 提取特征重要性

选择一个scikit-learn中有feature_importance_属性的监督学习分类器,这个属性是一个在做预测的时候根据所选择的算法来对特征重要性进行排序的功能。

在下面的代码单元中,你将要实现以下功能:

  • 如果这个模型和你前面使用的三个模型不一样的话从sklearn中导入一个监督学习模型。
  • 在整个训练集上训练一个监督学习模型。
  • 使用模型中的'.feature_importances_'提取特征的重要性。
In [23]:
# TODO:导入一个有'feature_importances_'的监督学习模型from sklearn.ensemble import RandomForestClassifier# TODO:在训练集上训练一个监督学习模型model = RandomForestClassifier(random_state=0)model.fit(X_train, y_train)# TODO: 提取特征重要性importances = model.feature_importances_importances_AdaBoost = best_clf.feature_importances_# 绘图vs.feature_plot(importances, X_train, y_train)vs.feature_plot(importances_AdaBoost, X_train, y_train)

问题 7 - 提取特征重要性

观察上面创建的展示五个用于预测被调查者年收入是否大于$50,000最相关的特征的可视化图像。 这五个特征和你在问题 6中讨论的特征比较怎么样?如果说你的答案和这里的相近,那么这个可视化怎样佐证了你的想法?如果你的选择不相近,那么为什么你觉得这些特征更加相关?

回答: 与问题6中的答案有部分是相关的,例如:年龄、教育程度、工作时长。 但是,使用随机森林与前面使用的AdaBoost所选择出的重要的信息有一些出入。

特征选择

如果我们只是用可用特征的一个子集的话模型表现会怎么样?通过使用更少的特征来训练,在评价指标的角度来看我们的期望是训练和预测的时间会更少。从上面的可视化来看,我们可以看到前五个最重要的特征贡献了数据中所有特征中超过一半的重要性。这提示我们可以尝试去减小特征空间,并简化模型需要学习的信息。下面代码单元将使用你前面发现的优化模型,并只使用五个最重要的特征在相同的训练集上训练模型。

In [25]:
# 导入克隆模型的功能from sklearn.base import clone# 减小特征空间X_train_reduced = X_train[X_train.columns.values[(np.argsort(importances_AdaBoost)[::-1])[:5]]]X_test_reduced = X_test[X_test.columns.values[(np.argsort(importances_AdaBoost)[::-1])[:5]]]# 在前面的网格搜索的基础上训练一个“最好的”模型clf = (clone(best_clf)).fit(X_train_reduced, y_train)# 做一个新的预测reduced_predictions = clf.predict(X_test_reduced)# 对于每一个版本的数据汇报最终模型的分数print "Final Model trained on full data\n------"print "Accuracy on testing data: {:.4f}".format(accuracy_score(y_test, best_predictions))print "F-score on testing data: {:.4f}".format(fbeta_score(y_test, best_predictions, beta = 0.5))print "\nFinal Model trained on reduced data\n------"print "Accuracy on testing data: {:.4f}".format(accuracy_score(y_test, reduced_predictions))print "F-score on testing data: {:.4f}".format(fbeta_score(y_test, reduced_predictions, beta = 0.5))
Final Model trained on full data------Accuracy on testing data: 0.8651F-score on testing data: 0.7396Final Model trained on reduced data------Accuracy on testing data: 0.8385F-score on testing data: 0.6920

问题 8 - 特征选择的影响

最终模型在只是用五个特征的数据上和使用所有的特征数据上的F-score和准确率相比怎么样?
如果训练时间是一个要考虑的因素,你会考虑使用部分特征的数据作为你的训练集吗?

回答: 使用上面的五个最为重要的个模型,会使得accuracy和f-score都略有下降。


假如训练时间是一个非常重要的考虑的因素时,使用重要的特征进行训练可以是一个备选方案。但是,我更希望通过对数据集进行降维、选择计算复杂度更小或者增加设备的计算能力的方式来解决这个问题;当这些手段都不能使用的时候,可能才会选择这种使用部分数据集的方案。

注意: 当你写完了所有的代码,并且回答了所有的问题。你就可以把你的 iPython Notebook 导出成 HTML 文件。你可以在菜单栏,这样导出File -> Download as -> HTML (.html)把这个 HTML 和这个 iPython notebook 一起做为你的作业提交。

原创粉丝点击