这篇文章我将从两个方面写一些机器学习模型的事项,一是如何从真实数据中抽取数据集,二是如何从数据集构建机器学习模型。因为第一部分偏向工业应用,我们先从第二部分开始。内容比较多,大概要好几篇文章才能写完吧(╯‵□′)╯︵┻━┻
1.构建机器学习模型
我们首先从最常见的Supervised Learning开始,之后会介绍unsupervised Learning及Reinforce Learning算法的一些细节。
1.1 数据分析(Data Exploration)
一般来说我们提取后的的数据集可能并不是像SPAM或者MNIST的标准数据集,我们需要在观察数据的过程中思考以下几个问题:
- 数据应该怎么清洗和处理才是合理的?
- 数据中的哪些特征会对标签的预测有帮助?
- Balanced Or Unbalanced问题?
- 根据数据的类型可以挖掘怎样的特征?
1.1.1 数据预处理(Data Preprocessing)
(1)首先我们要考虑对数据进行分析,因为数据的特征项可能并不是同一量纲,甚至不是一种数据类型,直接比较可能导致溢出以及分析误差。我们主要考虑以下方面:
- 是否要对特征向量化,一般除了决策树这种对特征不敏感的算法外,其他大部分都是只能取数值类型变量,需要进行合适的编码操作,常用的有One-hot Encoding(但会导致Sparse及抹除数据相关性等问题),哈夫曼编码(复杂度问题)等;
- 是否要对连续变量进行分割,因为一些如MAP等概率算法一般无法处理连续变量;
- 是否要考虑数据的序数特性,对此类数据要用有序的编码方式如rank编码或序数编码;
- 是否要考虑数据的特殊性,如时间变量,一般可以独立地作为核心变量;
(2)在做后续数据处理之前,我的建议是先进行数据归一化(Data Nomalization),同样因为不同数据之间的量纲可能是不同的,先进行归一化可以防止我们在分析数据时意外抹除了一些有效地特征,这里一般会用maxminmap算法及z-score算法(quantile normalization也有,不过不常见)等,前者将特征映射到[-1,+1],后者将特征映射到零均值单位方差的高斯区间。
这里提一下Normalization的作用:
- 规范化特征,保证特征之间可以比较,这一点可以参考SVM;
- 加速训练过程及表现Performance,这一点可以参考反向传播梯度更新问题,也就是Adam和RMSprop算子的核心;
- 减少溢出错误的可能,这一点可以参考C语言等的溢出问题,Python因为使用Block块存储数据,这方面的问题可能还好一些;
但Normalization也有问题,比较明显的是舍入误差,以及均值信息的移除。
最后一些分类器如朴素贝叶斯Naive Bayer在做连乘积的过程中不进行Normalization可能会导致算法失效,不过算是特例,大部分分类器没有这个问题。
(3)由于收集的数据不是完美的,我们要考虑数据是否是满的(full data set),如果数据不是满的,我们就必须要考虑对数据进行清洗或者数据填充。数据清洗一般可以选择直接删除column不满的样本或者不满的特征族,优点是不会引入错误数据,但缺点是造成数据丢失,而数据填充则可以选择依据中值,均值,零以及概率填充等方式保留样本项,优缺点与前者正好相反。概率填充在决策树模型比较常用,而更一般的我们会选择保留特征观察后再考虑填充与运用。
1.1.2 数据分析(Data Analysis)
接下来我们要考虑特征的相关性(Data Relevance),低相关性模型可能是边缘特征,也可能是噪声,我们需要对这部分特征进行分类处理。一般来说分析相关性有以下方法:
a.皮尔逊相关系数,描述了特征与标签的线性相关性,但是在高次特征可能失效;
b.斯皮尔曼相关秩,描述了特征与标签的秩相关性,比较常用;
c.卡方检验,描述特征相关性,常用与检验特征的独立性;
不过这三种是理论方法,在现实应用上我们更多用的是特征工程:
总结一下,也就是要移除低方差(low variance),共线性(cor-linear),难编码,低相关(low relevance)及不合理(outlier)的特征。一般来说常用的有绘制histogram或者coefficient matrix做处理前后的分析。
例如在分析某个特征的分布常用的hisogram
以及分析变量相关性的coefficient matrix:
用法很多,建议多尝试吧,我就不具体举例了。
1.1.3 数据聚合(Data Aggregation)
这里的数据组合其实也就是对一般的数据特征,我们可以组合产生高次特征,这一点可以参考SVM的Kernel方法,对特征进行组合并升维,使得样本在高维度更容易分类。或者对一些变量进行聚合,例如小时间区间聚合成大事件区间。这个方法有太多的tricks我并不太喜欢,不过数据集比赛效果似乎很好。稍微举个栗子:
假设有样本:
特征1 特征2
- a t1
- b t2
前者的大意就是生成特征3(at1) ,特征4(aa),特征5(abb) etc.
后者则是如果t1-t2间隔过小就把样本1,2合并,特征去max或者mean都可以。
1.1.4 数据扩充(Data Boost)
而后我们考虑一下,加入数据集不是平衡的,也就是Balanced Or Unbalanced问题。例如大量正样本,少量负样本,我们可以用ROC或者PC图分析分类器结果,但很难依据这些不平衡训练好的分类器,此时我们可以考虑down-sampling的随机采样或up-sampling的数据增强(Data Augmentation)。down-sampling很直接,而up-sampling可能我再简单说明一下比较好。
up-sampling最常用的方式是SMOTE算法(Synthetic Minority Over-sampling Technique),其实也就是通过k个小类的最近邻用line segments joining产生synthetic的样本(原谅我没想出个好的翻译方式[(σ-`д・´)好气]。
基本产生也很简单 C=aA+(1-a)B,用滑动变量a做不同的k近邻的trade-off来产生新的伪样本,具体可以参考Chawla,Hall,& Kegelmeyer在2002的论文。但是这个算法的问题是新数据只会在旧样本内部,代表性可能远小于旧样本,参考SVM的非支持向量,因此随后出现Borderline SMOTE及ADASYN。
另一种则是SPO(Structure Preserving Oversampling),这个我没想好怎么解释,可能看一下这篇论文比较好:
Structure Preserving Oversampling for Imbalanced Time Series Classification (icdm 2011)
以及Integrated Oversampling for Imbalanced Time Series Classification (TKDE,2013)
最后我们可以做optimal的选择,也就是数据增强(Data augmentation)。常用的有以下两种不同的使用场合:
- 对文本类的文字特征可以考虑添加语法语义诸如Pos-tagger,Parsing及FOL等扩充,我们留到NLP算法再做讲解及实现;
- 对图形的像素特征,我们可以运用包括切割(clip),旋转(rotate),翻转(reverse),缩放(scale)等方法做数据集的扩充,具体可以参考:Keras中文文档(图片预处理) 这其实是因为在做比赛时数据可能并不足够支撑复杂模型,我们用数据增强的方式降低模型的方差。在这一点上,诸如锐化钝化,高斯模糊,色相变换甚至尺度空间从原理上都是可以做为数据增强项的,可能是因为复杂度的关系才没有广泛应用;
1.1.5 数据降维(Dimension Deduction)
这里主要提两种算法,PCA和LDA,实施细节及其他的算法可以参考以下链接:
四大机器学习降维算法:PCA、LDA、LLE、Laplacian Eigenmaps
做数据降维的主要目的是将特征重新投影到新的空间,以求新维度空间可以以一个低维度的尺度来描述高纬度的原始数据,并最大可能保留原始信息。降维可以在降低模型冗余的同时减少噪音,发掘本质特征及解决Sparse问题,但计算的空间复杂度极大,在模型较小的时候我们有时会采用这种算法,不过现代模型用处可能不大,尤其是在HDFS环境下,我们更希望模型是独立的而不是PCA,LDA这种比较global的算法,独立的算法更便于我们部署MapReduce的设计。Spark的流式RDD图可能会有global的一些优化吧,只能以后研究清楚再来说明了。
PCA算是最常用的数据降维方式,核心思路是将原始特征空间映射到彼此正交的特征向量对应的空间,复杂度主要集中在分解特征向量的过程,而一般数据在非满秩的情况下更多会用SVD分解来构建特征向量;
LDA则是在PCA的基础上要求最小化组内距的同时最大化组间距,其实也就是fisher法则。
以上主要是数据的分析部分,下一篇我们开始讨论模型选择及模型原理分析。
最后在这篇的结尾再补充点具体的东西,以后大概会在每篇结尾写一些具体结构。今天主要说一下DQN这个东西吧。Stanford的公开课有专门介绍这个鬼东西的,其实我觉得这个东西用generator类比可能比较合适。
传统的RL算法不论是Dynamic Programming还是Q-learning都需要基于Reward矩阵构建Value矩阵以作迭代,思路很直接,Bellman公式也很容易接受,但是有个问题,就是需要的状态矩阵可能及其庞大,一个256256的像素游戏,就需要pow(256,256256)的状态,这是不可接受的。而DQN则将256的像素作为输入值,256*256的像素点作为输入特征,通过权值拟合来达到比较好的分离,或者说低维度表示高纬度。
每次在转移状态时,传统算法用的是O(1)的hashmap,这个hashmap的空间就是算法的局限性,尤其是在状态无限时,算法会直接失效,这一点可以参考self-driving的问题。
而DQN用的是MLP的深层网络,相当于时间换空间,不过更多的是通过拟合产生对新状态的判断,解决了RL算法中无法对新状态做估计的问题