一、基础介绍
机器学习
机器学习的核心是通过模型从数据中学习并利用经验去决策。进一步的,机器学习一般可以概括为:从数据出发,选择某种模型,通过优化算法更新模型的参数值,使任务的指标表现变好(学习目标),最终学习到“好”的模型,并运用模型对数据做预测以完成任务。由此可见,机器学习方法有四个要素:数据、模型、学习目标、优化算法。具体可见系列文章:一篇白话机器学习概念
深度学习
深度学习是机器学习的一个分支,它是使用多个隐藏层神经网络模型,通过大量的向量计算,学习到数据内在规律的高阶表示特征,并利用这些特征决策的过程。
keras简介
本文基于keras搭建神经网络模型去预测,keras是python上常用的神经网络库。相比于tensorflow、Pytorch等库,它对初学者很友好,开发周期较快。下图为keras要点知识的速查表(pdf原版到公众号阅读原文后可见):
二、建模流程
深度学习的建模预测流程,与传统机器学习整体是相同的,主要区别在于深度学习是端对端学习,可以自动提取高层次特征,大大减少了传统机器学习依赖的特征工程。如下详细梳理流程的各个节点并附相应代码:
2.1 明确问题及数据选择
2.1.1 明确问题
深度学习的建模预测,首先需要明确问题,即抽象为机器 / 深度学习的预测问题:需要学习什么样的数据作为输入,目标是得到什么样的模型做决策作为输出。
以预测房价为例,我们需要输入:和房价有关的数据信息为特征x,对应的房价为y作为监督信息。再通过神经网络模型学习特征x到房价y内在的映射关系。通过学习好的模型输入需要预测数据的特征x,输出模型预测Y。对于一个良好的模型,它预测房价Y应该和实际y很接近。
2.1.2 数据选择
深度学习是端对端学习,学习过程中会提取到高层次抽象的特征,大大弱化特征工程的依赖,正因为如此,数据选择也显得格外重要,其决定了模型效果的上限。如果数据质量差,预测的结果自然也是很差的——业界一句名言“garbage in garbage out”。
数据选择是准备机器 / 深度学习原料的关键,需要关注的是:
①数据样本规模:对于深度学习等复杂模型,通常样本量越多越好。如《Revisiting Unreasonable Effectiveness of Data in Deep Learning Era 》等研究,一定规模下,深度学习性能会随着数据量的增加而增加。
然而工程实践中,受限于硬件支持、标注标签成本等原因,样本的数据量通常是比较有限的,这也是机器学习的重难点。对于模型所需最少的样本量,其实没有固定准则,需要要结合实际样本特征、任务复杂度等具体情况(经验上,对于分类任务,每个类别要上千的样本数)。当样本数据量较少以及样本不均衡情况,深度学习常用到数据增强的方法,具体可见系列文章:《数据增强方法的归纳》
② 数据的代表性:数据质量差、无代表性,会导致模型拟合效果差。需要明确与任务相关的数据表范围,避免缺失代表性数据或引入大量无关数据作为噪音。
③ 数据时间范围:对于监督学习的特征变量x及标签y,如与时间先后有关,则需要划定好数据时间窗口,否则可能会导致常见的数据泄漏问题,即存在了特征与标签因果颠倒的情况。
以预测房价任务为例,对数据选择进行说明:
- 收集房价相关的数据信息(特征维度)和对应房价(标签),以及尽量多的样本数。数据信息如该区域的繁华程度、教育资源、治安等情况就和预测的房价比较相关,有代表性。而诸如该区域“人均养的兔子数”类数据信息,对房价的预测就没那么相关,对于无代表性的数据特征的加入,主要会增加人工处理的成本、计算复杂度,还有可能引入了模型学习的噪音。
- 划定好数据时间窗口。比如我们可以学习该区域历史2010~2020年的房价,预测未来2021的房价(这是一个经典的时间序列预测问题,常用RNN模型)。但却不能学习了2021年或者更后面的未来房价、人口数等相关信息,反过来去预测2021年房价,这就是一个数据泄露的问题(模型都学习了与标签相关等未知的信息,还预测个啥?)。
本节代码
如下加载数据的代码,使用的是keras自带的波士顿房价数据集。一些常用的机器学习开源数据集可以到http://kaggle.com/datasets、http://archive.ics.uci.edu等网站下载。
from keras.datasets import boston_housing #导入波士顿房价数据集 (train_x, train_y), (test_x, test_y) = boston_housing.load_data()
波士顿房价数据集是统计20世纪70年代中期波士顿郊区房价等情况,有当时城镇的犯罪率、房产税等共计13个指标(特征)以及对应的房价中位数(标签)。
2.2 特征工程
特征工程就是对原始数据分析处理,转化为模型可用的特征。这些特征可以更好地向预测模型描述潜在规律,从而提高模型对未见数据的准确性。对于深度学习模型,特征生成等加工不多,主要是一些数据的分析、预处理,然后就可以灌入神经网络模型了。
2.2.1 探索性数据分析
选择好数据后,可以先做探索性数据分析(EDA)去理解数据本身的内部结构及规律。如果你对数据情况不了解,也没有相关的业务背景知识,不做相关的分析及预处理,直接将数据喂给模型往往效果不太好。通过探索性数据分析,可以了解数据分布、缺失、异常及相关性等情况。
本节代码
我们可以通过EDA数据分析库如pandas profiling,自动生成分析报告,可以看到这份现成的数据集是比较"干净的":
import pandas as pd import pandas_profiling # 特征名称 feature_name = ['CRIM|住房所在城镇的人均犯罪率', 'ZN|住房用地超过 25000 平方尺的比例', 'INDUS|住房所在城镇非零售商用土地的比例', 'CHAS|有关查理斯河的虚拟变量(如果住房位于河边则为1,否则为0 )', 'NOX|一氧化氮浓度', 'RM|每处住房的平均房间数', 'AGE|建于 1940 年之前的业主自住房比例', 'DIS|住房距离波士顿五大中心区域的加权距离', 'RAD|距离住房最近的公路入口编号', 'TAX 每 10000 美元的全额财产税金额', 'PTRATIO|住房所在城镇的师生比例', 'B|1000(Bk|0.63)^2,其中 Bk 指代城镇中黑人的比例', 'LSTAT|弱势群体人口所占比例'] train_df = pd.DataFrame(train_x, columns=feature_name) # 转为df格式 pandas_profiling.ProfileReport(train_df)
2.2.2 特征表示
像图像、文本字符类的数据,需要转换为计算机能够处理的数值形式。图像数据(pixel image)实际上是由一个像素组成的矩阵所构成的,而每一个像素点又是由RGB颜色通道中分别代表R、G、B的一个三维向量表示,所以图像实际上可以用RGB三维矩阵(3-channel matrix)的表示(第一个维度:高度,第二个维度:宽度,第三个维度:RGB通道),最终再重塑为一列向量(reshaped image vector)方便输入模型。
文本类(类别型)的数据可以用多维数组表示,包括: ① ONEHOT(独热编码)表示:它是用单独一个位置的0或1来表示每个变量值,这样就可以将每个不同的字符取值用唯一的多维数组来表示,将文字转化为数值。如字符类的性别信息就可以转换为“是否为男”、“是否为女”、“未知”等特征。
②word2vetor分布式表示:它基本的思想是通过神经网络模型学习每个单词与邻近词的关系,从而将单词表示成低维稠密向量。通过这样的分布式表示可以学习到单词的语义信息,直观来看语义相似的单词其对应的向量距离相近。
本节代码
数据集已是数值类数据,本节不做处理。
2.2.2 特征清洗
- 异常值处理 收集的数据由于人为或者自然因素可能引入了异常值(噪音),这会对模型学习进行干扰。 通常需要处理人为引起的异常值,通过业务及技术手段(如数据分布、3σ准则)判定异常值,再结合实际业务含义删除或者替换掉异常值。
- 缺失值处理 神经网络模型缺失值的处理是必要的,数据缺失值可以通过结合业务进行填充数值或者删除。 ① 缺失率较高,结合业务可以直接删除该特征变量。经验上可以新增一个bool类型的变量特征记录该字段的缺失情况,缺失记为1,非缺失记为0; ② 缺失率较低,可使用一些缺失值填充手段,如结合业务fillna为0或-9999或平均值,或者训练回归模型预测缺失值并填充。
本节代码
从数据分析报告可见,波士顿房价数据集无异常、缺失值情况,本节不做处理。
2.2.3 特征生成
特征生成作用在于弥补基础特征对样本信息的表达有限,增加特征的非线性表达能力,提升模型效果。它是根据基础特征的含义进行某种处理(聚合 / 转换之类),常用方法如人工设计、自动化特征衍生(如featuretools工具):
深度神经网络会自动学习到高层次特征,常见的深度学习的任务,图像类、文本类任务通常很少再做特征生成。而对于数值类的任务,加工出显著特征对加速模型的学习是有帮助的,可以做尝试。具体可见系列文章:一文归纳Python特征生成方法(全)
本节代码
特征已经比较全面,本节不再做处理,可自行验证特征生成的效果。
2.2.4 特征选择
特征选择用于筛选出显著特征、摒弃非显著特征。这样做主要可以减少特征(避免维度灾难),提高训练速度,降低运算开销;减少干扰噪声,降低过拟合风险,提升模型效果。常用的特征选择方法有:过滤法(如特征缺失率、单值率、相关系数)、包装法(如RFE递归特征消除、双向搜索)、嵌入法(如带L1正则项的模型、树模型自带特征选择)。具体可见系列文章:Python特征选择(全)
本节代码
模型使用L1正则项方法,本节不再做处理,可自行验证其他方法。
2.3 模型训练
神经网络模型的训练主要有3个步骤:
- 构建模型结构(主要有神经网络结构设计、激活函数的选择、模型权重如何初始化、网络层是否批标准化、正则化策略的设定)
- 模型编译(主要有学习目标、优化算法的设定)
- 模型训练及超参数调试(主要有划分数据集,超参数调节及训练)
2.3.1 模型结构
常见的神经网络模型结构有全连接神经网络(FCN)、RNN(常用于文本 / 时间系列任务)、CNN(常用于图像任务)等等。具体可以看之前文章:一文概览神经网络模型
神经网络由输入层、隐藏层与输出层构成。不同的层数、神经元(计算单元)数目的模型性能也会有差异。
- 输入层:为数据特征输入层,输入数据特征维数就对应着网络的神经元数。(注:输入层不计入模型层数)
- 隐藏层:即网络的中间层(可以很多层),其作用接受前一层网络输出作为当前的输入值,并计算输出当前结果到下一层。隐藏层的层数及神经元个数直接影响模型的拟合能力。
- 输出层:为最终结果输出的网络层。输出层的神经元个数代表了分类类别的个数(注:在做二分类时情况特殊一点,如果输出层的激活函数采用sigmoid,输出层的神经元个数为1个;如果采用softmax,输出层神经元个数为2个是与分类类别个数对应的;)
对于模型结构的神经元个数 ,输入层、输出层的神经元个数通常是确定的,主要需要考虑的是隐藏层的深度及宽度,在忽略网络退化问题的前提下,通常隐藏层的神经元的越多,模型有更多的容量(capcity)去达到更好的拟合效果(也更容易过拟合)。搜索合适的网络深度及宽度,常用有人工经验调参、随机 / 网格搜索、贝叶斯优化等方法。经验上的做法,可以参照下同类任务效果良好的神经网络模型的结构,结合实际的任务,再做些微调。