构建数据科学档案:机器学习项目

原文:Building a data science portfolio: Machine learning project
作者:Vik Paruchuri,开发者,数据科学家,Dataquest.io创始人
翻译:Alvin 校审:KK4SBB
责编:周建丁(zhoujd@csdn.net)

下文仅是一系列关于如何建立数据科学档案(Data Science Portfolio)的文章的一部分。如果你喜欢此篇文章,并且想得到该系列最新的连载文章,可以在页面的底部选择订阅。

大数据企业在评估新员工的时候会越来越重视他们的档案。原因之一就是档案是判断某人在现实世界的技能的最佳方式。但好的消息是此档案完全在你的的掌控范围内,如果你做了一定的工作,你将得到一份企业青睐的好档案。

建立优质数据档案的第一步是确定需要展示哪些技能。如下是企业想在你的数据档案里看到的一些基本技能:

  • 沟通的能力。
  • 与他人合作的能力。
  • 技术的程度。
  • 解释能力的相关数据。
  • 动力和主观能动性。

任何一个优秀的档案是由多个项目组成,每个项目至少包括上述的一到两点。此文是一系列关于如何建立数据科学档案的文章的一部分。在文章中将会讲述到如何在你的数据档案中添加第二个项目,而且将会阐述如何构建一个端对端的机器学习项目。在文章最后,你将会拥有一个通过数据展现你的水平和技术能力的项目。如果你感兴趣一定不能错过此篇文章。

端对端的项目

作为一个数据科学的科学家,有时候你会被要求得出一个数据集并且要描述他。在这种情况下,良好的交流过程和连贯的思路变得很重要。比如一些工具例如“Jupyter 记事本”(Jupyter notebook),这个工具在我们这之前的文章中使用过,对我们的帮助很大。这里想说的是,我们期待的成果是一个能总结你的发现成果的演示或者文档。

然而有些时候,你会被要求创建一个具有操作价值的项目。这个具有操作价值的项目直接影响公司的日常运作,并且使用的时间和操作的人数都会很大。这样的任务可能是用来“创建一个算法来预测我们的客户的流失率”或者“创建一个可以自动标识我们的文章的模型”。在这只能过情况下,叙述故事跟技术能力相比,就显得不是那么重要了。你需要构建并且了解一个数据集,然后创建一组可以处理数据的脚本程序。重要的是这些脚本运行要很快并且尽可能少的使用例如内存的系统资源。常见的是这些脚本程序将运行不止一次,所以需要交付的是实实在在的程序代码而不是一个流程演示。同时这些交付项目往往是需要纳入业务流程的范畴,甚至可能是面向用户的。

构建端对端项目的主要要素如下:

  • 理解上下文。
  • 研究数据并找出其中细微的差别。
  • 创建一个结构良好的项目,所以此项目才能轻松地集成到操作流程里。
  • 编写高性能的,运行速度快的,并使用最少系统资源的代码。
  • 记录你的程序安装和使用情况,好的记录会反应你的代码质量的好坏,从而方便代码的复用。

为了有效创建这种类型的项目,我们需要操作多个文件。使用文本编辑器比如Atom,或者集成开发环境比如强烈推荐PyCharm。这些工具可以方便你在文件之间切换并且编辑不同类型的文件,比如markdown文件,Python文件,csv文件等等。还有构建你的项目,所以版本控制变得非常容易操作,同时可以上传到可协作编码工具例如Github


这个项目的Github页面

在这篇文章中,我们将使用我们的编辑工具,比如Pandasscikit-learn。我们将广泛的利用Pandas的数据框,它可以很容易地阅读和操作Python上的数据表格。

寻找优秀的数据集

一个好的端对端数据集项目是很难找到。这就要求数据量需要足够的大,这样才能使得存储器和系统性能发挥作用。它还可能需要在操作上非常有用,例如,在这个数据集中包含录取标准,毕业率数据,并且毕业后的未来收益对于一个美国大学都是将是一个值得称赞的巨大数据档案。但是,当你在考虑这个数据集时,你会清楚地发现它没有足够的差别以建立一个良好的端对端项目。例如,你可以告诉别人他的潜在的未来收益,如果他们去了一个特殊的大学,但是这将没有足够的差别来快速表明其技术水平。你也可以判别是否具有较高入学标准的院校会拥有更多薪资的毕业生,这将比运营更具有故事性。

当你拥有比千兆字节还要多的数据时,这些内存和性能的限制往往会发挥作用,同时当你需要预测一些事情的时候,其中涉及的运行算法是要超过数据集本身的。

良好的操作数据使你能够创建一组转换数据的脚本程序,并且即时地回答问题。一个很好的例子就是关于股票价格的数据集。你将能够预测第二天的价格,并将最新的数据反馈给后台作为交易的结果。这将有利于你进行交易甚至可能从中盈利。这不仅仅是讲述一个故事,而是从中获利。

