作者 | 陆春晖
责编 | 寇雪芹
当我们在进行机器学习领域的学习和研究时,遇到的第一个难点就是数据探索性分析(Exploratory Data Analysis)。虽然从各种文献中不难了解到数据探索性分析的重要性和一般的步骤流程,但是在面对实际问题时,往往会有不知道从哪儿下手以及不知道怎么根据分析结果来优化算法的困境。
本文通过对真实业务场景数据的探索性分析及建模与优化,尝试对其进行解构,揭示其真实的意图和作用,希望能对同行有所启示。本文采用kaggle平台上正在进行的Jane Street 市场交易预测比赛数据,该比赛要求参赛选手设计一个量化交易预测模型,利用全球主要证券所得市场数据识别最有效的交易,从而实现回报最大化。
数据探索性分析从解读数据业务背景开始
数据探索性分析首先要根据数据集所描述的主体含义,即这个数据集蕴含的背景知识,确定其所属的问题领域,通常通过对业务的深刻理解实现。
以Jane Street市场交易预测比赛数据为例,我们首先要理解这个交易预测模型的目的是实现交易牟利最大化,也就是最大限度的实现“低买高卖”,但是由于市场的波动性这个目的很难实现。
因此给定一组交易的历史相关数据(例如股票市场的)和历史回报率,希望能训练出模型,能够根据当前交易的实时相关数据,准确预测该交易的未来回报率,从而筛选出那些回报率高的交易进行操作,回报率低的交易不进行操作。通过对业务背景的解读,我们大致判断这是一个时间序列类的预测问题,根据操作和不操作两种行为,进一步判断出其是时间序列二分类预测问题。
有了对问题领域的大致判断,接下来结合业务背景知识对数据集进一步展开分析。首先观察数据集中训练集和测试集的特征列,如图1所示。
图1 训练集和测试集特征列
发现训练集比测试集多了五列特征,分别是resp_1、resp_2、resp_3、resp_4、resp,resp大致可以猜测代表回报率,可是为什么有五列回报率?我们再回到业务背景中去找答案,业务背景中描述resp_1~resp_4代表不同时间范围内的回报率。不是很理解什么含义,分析一下resp和resp_1~resp_4的相关性,使用热力图进行可视化分析。
图2 回报率各列相关性热力图
通过热力图可视化相关性发现,这五列回报率间存在很明显的相关性,并且越临近的列相关性越高。再选取前10行数据用折线图观察下各列回报率的波动状况。
图3 回报率列折线图
大致可以理解,每笔交易的回报率都是随着时间时刻变化的,resp代表交易时刻的回报率,resp1~resp4代表交易时刻前四个时点的回报率。也就是说,每笔交易的回报率本身也是一个时间序列,在预测进行交易是否进行时,可以依据当前时刻的resp值进行判断,也可以尝试依据给定时间周期内整体的回报率趋势进行判断。
如果依据当前时刻resp值进行是否交易的判断,resp<0时目标值action=0,且resp>0时目标值action=1,则数据集的目标值分布如下图(a)所示,如果依据回报率区间整体均值和最大值进行是否交易的判断,其目标值分布如下图(b)和(c)所示。回报率的使用对目标值分布有一定的影响,可能是影响模型准确性的因素之一。
图(a) 图(b) 图(c)
图4 依据回报率不同角度进行是否交易的分析
通过对数据业务背景的解读,我们已经得知所需要解决的是一个典型的时间序列二分类预测问题,并且其目标值需要通过一组时间序列来确定。
数据探索性分析以特征为最小分析单元
当对整体问题有了大致了解,接下来就需要针对具体的特征变量进行具体分析,分析从三个方面进行。
1.特征含义分析
特征含义往往结合特征变量的名称。部分特征变量往往通过名称就可以大致了解其含义,了解其特征含义可以帮助我们更好的理解数据本身,协助建模。
本文中使用的数据总共有133列特征,其中名称有意义的特征列为‘date’,‘weight’和‘ts_id’,其他列从’feature_0’~’feature_129’,明显是做过匿名处理的特征,暂不做分析。
对名称有意义的特征进行分析。其中‘ts_id’列因为标明是ID列,并且其序号从0开始到2390490无重复,与数据集行数相同,并且因为是时间序列类数据,故可认定其为按一定时间先后排序的交易序列号。
‘date’列顾名思义可知是日期类,观察其具体取值是从0~500的整数,估计每个取值代表一天,并且‘date’每个取值对应的交易数量不同,其分布如下图所示,横坐标代表’date’取值,纵坐标代表每一个’date’取值区间对应的‘ts_id’数量。可以发现交易数量的分布并不平稳,大致以date值85为界限,之前与之后的交易数据分布有明显的差异。
图5 不同日期值交易数量分布
‘weight’列含义为权重,结合背景知识中权重和回报率一起作为评价函数的输入项,并且’weight’为0的交易不影响最终评价函数的评分,大致可以判断其是一个代表交易的盈利率或者说重要性的指标。观察其分布如下图所示。
图6 权重值的分布
其中权重为0的数据大约占总数据量的17.1%,也就是说原始数据集中有17.1%的交易数据,是否进行交易对评价结果不产生影响,可以在训练模型时去掉。
接下来对‘feature_0’~’feature_129’这130维特征进行分析,虽然特征已经做了匿名处理,但是还提供了一个features.csv的文件,描述了特征的一些情况,对其进行分析。文件总共包含30个标签,分别对130维特征进行了True和False的标记,对每维特征的标签数量分析如图7所示。
图7 特征标签数量分析示意图
可以发现‘feature_0’特征比较特殊,一个标签也没有,其他特征都至少存在一个标签,最多不超过四个标签,‘feature_0’特征可能需要给与比较多的关注。
2.特征“脏数据”分析
经过前面的分析,对数据已经有了相对清晰的认知,接下来要对‘feature_0’~‘feature_129’这130维特征做“脏数据”分析,主要包括缺失值和异常值的分析。
缺失值分析可以通过统计特征集中的null值个数实现,各特征的缺失率如下图所示。
图8 特征缺失值比率分析
可以分析得知,130维特征中有88维特征存在缺失值,平均缺失率大致为2.18%,最大缺失率为16.55%,缺失率最大的四个特征是‘feature_17’,‘feature_18’,’feature_27’,’feature_28’,考虑到缺失率没有超过50%,可以先不处理,也可以在建模时用均值或者分位数填充。
异常值分析可以考虑使用箱线图,部分特征的箱线图如下图所示:
图9 部分特征箱线图分析
从图9中发现,除了‘feature_0’外,其他特征都存在许多偏离较大的异常值,可以考虑进行移除。
3.特征统计分布分析
完成特征“脏数据”分析后通常会继续对特征进行统计分布分析。
首先判断特征是否是正态分布的,对于非正态分布的特征可以考虑进行相应转换。之所以希望特征是正态分布的,是因为机器学习领域的很多模型是基于数据服从正态分布的假设,所以如果数据服从正态分布,会对模型的训练效果有比较明显的提升。可以使用Q-Q图对特征进行分析,部分特征的Q-Q图如下图所示。
图10 特征分布Q-Q图
可以发现,很多特征变量的数据分布都不是正态的,后续可以使用数据变化对其进行处理
其次对比训练集和特征集的数据分布是否一致,对于分布不一致的特征,考虑进行删除处理。本文使用KDE分布图来进行观察。130维特征中没有发现训练集和测试集明显分布不一致的特征。
图11 用KDE分布图对比训练集和测试集数据
最后对特征的相关性进行分析,用来发现特征变量和目标变量间、以及特征变量之间的关系,为特征工程中提取特征做准备。本文使用相关性热力图来进行观察。观察与目标值’resp’相关性最高的10个特征变量。
图12 特征间相关性热力图
发现一个非常有意思的现象,与目标值’resp’相关性最高的10维特征,彼此间的相关性也非常高,建模时如果选择线性回归模型,需要对相关性高的特征多加关注。
数据探索性分析为建模提供理论支撑
所有的数据探索性分析最终都是为建模进行服务的。通过上文的数据探索性分析,可以指导我们进行建模。
通过对数据业务背景的解读,我们得知需要建立的是一个基于时间序列的二分类预测模型,可以先采用决策树类模型做基础模型,本文使用了Xgboost分类模型,不对原始数据做任何处理,直接用xgboost模型进行预测分类,训练集和验证集比例为7:3时,基础得分为4078.620。
首先结合对特征含义的分析。考虑过滤掉weight特征值为0的特征,模型得分提升到4292.947,同时调整训练集和验证集的比例分布,当训练集和验证集比例为9:1时,模型得分提升到4601.8。用resp_1,resp_2,resp_3,resp_4,resp五列回归值的均值判断action取值,替代单纯的根据resp判断action取值,模型得分提升到5277.285。
其次结合对特征异常值的分析。由于使用的是树类模型,对缺失值不敏感,可以将缺失值统一处理为-999,也可以用特征的均值替代,对于树类模型来说,模型得分没有明显的提升。
接下来考虑对部分非正态分布的特征进行转化,当对标签为’feature_1’,’feature_2’,’feature_41’,’feature_42’的特征进行log变化,将其转换为正态分布时,模型得分提升到了6310.758。
根据数据探索性分析的结果,完成了第一轮的建模和优化,将模型得分从基础分4078.620,提升到了6310.758,提升率达到54.7%,效果很显著。
第一轮建模和优化完成后进入了一段瓶颈期,于是再次回到数据探索性分析,尝试解构出更多的信息。仍然从特征开始,我注意到‘date’这一列特征,作为时间序列类问题最重要的特征,应该有继续挖掘的价值。首先结合不同日期值交易数量分布图(图5),可以观察到以date=85为界限,之前的日交易频率明显比之后的高,不了解是因为什么原因导致的。根据kaggle网站上的一些建议,尝试放弃掉前85天的数据,只用后415天的数据进行建模,模型得分提升到了6390,再稍微调整下参数,最终达到了6405.901。
调整参数的时候,发现之前建模时犯了一个错误,date这维特征本身有时间约束,建模时不能用未来的数据对历史的数据做验证,所以改变了之前随机划分训练集和测试集的方式,改变使用前385天的数据训练,后30天的数据验证,模型得分提升到了7040.166,尝试调整下训练集和测试集的比例,当使用前375天的数据训练,后40天的数据验证时效果最好,模型得分为8757.05,,在第一轮的基础上又提升了38.7%。
仅仅通过两轮数据探索性分析,便极大地优化了模型,显著提升了预测的效果,由此可见其重要性。并且数据探索性分析可以持续迭代进行,不断挖掘出数据集内隐藏的一些特征,加深我们对于背景知识的理解,指引我们进行有效的特征工程,并且为建立模型和优化模型提供理论依据,是进行数据挖掘和机器学习最有效的辅助手段。