关于人肉工程,包括业务知识、领域知识,经验等,在实际的机器学习问题中的应用,是一个屡见不鲜的话题,典型的有苦逼的数据清洗、人肉特征工程等。大家都想把尽可能多的过程由机器自动完成,但是目前的状态是,大部分机器学习问题中,最困难也最重要的部分,还是依靠人的经验来生成特征。那么人的经验为什么重要,能否用机器完成这个过程,本文试作一简单分析。
机器和人看待数据的区别
首先要看一下,从机器的角度看,机器学习是怎样一个问题?在机器看来,机器学习的问题通常是在一组特征上,最大化某个目标函数。注意,对于这组特征而言,机器是理解不了它的含义的。举例来说,下面一组数据(第一列是targe)
0, 1, 1, 0
1, 0, 1, 1
1, 0, 0, 1
…
你能看出这组数据是什么含义吗?显然不能。但是完全可以用它训练一个分类模型,比如logistic regression。
然后查看一下关于这组数据的描述,知道这是关于某个班某次考试的结果,第一列表示物理是否及格,后面三个特征分别是性别、文理科班、数学是否及格,那么现在我知道这组数据的含义了。这样又可以训练一个logistic regression模型。问题来了,这两个模型有区别吗?显然没有。也就是说,人是如何理解数据含义的,对于算法并没有任何影响。因为从机器的角度看,这都是一堆数字而已。
现在看另一个例子,这里有一个特征是这样的
1, …, 1431174193, …
1, …, 1431087793, …
0, …, 1431001393, …
1, …, 1430914993, …
0, …, 1430828593, …
…
能看出这个特征是什么吗?如果你猜测这是时间(timestamp)——那么,你已经开始使用领域知识了。对于机器来说,这只是一个整数序列而已。如果我们把这组数据代入一个线性模型,那么意味着默认预测目标和特征之间是线性关系。也就是说,学习算法的假设空间仅包含timestamp的线性函数。
机器能否通过“学习”达到和人的知识相同的效果
现在,我们既然知道这是日期,就可以增加特征,比如从日期中提取月份、星期、小时等。假设增加“小时”这么一个特征,注意,这个变换是非线性的,这里使用了人的知识。对于机器而言,没有这样的知识。如果要求机器能自动提取出这个特征,那么学习算法的假设空间至少应该覆盖timestamp到小时的转换函数,类似于(timestamp/3600)%24
。这会增加假设空间的维度。如果知道函数的形式也还好,比如知道(timestamp/a)%b
, 这样只需要拟合a、b两个参数。但是实际问题往往是,我怎么知道特征的转换函数是怎样的?也许是log(sin(a x)) / (exp(x) + x^2)
,如果要求假设空间涵盖各种可能的函数形式,那必然大大增加假设空间的维度,很容易导致过拟合。比如神经网络,三层网络就可以逼近任意函数(有个什么连续性还是可导条件,忘了),但是太容易过拟合了,而且存在局部最优的问题。
所以,人的知识的作用在于特征变换。更进一步说,如果人的知识可以给出有效的特征变换,那么可以大大降低搜索空间的维度。对于线性模型而言,模型本身可以处理所有线性的情况,如果人的知识所产生的特征变换也是线性的,那么对于模型没有任何提升,只有非线性的变换才对模型有影响。而如果要求模型能够自动的学习出相同的非线性变换,则会造成模型的特征空间维度大大提高。
而人类的知识是千万年间积累下来的,其中包含了很多复杂的变换,而且知识之间相互依赖,如果要理解一个概念,往往需要首先理解其他的很多概念,所以,从这个意义上将,要求机器学习出人类的知识结构是不太现实的。当然,机器不必模仿人类的知识,可以学习出另外的特征变换,只要最后的模型是有效的。所以为什么现在的deep learning这么火,因为它在控制过拟合的前提下,能够在一定程度上学习出特征变换的形式,也就是在一定程度上完成了人肉特征工程的工作,目前大概也只有deep learning能做到这一点。不过,从目前的实践情况来看,人的知识仍然在具体问题中起着重要的作用。
“算法工程师”的角色和职责
基于此,可以把典型的机器学习建模过程分成三个阶段:
数据清洗、预处理、特征变换 -> 代入标准机器学习算法 -> 将结果应用到业务问题
其中,只有中间的部分是标准化的(所以一般大家都是调用现成的软件包),而两头的,则需要由人工完成,也就是把数据解释、变换成机器要求的形式,以及对结果的含义做出解释。因为机器理解不了数据的含义。
如果从这个角度看待“算法工程师”,或者“数据科学家”之类的角色,这种职业的作用在于解释数据,而不是算法研究或者编程。机器学习算法将会越来越标准化、平台化,使用门槛降低,数据科学家将不再需要处理大量的编程细节,而是越来越类似传统的医疗或金融行业的数据分析师,重在理解业务和数据。算法的研究由科研人员负责,而工程细节由通用的(分布式)平台解决。算法工程师的重点在于数据的预处理、特征生成以及模型选择和参数优化,这也是和现实情况相符的。
目前机器学习的应用还处于粗放阶段,要搭建一个系统,必须应付大量的编程细节。比如一个使用LR进行CTR预测的系统,即使使用开源的模块搭建,也往往要处理许多接口、测试和训练集划分、甚至数据存储的细节。然而,这些细节都和问题的本质无关。将来,这些技术细节将被屏蔽。例如,用一种类似SQL的语言执行模型训练过程,类似于
CLASSIFY click
RELATE TO time, pos, user_id, ad_id
FROM ad_show_dataset
WHERE '2015-07-01' <= time <= '2015-07-31'
USING logistic_regression
CROSS VALIDATION TRAIN 40% random TEST else
EVALUATE WITH auc;
EXPORT MODEL file_path FORMAT PRML;
这段代码比较接近自然语言了,意思是以click为目标,以time, pos, user_id, ad_id为特征,ad_show_dataset中2015-07-01到2015-07-31之间的数据为样本,训练logistic regression模型,其中随机选择40%作为训练集,其他作为测试集。模型以auc为评估指标。最后将训练出的模型以PRML格式导出到file_path。(如果你看了上面的代码后不明白,还要看这段解释,说明我的语法设计的不好。)
从更广的范围来说,计算机技术的发展过程,就是一个不断降低人们使用计算机门槛的过程,用Brooks大神的话说,是“消除软件领域的非本质性困难”。最初的程序员,需要写汇编代码、直接处理CPU与内存。C语言和操作系统出现以后,编程门槛降低了,但是仍然免不了处理底层细节。而Java、python、php等语言出现后,编程门槛进一步降低,只要稍微经过一些培训的人,都可以写代码。而有关进程调度、内存管理、IO、缓存一致性等底层细节,被少数专业化的制作编译器、操作系统、虚拟机等的程序员掩盖。而大部分程序员的职责,是把业务逻辑“翻译”成计算机听得懂的语言。
机器学习和分布式系统也将沿着这个路线发展。少数专业化程度很高的程序员负责平台开发,屏蔽技术细节,消除“非本质性困难”,使得算法工程师或数据科学家可以专注于业务逻辑和数据含义。这个职业的性质将越来越接近产品经理,而不是工程师。工程师的技术是通用的,比如一个音乐网站的php工程师,到一个互联网金融公司写php,技术上没什么区别。而产品经理就不一样了,因为音乐和金融的业务、用户、商业模式有很大不同。
结论
所以,直白的说,算法工程师的本质就是数据解释、清洗、预处理、人肉特征工程、参数调优等。究其根本原因,在于计算机理解不了数据的含义。如果有一天计算机能够理解数据含义了,那就像计算机能听懂自然语言一样,大部分程序员可以下岗了。