这里有一些能够找到这样的数据集的好地方:

在查看这些数据集的时候,想想有人会问到跟此数据集相关的问题,并且如果这些问题都是一次性的(“住房价格和标准普尔500指数有什么关联?”)或者是(“你能预测股市吗?”)。这里的关键是找到正在进行的,并需要相同的代码在多次运行的问题中输入不同的数据。

对于这篇文章的目的而言,我们将看看Fannie Mae贷款数据,Fannie Mae是美国政府赞助的企业,用来从其他贷款人手中购买按揭贷款。然后,它捆绑了这些贷款作为抵押贷款放入证券和转售他人。这使得贷款人有更多的按揭贷款,并且在市场上创造更多的流动性。这在理论上会产生更多的购房交易和更好地贷款条件。虽然从借款人的角度来看,事情保持大致相同。

Fannie Mae发布了两种类型的数据,一种是获得贷款的数据另一种是贷款表现的数据。在理想情况下,有人从贷款人借钱,然后偿还贷款,直到余额为零。然而,一些借贷人错过了多次付款的机会,这可能会导致他们丧失抵押品的赎回权。当抵押品的赎回权丧失的时候,房子就会被银行没收,因为他们无法按时还款。Fannie Mae错过了对支付贷款的跟踪和哪些贷款被取消了赎回权。此数据每季度出版一次,并且落后当前数据一年,在撰写本文时所用的最新的数据集止于2015年第一季度。

这些由Fannie Mae出版的采集数据,包含借贷人的信息,比如,信用分数,贷款和家庭的信息,收入信息。当贷款放出后,每季度公布这些信息,包括借款人的取消抵押品赎回权的状态和任何的支付信息。这些贷款可能会包含十几行的情况数据。好消息是这些收获的数据告诉你Fannie Mae 目前正在控制贷款,并且这些数据包含了一系列贷款状态的最新信息。其中一个最新的状态可能告诉我们贷款在一些季度会取消抵押品赎回权。


一栋取消抵押品赎回权的在售房屋

选择一个角度

这里有几个我们可以探索的Fannie Mae的数据:

  • 尝试在其抵债之后再预测房子的销售价格。
  • 预测借款人的付款记录。
  • 弄清楚在数据采集期间每笔贷款的得分。

重要的是要坚持一个角度,如果试图把重点放在太多的事情上将很难一下子做出一个高效的项目,而且选择那些有足够差别的角度也同样重要。这里有几个没有过多差别的角度的例子:

  • 哪些银行向Fannie Mae出售贷款的止赎是最多的。
  • 搞清楚借款人的信用分数的趋势。
  • 探索哪些类型的房屋经常性的止赎。
  • 探索贷款金额和取消抵押品赎回权的销售价格之间的关系。

以上的所有角度都是有意义的,如果我们都集中在叙述环节将会是很大的任务,但并没有为此任务做出相应的配合。

随着Fannie Mae的数据集,我们将尝试预测是否贷款将被止赎仅使用被收购的贷款信息。实际上,我们将创建任何抵押贷款,这将告诉我们如果Fannie Mae应当买它还是不能买。这将为我们提供一个很好的基础来构建,并且也是一块很大的档案。

了解数据

让我们来简单看一下一个原始的数据文件,下面是从2012年第一季度所采集的数据的前几行:

100000853384|R|OTHER|4.625|280000|360|02/2012|04/2012|31|31|1|23|801|N|C|SF|1|I|CA|945||FRM|
100003735682|R|SUNTRUST MORTGAGE INC.|3.99|466000|360|01/2012|03/2012|80|80|2|30|794|N|P|SF|1|P|MD|208||FRM|788
100006367485|C|PHH MORTGAGE CORPORATION|4|229000|360|02/2012|04/2012|67|67|2|36|802|N|R|SF|1|P|CA|959||FRM|794

下面是2012年第一季度业绩数据的前几行:

100000853384|03/01/2012|OTHER|4.625||0|360|359|03/2042|41860|0|N||||||||||||||||
100000853384|04/01/2012||4.625||1|359|358|03/2042|41860|0|N||||||||||||||||
100000853384|05/01/2012||4.625||2|358|357|03/2042|41860|0|N||||||||||||||||

在早早开始编码之前,有些时候这些都是很重要的,而且需要真正理解数据。这是在业务项目中更重要的,因为我们无法交互式的探索数据,它可以是很难察觉到的细微差别,除非我们能找到它们的上一层。在这种情况下,第一个步骤就是读取Fannie Mae网站上的资源:

在浏览这些文件之后,我们知道了一些有助于我们的关键事实:

  • 这里有从从2000年至今获取文件和每个季度业绩的文件,数据有一年的延迟,所以写这篇文章的数据引用自最新的2015年的数据。
  • 该文件是文本格式,用附号(|) 作为分隔符。
  • 该文件没有标题,但我们有表格知道每一列代表的是什么。
  • 总之,该文件包含2200万个贷款数据。
  • 因为性能文件包含以前的年度获得的贷款数据,所以前几年的贷款收购将有更多的性能数据(即在2015年获得的贷款将不会有太大的历史业绩记录)。

当我们弄清楚如何构建我们的项目和处理的数据信息时,这些小细节会为我们节约大量的时间。

构建项目

在我们下载和探索数据之前,有必要思考如何构建项目的结构。当构建端对端的项目时,我们的主要目标是:

  • 创建一个可行的解决方案。
  • 使用一个能快速运行并且使用最少资源的解决方案。
  • 让他人能轻松的在你的成果基础上进行扩展。
  • 让别人能够容易理解你的代码。
  • 尽可能的精简代码。

为了实现这些目标,我们需要调整我们的项目。一个结构良好的项目拥有如下几点原则:

  • 隔离数据文件和代码文件。
  • 隔离生成的数据和原始数据。
  • 拥有一个README.md文件能告诉用户部署和使用项目。
  • 拥有一个requirements.txt文件列出了运行项目所需的所有包。
  • 拥有一个settings.py文件包含在其他文件中使用的设置信息,
    • 例如,如果你正在多个Python脚本中阅读相同的文件,把他们全部导入设置并集中得到它们的名字是非常有用的。
  • 拥有一个.gitignore文件能防止大型或机密的文件被窃取。
  • 将任务的每个步骤可单独执行的文件,
    • 例如,我们可以让一个文件拥有创建功能,另一个文件用来进行预测读数。
  • 存储中间值。
    • 例如,一个脚本输出的文件可以被下一个脚本读取。这使得我们能够在数据处理流程中无需重新计算。

我们的文件结构是这样的:

loan-prediction
├── data
├── processed
├── .gitignore
├── README.md
├── requirements.txt
├── settings.py

创建初始文件

首先,我们需要建立一个贷款预测的文件夹。在这个文件夹里,我们需要做一个数据文件夹和进程文件夹,前一个将存储我们的原始数据,而后一个将存储任何的中间计算值。

接下来,我们将创建一个.gitignore文件,此文件用来确认某些文件被忽略的git信息,而不会上传到Github上。此类文件的一个很好的例子是由OSX的每个文件夹中创建的.DS_Store文件。在这里对于.gitignore文件是一个很好的开端。我们还需要忽略数据文件,因为它们是非常大的,而且Fannie Mae的条款禁止我们重新分配数据,所以我们需要在文件的末尾添加两行:

data
processed

这里有此项目的一个.gitignore文件的示例。

接下来,我们需要创建README.md文件,这将帮助人们了解这个项目。.MD表示给文件是markdown格式。Markdown格式能让你编写纯文本,而且即使你想添加一些花哨的格式也可以支持。这里有markdown格式的指南。如果你上传了一个名为README.md的文件到Github,Github将自动处理markdown格式,并展示给任何对此项目感兴趣的人。下面是一个例子

现在,我们只需要把一个简单的描述添加到README.md文件里:

Loan Prediction
-----------------------

Predict whether or not loans acquired by Fannie Mae will go into foreclosure.  Fannie Mae acquires loans from other lenders as a way of inducing them to lend more.  Fannie Mae releases data on the loans it has acquired and their performance afterwards [here](http://www.fanniemae.com/portal/funding-the-market/data/loan-performance-data.html).

现在,我们可以创建一个名叫equirements.txt的文件,这个文件会帮助其他人容易的部署我们的项目。我们还不知道将会使用哪些库,这里还有一个很好的开头:

pandas
matplotlib
scikit-learn
numpy
ipython
scipy

以上的库中最常用的Python数据分析任务,其基本预测我们会用到其中大多数的库。下面是该项目的例子要求的文件。

在创建requirements.txt文件之后,你应当安装软件包。在这篇文章中,我们将使用Python3,如果您尚未安装Python,您应该考虑使用Python,以上列出Python的安装程序以及还会安装的所有软件包。

最后,我们可以只是创建一个空白的settings.py文件,因为我们没有为项目做任何设置。

获取数据

一旦有了项目的原始框架,我们就可以得到原始的数据。

Fannie Mae在采集数据方面有一些限制,所以你需要注册一个账户,你可以在这里找到下载页面。创建账户后,你就可以根据需要下载尽可能少或尽可能多的贷款数据文件了。该文件是zip格式,解压后体积会相当大。

对于这个帖子的目的在于,我们已经下载了从2012年第一季度到2015年第一季度的数据。然后,我们将需要解压所有的文件,解压文件或,删除原来的.zip文件。最后,贷款预测文件夹应该是这个样子的:

loan-prediction
├── data
│ ├── Acquisition_2012Q1.txt
│ ├── Acquisition_2012Q2.txt
│ ├── Performance_2012Q1.txt
│ ├── Performance_2012Q2.txt
│ └── ...
├── processed
├── .gitignore
├── README.md
├── requirements.txt
├── settings.py

下载数据后,就可以使用头部和尾部的shell命令来查看文件中的行信息了。你将不需要列明查看信息,这样做有助于生成pdf格式

在数据中进行读取

这里有两个问题,是我们的数据难以正确使用:

  • 此收购和性能的数据涵盖多个独立的文件。
  • 每个文件都丢失了头信息。

在我们开始用数据工作之前,我们需要得到如下步骤,我们有一个文件用来获取数据,一个文件用来获取性能数据。每个文件都只需要包含我们关心的列信息和适当的标题。这里的一个问题是性能数据相当大,所以我们尝试削减一些列。

第一步是在settings.py中添加一些变量,这其中将包含我们的原始数据和处理的数据。我们还将添加一些其他的设置,这对后面是有益的:

DATA_DIR = "data"
PROCESSED_DIR = "processed"
MINIMUM_TRACKING_QUARTERS = 4
TARGET = "foreclosure_status"
NON_PREDICTORS = [TARGET, "id"]
CV_FOLDS = 3

把路径存入settings.py文件将会把他们放在一个集中的地方,使他们能够容易的更改。当多个文件指向的是相同的变量时,它更容易吧它们放在一个集中的地方,当你想改变他们的时候可以在每个文件夹中进行编辑。下面是一个settings.py文件的示例。

第二步是创建一个名为assemble.py的文件用来聚集所有成果到两个文件中。当我们运行Python的assemble.py文件时,我们将会处理两个目录里的数据文件。

然后,我们将开始在assemble.py文件中编写代码。我们首先需要定义每个文件的头信息,所以我们需要查看pdf中的列名和创建每次采集和性能的文件中的列信息:

HEADERS = {
  "Acquisition": [
  "id",
  "channel",
  "seller",
  "interest_rate",
  "balance",
  "loan_term",
  "origination_date",
  "first_payment_date",
  "ltv",
  "cltv",
  "borrower_count",
  "dti",
  "borrower_credit_score",
  "first_time_homebuyer",
  "loan_purpose",
  "property_type",
  "unit_count",
  "occupancy_status",
  "property_state",
  "zip",
  "insurance_percentage",
  "product_type",
  "co_borrower_credit_score"
  ],
  "Performance": [
  "id",
  "reporting_period",
  "servicer_name",
  "interest_rate",
  "balance",
  "loan_age",
  "months_to_maturity",
  "maturity_date",
  "msa",
  "delinquency_status",
  "modification_flag",
  "zero_balance_code",
  "zero_balance_date",
  "last_paid_installment_date",
  "foreclosure_date",
  "disposition_date",
  "foreclosure_costs",
  "property_repair_costs",
  "recovery_costs",
  "misc_costs",
  "tax_costs",
  "sale_proceeds",
  "credit_enhancement_proceeds",
  "repurchase_proceeds",
  "other_foreclosure_proceeds",
  "non_interest_bearing_balance",
  "principal_forgiveness_balance"
  ]
}

下一步是定义我们希望保留的列。由于所以我们关于贷款的信息在现有基础上衡量其跟以往的关系,我们可以抛弃很多的性能数据列。我们需要所以采集数据的列,不过因为我们要最大限度地提高被收购贷款的有关信息(毕竟,我们预测如果贷款将永远自安倍取消赎回权或不使用的情况下收购)。丢弃列将帮助我们节省硬盘空间和内存,同时还加快了我们的代码。

SELECT = {
  "Acquisition": HEADERS["Acquisition"],
  "Performance": [
  "id",
  "foreclosure_date"
  ]
}

下一步,我们将编写一个用来连接数据集的函数。代码如下:

  • 导入一些需要的库包括设置。
  • 定义一个函数串连,
    • 即获取数据目录中所有文件的名称;
    • 循环每个文件;
      • 比如如果该文件不是正确的类型则忽略(不是我们想要的前缀开头),
      • 将文件读入到DataFrame通过使用Pandas read_csv方法;
        • 设置分隔符“|”使得所有的字段被正确读入;
        • 该数据没有标题行,所以设置头为空来表明这一点;
        • 从HEADERS字典中获取正确的值来设置名称,这些都将是我们的数据框的列名;
        • 在DataFrame中仅选择我们添加到select里的列名;
        • 将所有的数据帧串联在一起;写入级联数据帧返回一个文件。

import os
import settings
import pandas as pd

def concatenate(prefix="Acquisition"):
    files = os.listdir(settings.DATA_DIR)
    full = []
    for f in files:
        if not f.startswith(prefix):
            continue

        data = pd.read_csv(os.path.join(settings.DATA_DIR, f), sep="|", header=None, names=HEADERS[prefix], index_col=False)
        data = data[SELECT[prefix]]
        full.append(data)

    full = pd.concat(full, axis=0)

    full.to_csv(os.path.join(settings.PROCESSED_DIR, "{}.txt".format(prefix)), sep="|", header=SELECT[prefix], index=False)

我们可以调用上述的方法两次通过参数采集和性能来连接所有的获得和性能文件在一起。代码如下:

  • 只有当脚本是通过命令行调用执行Python的assemble.py文件。
  • 串联所有的文件,并生成两个文件

    • processed/Acquisition.txt
    • processed/Performance.txt

if __name__ == "__main__":
    concatenate("Acquisition")
    concatenate("Performance")

我们现在已经有了一个良好的,划分的assemble.py文件,易于执行,而且容易创建。通过分解问题转化为这样的结果,我们可以很容易的建立我们的项目。而不是一个凌乱的脚本,我们定义脚本之间的传递,使他们有相互完全独立的数据。当你在操作较大的项目时,这是一个很好的主意,因为这使得它更容易改变各个部分,而无需对项目不重要部分得到意想不到的结果。

一旦我们完成了assemble.py脚本,我们就可以运行Python的assemble.py文件了,在这里你可以找到完整的assemble.py文件。
这会在处理目录中生成两个文件:

loan-prediction
├── data
│ ├── Acquisition_2012Q1.txt
│ ├── Acquisition_2012Q2.txt
│ ├── Performance_2012Q1.txt
│ ├── Performance_2012Q2.txt
│ └── ...
├── processed
│ ├── Acquisition.txt
│ ├── Performance.txt
├── .gitignore
├── assemble.py
├── README.md
├── requirements.txt
├── settings.py

在性能数据中计算值

下一步我们将从processed/Performance.txt文件中计算一些数值。所有我们想做的是预测财产是否被法拍。为了搞清楚这一点,我们只需要检查与贷款相关的性能数据中是否曾经有一个foreclosure_date。如果没有foreclosure_date,则该属性从未被法拍。为了避免在我们的样本中,包含很少有表现的历史贷款,我们还需要在每笔贷款的高性能文件中存储许多行计数。这将让我们从训练数据中筛选出没有太多表现的历史贷款。

思考贷款数据和性能数据的一个方法:

image here

正如你在上面看到的,在获取数据的每一行可以和性能数据的多行有联系。在性能数据上,foreclosure_date将出现在当止赎发生四分之一的时候,因此它应该在这段时间之前是空白的。一些贷款从未拍卖,所以所有的性能数据和与它们相关的行具有foreclosure_date空白。

我们需要计算foreclosure_status,这是一个布尔值,表示一个特定贷款的id是否曾经封死,并且performance_count是行中每个贷款ID的性能数据的数目。

有几种方法可以计算出我们想要的总量:

  • 我们可以读取所有的性能数据,然后在数据帧上使用Pandas的groupby方法来计算出与每个贷款ID相关联的行的数目,并且如果foreclosure_date是从不为空的id。

    • 这种方法的好处是,它很容易从语法的角度来实现。
    • 缺点是,阅读所有129236094线路中的数据会占用大量的内存,并极其缓慢。
  • 我们可以读出素有毒性能数据,然后对采集框应用中找到每个id的计数。

    • 好处是,该数据集不需要被加载到内存中,所以它是非常快速和高效的存储器。
    • 不足之处是,它会增长概念的落实,而且我们需要手动去解析行数据。

加载所有的数据需要相当多的存储空间,所以让我们选上面的第三个选择。所有我们需要做的是通过性能数据所有行的迭代,同时将每个贷款id的字典计数。在字典中,仿佛foreclosure_date是有史以来不是没有,沃尔玛·我们会继续跟踪出现在性能数据里的id。这将为我们提供foreclosure_status和performance_count。

我们将创建一个名为annotate.py的新文件,并添加代码,使我们能够计算这些值。在下面代码中,我们将:

  • 导入所需的库
  • 定义一个名为count_performance_rows的方法。
    • Open processed/Performance.txt文件,这并不读取文件到内存中,而是打开一个可用于按行文件中的行读取文件处理程序。
    • 在文件中的每一行进行循环,使用拆分行分隔符“|”,检查贷款id如果不在计数字典里,如果不是添加其到计数,对于给定的贷款id我们是在一个包含它的行递增性能计数器里,如果日期不为空,那么我们知道贷款被法拍,所以设置止赎状态正确。

import os
import settings
import pandas as pd

def count_performance_rows():
  counts = {}
  with open(os.path.join(settings.PROCESSED_DIR, "Performance.txt"), 'r') as f:
  for i, line in enumerate(f):
  if i == 0:
  # Skip header row
  continue
  loan_id, date = line.split("|")
  loan_id = int(loan_id)
  if loan_id not in counts:
  counts[loan_id] = {
  "foreclosure_status": False,
  "performance_count": 0
  }
  counts[loan_id]["performance_count"] += 1
  if len(date.strip()) > 0:
  counts[loan_id]["foreclosure_status"] = True
  return counts

获取值

一旦我们创建了计数字典,我们可以做一个功能,将来自贷款id和一个关键的字典值提取出来:

def get_performance_summary_value(loan_id, key, counts):
  value = counts.get(loan_id, {
  "foreclosure_status": False,
  "performance_count": 0
  })
  return value[key]

上述功能将从计数字典中返回适当的值,并且将使我们能够分配foreclosure_status值和performance_count值到获取数据的每一行。在字典的get方法返回,如果没有找到键的默认值,因此这有利于我们,如果密钥没有在字典中的计数不存在则返回合理的默认值。

注释数据

我们已经增加了一些功能在annotate.py中,但现在我们可以进入文件内部。我们需要将采集的数据转换成可以在一个机器学习算法使用的训练数据集。这涉及到几件事情:

  • 将所有的列变为数字
  • 填写任何遗漏的值
  • 指定performance_count和foreclosure_status到每一行
  • 删除那些没有很多表现的历史的行(性能计数很低)

我们几个列是字符串,其不给机器学习算法是有用的。但是,他们实际上是分类变量,在这里有几个不同的类别代码,例如R,S等。我们可以通过分配一个编号以每个类别标注这些列转换为数字:

image here

转换列这种方式将使我们能够在我们的机器学习算法中使用它们。某些列还包含日期(第一次付款日期和起始日期)。我们可以拆分这些日期到每2列:

image here

在下面的代码中,我们改变了收购数据。我们将定义一个函数:

  • 创建一个foreclosure_status列从数据字典中获取收购止赎状态。
  • 创建一个performance_count列从数据字典中获取收购的业绩。
  • 从以下各字符串列转换成整数列:
    • channel
    • seller
    • first_time_homebuyer
    • loan_purpose
    • property_type
    • occupancy_status
    • property_state
    • product_type
  • 转换first_payment_date和origination_date。
    • 以分隔符拆分列
    • 分配分割列表一个月列的第一部分
    • 分配分割列表一年列的第二部分
    • 删除这一列
    • 最终,我们拥有first_payment_month,first_payment_year,origination_month和origination_year。
    • 任何收购缺省值填充-1.

def annotate(acquisition, counts):
  acquisition["foreclosure_status"] = acquisition["id"].apply(lambda x: get_performance_summary_value(x, "foreclosure_status", counts))
  acquisition["performance_count"] = acquisition["id"].apply(lambda x: get_performance_summary_value(x, "performance_count", counts))
  for column in [
  "channel",
  "seller",
  "first_time_homebuyer",
  "loan_purpose",
  "property_type",
  "occupancy_status",
  "property_state",
  "product_type"
  ]:
  acquisition[column] = acquisition[column].astype('category').cat.codes

  for start in ["first_payment", "origination"]:
  column = "{}_date".format(start)
  acquisition["{}_year".format(start)] = pd.to_numeric(acquisition[column].str.split('/').str.get(1))
  acquisition["{}_month".format(start)] = pd.to_numeric(acquisition[column].str.split('/').str.get(0))
  del acquisition[column]

  acquisition = acquisition.fillna(-1)
  acquisition = acquisition[acquisition["performance_count"] > settings.MINIMUM_TRACKING_QUARTERS]
  return acquisition

聚合所有的事情

我们差不多准备拉都在一起,我们只需要多一点的代码添加到annotate.py。在下面的代码中,我们:

  • 定义一个函数在采集数据的读取。
  • 定义一个函数来写入处理的数据到处理/ train.csv
  • 如果该文件是在命令行中,像蟒蛇annotate.py叫:
    • 阅读在采集数据。
    • 计算计数的性能数据,并将它们分配给计数。
    • 注释采集数据帧。
    • 写在收购数据帧到train.csv。

def read():
  acquisition = pd.read_csv(os.path.join(settings.PROCESSED_DIR, "Acquisition.txt"), sep="|")
  return acquisition

def write(acquisition):
  acquisition.to_csv(os.path.join(settings.PROCESSED_DIR, "train.csv"), index=False)

if __name__ == "__main__":
  acquisition = read()
  counts = count_performance_rows()
  acquisition = annotate(acquisition, counts)
  write(acquisition)

一旦你完成更新文件,一定要与蟒蛇annotate.py运行它,生成train.csv文件。你可以在这里找到完整的annotate.py文件。

该文件夹现在应该是这样的:

loan-prediction
├── data
│ ├── Acquisition_2012Q1.txt
│ ├── Acquisition_2012Q2.txt
│ ├── Performance_2012Q1.txt
│ ├── Performance_2012Q2.txt
│ └── ...
├── processed
│ ├── Acquisition.txt
│ ├── Performance.txt
│ ├── train.csv
├── .gitignore
├── annotate.py
├── assemble.py
├── README.md
├── requirements.txt
├── settings.py

发现错误度量标准

我们正在与我们的生成训练数据集,而现在我们只需要做的最后一步,生成预测完成。我们需要找出一个错误的指标,以及我们如何要评估我们的数据。在这种情况下,有更多的贷款未比都封死了,所以典型精度措施并没有太大的意义。

如果我们在训练中读取数据,并检查计数的foreclosure_status列,这里就是我们得到:

import pandas as pd
import settings

train = pd.read_csv(os.path.join(settings.PROCESSED_DIR, "train.csv"))
train["foreclosure_status"].value_counts()

False 4635982
True 1585
Name: foreclosure_status, dtype: int64

既然这么几个贷款的抵债了,只需检查中正确预测将意味着我们可以作出这样的预测为False每一行,仍然得到了非常高精度的机器学习模型标签的百分比。相反,我们将要使用的度量,是以类不平衡考虑,并确保我们准确预测丧失抵押品赎回权。我们不希望太多假阳性,在那里我们作出预测,一个贷款将封死上,即使它不会,或过多的假阴性,在那里我们预测贷款不会被封死,但它是。这两个,假阴性是房利美更昂贵,因为他们购买的贷款他们可能无法收回投资的地方。

我们将定义假阴性率,其中模型预测没有丧失抵押品赎回权,但贷款数量的贷款实际上是法拍,通过实际上取消抵押品赎回权的贷款总额数除以。这是典型的“未接”实际取消抵押品赎回权的比例。这里有一个图:

image here

在上面的图中,1该笔贷款预测为没有被封死,但它实际上是。如果我们把这个由实际上的,2抵债贷款的数量,我们得到的假阴性率,50%。我们将以此作为我们的误差度量,因此,我们可以评估我们的模型的性能。

设置机器学习的分类

我们将使用交叉验证做出预测。将我们的数据分成3组。然后,我们将做到以下几点:

  • 训练组1和2的模型,并使用该模型,使为3组的预测。
  • 训练组1和3中的模型,并使用该模型,使2组的预测。
  • 训练2和3组模型,并利用该模型,使第1组的预测。

它拆分成组这种方式意味着我们使用我们正在做的预测为相同的数据永远不会训练模式。这就避免了过度拟合。如果我们过度拟合,我们会得到一个错误的低假阴性率,这使得它很难提高我们的算法还是在现实世界中使用它。

Scikit-learn有一个名为cross_val_predict函数,将可以很容易进行交叉验证。

我们还需要选择一个要使用的算法进行预测。我们需要一个分类,可以做二分类。目标变量,foreclosure_status只有两个值,真假。

我们将使用logistic回归,因为它可以很好地用于二分类,运行速度非常快,并且使用较少的内存。这是由于算法如何工作 - 而非建造几十棵,像一个随机森林,或做昂贵的转换,如支持向量机,回归有涉及较少的矩阵运算少得多的步骤。

我们可以使用在实施logistic回归分类算法Scikit-learn。我们需要关注的唯一事情就是每个类的权重。如果我们同样加权类,算法将预测假的每一行,因为它试图最大限度地减少错误。然而,我们关心更多关于取消抵押品赎回权比我们有关未止赎贷款。因此,我们将通过均衡的逻辑回归类的class_weight关键字参数,以获得算法,加权取消抵押品赎回权更多地考虑在每个类的计数差异。这将确保该算法不适合每一行预测假,而是针对预测或者类犯错误同样处罚。

预测

现在,我们有预赛出的方式,我们已经准备好做出预测。我们将创建一个新的文件名为predict.py将使用我们在上一步中创建的文件train.csv。以下的代码:

  • 导入所需的库。
  • 创建一个名为cross_validate该函数:
  • 创建一个逻辑回归分类用正确的关键字参数。
  • 创建一个我们要用来训练模型,删除ID和foreclosure_status列的列表。
  • 在整个运行列车数据帧交叉验证。
  • 返回预测。


import os
import settings
import pandas as pd
from sklearn import cross_validation
from sklearn.linear_model import LogisticRegression
from sklearn import metrics

def cross_validate(train):
  clf = LogisticRegression(random_state=1, class_weight="balanced")

  predictors = train.columns.tolist()
  predictors = [p for p in predictors if p not in settings.NON_PREDICTORS]

  predictions = cross_validation.cross_val_predict(clf, train[predictors], train[settings.TARGET], cv=settings.CV_FOLDS)
  return predictions

预知错误

现在,我们只需要编写一些函数来计算错误。代码如下:

  • 创建一个名为compute_error的函数:

    • 使用scikit-learn 来计算一个简单的精确度得分(预测百分比与实际foreclosure_status的值相匹配)。
  • 创建一个调用compute_false_negatives的函数:

    • 为方便起见,在数据框架里结合目标值和预测值。

    • 发现假阴性率。

      • 发现在模型预测中未取消抵押品赎回权的贷款数量。

      • 将不取消抵押品赎回权的贷款总数进行划分。

把这些全部放在一起

现在,我们只要把这些函数一起放进predict.py里。下面的代码将会:

  • 读取数据集。
  • 计算交叉验证预测。
  • 计算上述3项误差指标。
  • 打印错误指标。

def read():
    train = pd.read_csv(os.path.join(settings.PROCESSED_DIR, "train.csv"))
    return train

if __name__ == "__main__":
    train = read()
    predictions = cross_validate(train)
    error = compute_error(train[settings.TARGET], predictions)
    fn = compute_false_negatives(train[settings.TARGET], predictions)
    fp = compute_false_positives(train[settings.TARGET], predictions)
    print("Accuracy Score: {}".format(error))
    print("False Negatives: {}".format(fn))
    print("False Positives: {}".format(fp))

一旦你添加了代码,你就可以运行Python predict.py生成预测结果。一切运行都表明,我们的假阴性率是0.26,这意味我们错过了他们预测的26%的赎回贷款。这是一个良好的开端,但这用了大量的改进!

你可以在这里找到完整的predict.py文件。

您的文件树现在看起来应该是这样的:

loan-prediction
├── data
│   ├── Acquisition_2012Q1.txt
│   ├── Acquisition_2012Q2.txt
│   ├── Performance_2012Q1.txt
│   ├── Performance_2012Q2.txt
│   └── ...
├── processed
│   ├── Acquisition.txt
│   ├── Performance.txt
│   ├── train.csv
├── .gitignore
├── annotate.py
├── assemble.py
├── predict.py
├── README.md
├── requirements.txt
├── settings.py

写一个README文件

现在,我们已经完成了我们的端对端项目,我们只需要编写一个README.md文件,以便其他人知道我们做了什么,以及如何复制它。一个典型的README.md项目文件应该包括以下几个部分:

  • 该项目的高度概括,以及目标是什么。

  • 哪里可以下载到任何需要的数据或资料。

  • 安装说明。

    • 如何安装的要求。
  • 使用说明。

    • 如何运行项目。

    • 每个步骤结束后,你会看到什么样的结果。

  • 如何为项目做出贡献。

    • 接下来用于扩展该项目的好的步骤:

这里是该项目的一个样本README.md文件。

接下来要做的事

恭喜,你已经完成了端对端的机器学习项目!你可以在这里找到一个完整的项目实例。将你完成的项目上传至Github是个好主意,这样其他人就可以看到这是你个人文件夹的一部分。

这个数据仍然还有相当多的角度可以去探索。从广义上讲,我们可以将它们分割成3类 -扩展项目,并使其更加准确,寻找其他栏目进行预测,并探索数据。以下是一些建议:

  • 往annotate.py 里添加更多特性。

  • 在predict.py里转换算法。

  • 比我们在这篇文章中更多的尝试使用来自Fannie Ma的数据。

  • 在未来数据的预测里添加一个方法。我们写的代码在添加更多的数据后仍然是可以工作的,因此我们可以添加更多的过去或未来的数据。

  • 如果银行应出具的原贷款发生了问题, 尝试看是否可以预测(或者如果Fannie Mae已经获得了贷款)。

    • 从train中 删除任何银行在那是不知道的贷款条款。

      • 当Fannie Mae购买贷款时会知道一些条款,但不是在此之前。
    • 作出预测。

  • 探索看看是否能预测除了foreclosure_status之外更多的栏目。

    • 你可以预测上市时间时物品的价值是多少吗?
  • 探索性能更新之间的细微差别。

    • 你可以预测借款人将有多少次推迟支付吗?

    • 你能映射出典型贷款的生命周期吗?

  • 按洲到洲或者邮编到邮编的方式映射数据。

    • 你能发现其他有趣的模式吗?

CCAI 2016中国人工智能大会将于8月26-27日在京举行,AAAI主席,多位院士,MIT、微软、大疆、百度、滴滴专家领衔全球技术领袖和产业先锋打造国内人工智能前沿平台,6+重磅大主题报告,4大专题论坛,1000+高质量参会嘉宾,探讨人机交互、机器学习、模式识别及产业实战。门票限时六折优倒计时第二天

图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值