[长文手敲] 简论机器学习——机器学习之前,先学会看数据(其二)

数据表里没有一桩小事 上一篇我们反复申说,机器学习项目真正启动之前,最好先把数据这件头等大事端详清楚。 听上去像极了一句正确得令人打不起精神的唠叨。 好比出门前有人叮嘱你观测天象,下厨前提醒你刷锅净灶,写代码前告诫你先读懂需求文档。 道理桩桩件件都对,执行起来却常常被当作耳旁风,左耳进右耳出。 很多...
[长文手敲] 简论机器学习——机器学习之前,先学会看数据(其二)
[长文手敲] 简论机器学习——机器学习之前,先学会看数据(其二)

数据表里没有一桩小事

上一篇我们反复申说,机器学习项目真正启动之前,最好先把数据这件头等大事端详清楚。

听上去像极了一句正确得令人打不起精神的唠叨。

好比出门前有人叮嘱你观测天象,下厨前提醒你刷锅净灶,写代码前告诫你先读懂需求文档。

道理桩桩件件都对,执行起来却常常被当作耳旁风,左耳进右耳出。

很多人接过数据以后,第一反应仍然是立刻让流程跑起来,片刻都不想耽搁。

导入 pandas,读取一份 csv 文件,瞄一眼前五行,确认没有当场报错,接着便是一气呵成的连续操作——切分训练集与测试集,挂载一个模型,最后目不转睛地盯住分数。

整个过程行云流水,手法娴熟,一副老师傅的派头。

唯一的问题是,数据可能从最初那一秒便开始不动声色地蒙骗你。

字段名称看上去无可挑剔,背后的含义或许南辕北辙。

数字排列得整整齐齐,单位却可能张冠李戴地混在一处。

类别列瞧上去干净利落,内里却可能藏匿着大小写乱斗、首尾空格、缩写异体、历史版本,以及运营同学一时心急添加的一连串天书般的选项。

标签列表面只有 0 和 1 两个数字,骨子里也许已经混杂了三套互不通气的业务口径。

样本数目粗看蔚为壮观,真正有价值的有效样本说不定稀稀拉拉,像清晨八点教室里醒着的大学生那般屈指可数。

因此,看数据的第二步,绝不能浅尝辄止,只停留在“有没有缺失值”“有没有重复行”“有没有异常点”这类初级检查上。

这些当然都要逐一审视。

但更要紧的是,弄明白这些数据千回百转之后,究竟在向你诉说什么。

机器学习世界中最容易遭到忽略的一件事是,数据表从来就不是天然生长成机器可以照单全收的模样。

它常常是业务流程、系统埋点、人工操作、历史迁移、统计口径以及各式各样的临时补丁一针一线缝合而成的产物。

你以为自己面对的是一张干净利落的训练表。

实际上,你面对的可能是一块沉淀了组织记忆的活化石。

上边刻着产品经理的需求变更痕迹,烙着后端工程师的字段命名偏好,浸着运营人员的活动统计习惯,粘着客服系统的补录记录,甚至还残留着某位离职同事三年前留下的一句“先这样吧,往后再说”。

然后模型规规矩矩地坐到一旁,面容诚恳地表示:好的,我都听明白了,现在开始认真学习。

字段是现实世界的压缩包

打量数据时,许多人习惯把字段径直理解为表格里的一列。

年龄是一列,收入是一列,登录次数是一列,所在地区是一列,订单金额是一列。一眼扫过去,清清楚楚,宛如一张收拾得规规整整的办公表格。

然而从机器学习的视角出发,字段绝不仅仅是一个列名那么简单。

字段,是现实世界被高度压缩之后的象征符号。

一个简简单单的“年龄”,背后可能是用户信手填报的年龄,也可能是从身份证号码推算而得的年龄,还可能是运营活动里随手勾选的年龄段分组。

一个看似明确的“地区”,可能源自用户注册时填写的所在地,可能来自 GPS 定位,可能出自 IP 地址归属地,也可能引用自收货地址。

一个“活跃天数”,或许统计的是自然日,或许只计算登录日,或许进一步限定了打开应用且停留超过某个秒数的日子。

你目光所及,是一枚干干净净的字段。

模型视野所及,是一串数字或者一个类别。

业务角度所及,是一处行为切片。

工程系统所及,则是一条采集链路返回的结果。

这几层认知倘若没能对齐,后面便会接二连三地爆发经典事故。

比如,做一个用户价值预测项目,同事把“累计消费金额”视作强力特征。

模型练得虎虎生风,指标一路高举高打,大家抚掌相庆,以为万事大吉。

可一旦回过身来细细追问业务场景,才发现预测目标明明是用户未来三十天内的消费潜力。

再翻回头核查字段定义,赫然看见“累计消费金额”里竟然囊括了预测窗口之后才发生的消费记录。

这压根儿不是模型有多么神通广大。

这分明是模型演员在台上念台词,而你只是悄悄把下一幕的剧本预先塞进了它的口袋。

再比如,做一套设备故障预测系统,特征中包含一条“最近一次维修的状态”。线下评估分数一骑绝尘,仿佛开启了上帝视角。

等到系统真正部署上线才恍然大悟:现实预测的那个时刻,维修状态根本还没有发生,等于一张来自未来的纸条。

模型此前学得入木三分,实际上只是老老实实地背诵了售后系统里早已知道的结论。

这种情形在各类文档中通常被称作数据泄露

scikit-learn 的实践指南清晰无误地提醒过,训练数据与测试数据必须先切分开来,测试集绝对不允许参与任何形式的拟合式预处理,那些看似无害的特征筛选、标准化、缺失值填充,个个都可能成为泄露的暗道。

不计其数的机器学习项目,起步阶段便折戟于此。

而且败得还挺有面子。

因为线下评估的分数实在是太高了,高到让人不好意思去质疑它,仿佛一名学生在模拟考试前就拿到了最终答案。

他当然是满分,甚至还因此虚幻地相信自己已经打通了任督二脉。

可当真正的大考来临,他会沮丧地发现,自己善于背诵答案,却丝毫不懂解题。

模型也同样如此。

它不会主动向你发出绅士般的提醒——朋友,这个字段到了真正做预测的那一刻,我是拿不到手的。

数值型字段未必真是数值

看数据时需要拆解的第一重误会,往往正巧落在数值型字段头上。

大量字段在数据库里被标记为 int 或者 float,于是很多人顺理成章地把它当作连续数值特征来使用。好像它们天然就能加减乘除,能归一化缩放,能直接馈入模型,一切看上去畅通无阻。

可数字的外皮底下,并不天然代表连续意义。

邮政编码是一串数字,省市区行政编码也是一串数字,商品类目 ID 是数字,用户等级有时也是数字。

它们披着数值的皮相,骨子里却更接近类别。

Google 的机器学习课程曾特意点出,像邮编这样的整数,往往更适合按类别来处理,因为倘若径直把它当成连续数字,模型便会产生一种煞有介事的错觉,以为不同邮编之间存在着某种大小的次序与比例关系。

这一认知非常关键。

因为模型并不会凭借常识去理解,“10001”与“20002”只不过是两枚符号。

你若坚持把它们当作数值塞进去,模型就可能一丝不苟地去学习:20002 大约是 10001 的两倍。

当你事后盯着模型的输出发呆时,心中难免翻江倒海:这玩意儿,到底学到了一些什么东西?

类似的问题俯拾皆是。

用户 ID 不可直接当作数值来用。

订单号不能当成数值来用。

城市行政编码不可径直当成连续变量。

商品 SKU 编码也不该被当作普通数字。

这些字段身上穿的数字外衣,仅仅是数据库为了方便存储和索引而保留下来的时装。

你不能因为看见它穿了件数字模样的衣裳,就定势地以为它天生适合塞进回归模型里去唱主角。

这就好比一个人披了一身白大褂,你不能不分青红皂白,立马把他推上手术台主刀。万一他是食堂里掌勺的大师傅,只不过今天衣服颜色刚好撞了衫呢?

真正合格的数值型字段,理应具备某种无可辩驳的数量含义。

面积从五十平米增加到一百平米,通常可以理解为扩大了一倍。

价格从十元涨到二十元,通常可以理解为提高了一倍。

时长从五分钟延长到十分钟,也可以进行类似的递推理解。

然而,即便它是货真价实的数值,你也得耐住性子继续打量它的分布。

平均值看上去四平八稳,绝不代表数据本身没有问题。

收入、消费金额、视频播放量、粉丝数目、网络流量,这些字段十之八九是长尾分布。

绝大多数样本挤在低值区域摩肩接踵,而极少数的样本却仿佛开启了传送门,径直飞到天际线以外。

你只盯着平均数观赏,上当受骗的概率极高。

一个班级里,四十九名学生每月生活费大约一千五百块钱,剩下一名学生每月生活费高达五万。平均值立刻被打扮得精神焕发,我和马云平均亿万富翁。

假若你拿这个平均值去描绘普通学生的日常生活,那基本等同于用校长办公室的装修预算去预测食堂二楼炒饭的价钱——牛头不对马嘴。

因此观看数值字段,至少需要巡视它的取值范围、分位数、长尾形态、零值占比、负值占比以及那些横空出世的异常跳跃点。

别只问它的平均值是多少。

还要追问它大部分时候出落成什么模样,绝少数时候又呈现出什么极端姿态,以及那些极端值究竟是一场错误输入,还是业务世界里真正重要的核心对象。

大宗客户可能是离群值,但同时也可能是价值命脉。

攻击流量可能是离群值,但说不定正是你最该全力捕获的目标。

传感器里骤然蹿升的高温可能是噪声,但也极可能是故障爆发前最后一次呼救。

“异常”这两个字,绝不能与“一删了之”画等号。

许多人一看见箱线图里弹出的离群点,便手起刀落,一个不留。数据表被清理得清爽宜人,模型也因此变得温驯平和,唯一可惜的是,业务价值也跟着一并被扫地出门。

这情景像极了打扫房间时,嫌保险柜太占地方,顺手扔了出去。

整洁确实是整洁了,但是保险柜里面的东西就直接没了。

类别型字段最忌讳表面光鲜

类别字段一眼望过去,比数值字段显得人畜无害得多。

男与女,省份与城市,设备类型,渠道来源,商品类目,风险等级。

来一手 value_counts,画一张柱状图,好像大功告成,万事俱备。

实际上,类别字段暗藏的坑一点也不比别人少。

首当其冲的是同义异写。

北京、北京市、BeiJing、beijing、BJ,指向的可能是同一个地方。

iOS、IOS、苹果、Apple,在业务语境下可能对应的是同一类设备。

Web、网页端、PC、浏览器访问,或许只是不同系统在不同年代留下的不同称呼而已。

紧随其后的是类别空间的急剧膨胀。

一个渠道字段,如果只有十几种来源,处理起来还算神清气爽。

假若有朝一日它膨胀成了几十万种推广链接、广告计划、短链参数和乱七八糟的追踪标识,这个字段便从有益的特征,摇身一变成了让人头疼的精神污染。

再往后还有新类别的难题。

训练数据中从未露过面的新城市、新商品、新设备、新活动,到了线上却是家常便饭。模型如果没有预先设计好对未知类别的兜底处理,就会在生产环境里当场表演选择性失忆。

类别数据需要被转换成模型可以训练的数值向量,因为模型天然无法直接消化字符串。

与此同时它还点明,类别特征自有一本难念的经,比如编码方式、类别含义以及类别组合之间千丝万缕的联系。

所以说,类别字段要端详的,远不止一共有几个类别这么简单。

还要看类别之间是否稳定,是否存在天然的层级,尾部类别是否稀稀拉拉,类别是否会源源不断地新增,是否需要适度归并,以及有没有为未知值预留兜底空间。

拿商品类目来说。

一级类目、二级类目、三级类目所蕴含的信息量天差地别。

你仅用一级类目,粒度恐怕粗放得像是拿渔网捞绣花针。

你直截了当地使用三级类目,尾部类目又会细碎到让模型无从学起。

模型并非不愿意下功夫,只是样本寥若晨星,它除了依靠猜测,实在别无他法。

再说城市。

北京、上海、深圳这类体量的城市,样本丰沛充足,模型学起规律来得心应手。某些小城市,样本数量屈指可数,单独为它们建立类别,恐怕价值寥寥。可你若把全部城市不分青红皂白地合并成一个“其他”,又有可能把真实的区域差异一股脑儿地抛弃。

这种时候,就需要结合业务进行层层分级,细针密缕地处理。

不要一提到类别处理,脑海里就只剩下 one hot 编码。

那只是编码方式而已。

真正不可忽视的,是类别背后隐藏的业务结构有没有被妥善地保留下来。

有一些关系,恰恰藏匿在类别的组合之中。

比如用户所在城市与商品价格带放在一起端详,也许比孤立地查看城市或者价格要更具洞见。工作日与访问时间段结合起来分析,或许比单纯看时间来得更立竿见影。设备类型与 App 版本相提并论,常常能解释很多莫名其妙的卡顿、闪退和转化差异。

Google 的课程把这种组合称为特征交叉,也就是将多个类别或分桶之后的特征组合在一起,用于捕捉它们之间的交互关系和非线性模式。课程也不忘敲响警钟,过度的组合会招致特征稀疏这一顽疾。

把这句话翻译成人话,那便是:组合特征确实思路巧妙,但请不要把所有字段都两两送入洞房。

字段太多,样本太少,最终特征空间就如宇宙般急剧膨胀,模型站在里面,两眼一抹黑。

业务还没变聪明。

内存却先拉响了防空警报。

分桶不是在偷懒,是让模型少遭罪

数值字段还有一桩常见的操作,叫作分桶

这个名词听上去不免有几分土气。

把年龄划分成几个区间,把价格切分成几个档位,把访问时长截成几段,把消费频次归为低中高。

很多人一听这套路,立刻皱起眉头:这难道不会让信息白白流失吗?

流失确实是流失了。

可有时候,信息量适当减少,模型反而学得更通透。

因为现实世界中有太多关系,本来就不是平滑连续的。

年龄从二十岁变成二十一岁,对许多任务而言几乎波澜不惊。

可从十七岁跨到十八岁,却可能直接牵涉到成年与未成年这一道法律分水岭。

价格从九十九元涨到一百元,用户的心理感知往往异常分明。

访问时长从一秒钟延长到五秒钟,很可能清一色是误触。直到超过三十秒,才开始隐隐透露出真实的兴趣信号。

Google 关于数值数据的课程里谈到,分桶会把数值的子区间转换成一个个桶,特别适合用来应对聚集分布、弱线性关系以及某些异常值场景。它也毫不避讳地告诫,桶的数量一旦过多,每个桶里的样本便会捉襟见肘,还会导致特征维度急剧攀升。

你不能见到数值就不假思索地分桶,也不能对一切数值都无动于衷。

分桶的真正价值,在于把业务世界的天然边界,明明白白地写进特征里面。

拿风控场景来说,逾期一日、逾期三十日、逾期九十日,这三者之间的含义判若云泥。

在医疗领域,某些指标一旦跨过临界值,意义便会发生猝然转折。

推荐系统里,用户停留时长超过某个意味深长的区间,才可能代表切实有效的兴趣。

在这类位置上,线性模型未必能够自然而然地习得。

你若借助分桶,把这种结构性讯息明明白白地递到它手上,它反倒能事半功倍。

这不是智力上的倒退。

这是在给模型递上一张绘制好的地形图。

当然,分桶也极易被滥用,一不留神就走向反面。

有些人一瞧见数值字段,不管三七二十一,操刀就开始切。切完之后,每一列都衍生出几十个桶,最终模型面对的是一面挂满稀疏特征的墙壁,就像面对一整墙没有贴标签的快递柜。

看得见。

但取不出。

因此,分桶之前,先要端详分布,先要琢磨业务上有关的阈值,先要掂量样本量的承受能力。

切莫为了分桶而分桶。

机器学习领域中,许多操作都有这种毛病。

原本是一件称手的工具,用着用着变成了盲目模仿的仪式。别人教程里这么做了,你也照单全收;别人模型里加上了,你也亦步亦趋。

最后代码越来越冗长,效果越来越扑朔迷离,解释起来越来越像街头算卦——听上去头头是道,实际全凭一张嘴。

缺失值也是一种信息

缺失值在数据里随处可见,已经稀松平常得像菜市场里的讨价还价。

许多教科书会殷殷告知:缺失值可以删除、可以用均值填充、可以用中位数填充、可以用众数填充,甚至可以训练一个模型去填充。

scikit-learn 的文档也实事求是地写道,真实数据常常夹杂着空白、NaN 或者种种占位符,如果直接丢弃整行或整列,会损失掉大量可能蕴含价值的数据,而 SimpleImputer 则可以凭借均值、中位数、最频繁值或者指定的常量进行填充。

这些方法论当然样样都对。

但真正站在数据面前时,第一句冲口而出的问题,不应该纠结于“怎么填”。

第一句应该是刨根问底为什么缺。

这比填什么要紧要一百倍。

用户年龄缺失,很可能是用户自己不愿意填写。

收入信息缺失,大概是用户认为触碰了隐私红线。

设备传感器上报缺失,兴许是设备本身已经出现了故障。

交易地理位置一片空白,可能是权限被关闭了。

客服记录杳无音讯,可能是用户确实没有投诉,也可能是两个系统之间根本没有打通数据。

同样是空荡荡的值,背后的含义却判若鸿沟。

有些缺失,代表该项事实“根本不存在”。

有些缺失,代表“当时没有采集”。

有些缺失,代表“采集了但是失败了”。

有些缺失,代表“用户主动遮掩”。

还有些缺失,代表“业务流程压根没有走到那一步”。

倘若不分青红皂白,统统用均值往里填塞,就好比公司里所有没填绩效自评的人,系统自动替他们洋洋洒洒地写上一句“表现平稳,无突出贡献也无明显过失”。表面上看起来一碗水端平,实际上能把人事部门和员工本人一起沉默到无语凝噎。

缺失这件事本身,有时恰恰是非常珍贵的特征。

比如在信用申请里,某些信息刻意留白,很可能与风险隐隐相关。医疗数据中,某些检查没有被安排,可能意味着医生判断没有必要性,也可能映射出医疗资源遥不可及。推荐系统里,用户从来没有点击过某一类内容,可能是因为毫无兴趣,也可能是因为系统根本就没有把它曝光在用户眼前。

这就要求我们,为缺失值仔仔细细地画一幅画像。

哪一列缺得分外触目惊心。

缺失是否在某一类用户身上扎堆出现。

缺失是否伴随着时间推移而悄无声息地改变。

缺失与目标标签之间,是否藏着暗通款曲的关联。

缺失是否齐刷刷地来自同一个渠道、同一个版本、同一片地区、同一套采集系统。

很多时候,端详缺失的分布模式,比端详完整数据本身还要富于启发性。

因为缺失模式,会毫不留情地暴露系统的隐性断点。

比方说,某个 App 版本发布之后,某一个字段的缺失率突然如脱缰野马般蹿升。先不用急着去调试模型,应当先去问一问埋点是不是被改动了。

再比如,某个渠道的用户,其收入字段大面积留白,恐怕不是这批用户群体有什么特殊癖好,而是渠道的落地页面里,压根儿就没有设计这个表单。

很多模型问题,表面上看是算法在退化。

往深处刨一刨,常常是数据管道在哪个不起眼的角落悄悄漏了风。

样本不平衡会把评估分数变成一出荒诞的喜剧

分类任务当中,样本不平衡是一个老生常谈却又屡屡绊倒人的问题。

欺诈检测里,真正欺诈的样本寥寥无几。

疾病筛查里,阳性样本或许少得像沙漠里的绿洲。

网络攻击检测中,攻击流量相比正常流量,可能微小得不值一提。

内容审核场景之下,高风险内容也往往只是浩瀚数据海洋中极小的一撮泡沫。

这类任务,如果只拿准确率这一把尺子去衡量,极其容易上演让人啼笑皆非的喜剧。

Google 的分类指标课程说得一针见血:在严重失衡的数据里,假如正类只占百分之一,模型哪怕把头一缩,一股脑儿把所有样本都预测为负类,也能堂而皇之地拿到百分之九十九的准确率,但这样一个模型,在业务上简直形同虚设,毫无半点实际价值。

这便是准确率最经典的障眼法。

你费尽心力做出一个欺诈检测模型,准确率高达百分之九十九。

老板一听,双目放光。

安全团队的同事一看仪表盘,血压瞬间拉满。

因为这个模型极有可能只是学会了把每一笔交易都轻飘飘地判定为正常。

什么都不拦截,当然在绝大多数时候都能蒙混过关。这就像小区的保安,从来不对任何人进行盘查,业主投诉是少了,通行效率是高了,报表也确实赏心悦目了。

等到真的出了大事,大家才幡然醒悟,这套系统的核心能力叫做“满脸堆笑,一律放行”。

因此,审视数据时,一定要把标签分布看得清清楚楚。

正负样本各自比例究竟是多少。

少数类到底拥有多少实实在在的样本。

每一个时间段里,是否都有少数类的影子。

训练集与测试集里的类别比例,是否保持着一致。

某些类别,是不是仅仅在训练集里露过脸,却在测试集里销声匿迹了。

某些类别在测试集里若隐若现,数目微小到令评估结果如风中烛火般飘忽不定。

评价指标也要跟着改变思路。

准确率可以一瞥而过,但绝不能奉为唯一的圭臬。

召回率关心的是,在真实的正类当中,究竟被你成功捕获了多少。精确率关心的是,模型高声断定为正类的样本当中,到底有多少确实是真材实料。

指标的选择取决于具体的任务需求、分属不同类别的错误代价,以及数据本身是否平衡,并特意指出,在不平衡数据或者某一类错误代价高得惊人的场景里,必须抬头看一看向准确率之外的其他指标。

这就牵扯出另一个东西。

模型追逐的,从来不是抽象的高分数。

模型是在替业务承担真实的代价。

欺诈检测漏掉一笔大额盗刷,损失可能让人心惊肉跳。

内容审核误杀一篇正常内容,用户体验就会打折扣。

医疗筛查遗漏一例阳性,风险之重不言自明。

推荐系统推送了一条风马牛不相及的内容,用户或许只是指尖一划而过。

不同业务的错误成本判若云泥,指标的选择就不可能一刀切。

太多时候,模型的分数不过是台前那位字正腔圆的主持人。

真正在幕后一锤定音的,是业务可以为错误承受的代价。

相关性不是因果

端详数据时,相关性分析是一项出场率极高的活儿。

某个字段与标签之间相关性高得耀眼,众人便兴奋不已。

某个特征的重要性排名位列榜首,大家就开始据此长篇大论地写结论。

然而,相关性是一个极易让人头脑发热的东西。

它能告诉你有两个变量在常常相伴而行,却无法直接告诉你究竟是谁牵动了谁,谁才是一切的始作俑者。

冰淇淋的销量和溺水事故,通常都会在夏日里同步攀升。你不能据此得出结论,冰淇淋是溺水事故的元凶。

网站的访问量同订单量一道节节拔高,可能是营销活动在背后推波助澜,也可能单纯是节假日带来的消费惯性,还可能是统计口径悄悄发生了改变。

模型极其擅长利用相关性,在三长两短的数据中牵线搭桥。

业务方却容易顺水推舟,把相关性滔滔不绝地讲述成因果。

PPT 最乐于把相关性精心包装成石破天惊的洞察。

这三样东西凑到一起,就很容易炮制出一批看似专业、实则危险重重的结论。

比如,模型发现某一个地区的违约率格外刺目。

这可能与当地的经济结构有着千丝万缕的联系,也可能仅仅是历史样本选择产生的偏差,还可能和渠道的采集质量脱不开干系,甚至可能只是某段时间里,业务策略集中性地投向了那一带。

你不能看到特征重要性高高在上,就拍着桌子宣布,这个地区天生就属于高风险。

模型从来不为伦理负责,也不承担解释的义务。

它只负责把数据里的模式打捞上来给你看看。

至于这个模式到底合不合理,能不能放进决策链条,会不会悄无声息地滋生偏见,全然需要人来慎之又慎地判断。

这也是为什么看数据不能只盯着统计图表,还要去打量采集方式、业务流程和使用后果。

数据分析领域最叫人头疼的一种人莫过于:图画得美轮美奂,结论下得斩钉截铁,可等到业务方追着问了三句,他便马上搬出那句万能逃生台词——“这个问题我们后续还需要进一步深入研究。”

话当然不能算错。

但如果每次都靠这句话化险为夷,那就不是做数据分析。

数据漂移不过是日常保养

上一篇已经絮叨过,模型上线以后,世界这台机器并不停转,它会一刻不停地变化。

这里可以再往下深挖一锹。

许多人对数据漂移的理解,还停留在大惊小怪的“重大事件”层面。

譬如疫情突然来袭,政策一夜转向,市场发生剧烈震荡,平台大张旗鼓地改版,攻击方式骤然升级。

这些当然会劈头盖脸地造成漂移。

但更多时候,漂移走得静悄悄,不带一丝硝烟味。

用户年龄结构日复一日地缓缓老去。

新增渠道带来了一批性情迥异的新用户。

某个推荐入口的位置被不经意地调动了。

埋点 SDK 升级之后,字段的分布无声无息地改变了模样。

运营活动一茬接一茬地重塑了用户行为。

竞品的价格微调,影响了原本牢不可破的购买决策。

这些变化,单独拎出来看都不至于天翻地覆,可涓涓细流汇聚在一起,就足够让模型像偏离航道的船只,在不知不觉中驶向一片陌生的海域。

Google Cloud 的 Vertex AI 文档中,将训练‑服务偏差和推理漂移双双列为模型监控的靶心,前者关注生产环境中的特征分布与训练数据之间的偏离,后者则紧盯着生产数据分布随着时间推移所发生的演变。

这揭示了一个不可回避的现实问题。

看数据,绝不能是一场仅限于训练之前的突击检查。

上线之后,仍然需要睁大眼睛,持续地看。

训练前看数据,是为了让模型不要一出生就百病缠身。

上线后看数据,是为了弄清楚模型有没有在真实世界的磨砺中悄然走上了歧途。

如果一个模型上线之后,没有严密监控其输入分布、输出分布、关键业务指标、异常样本的聚集以及来自用户的反馈质量,那么它更像一个被放归山野的实习生。

一开始还挺听话,照着规矩办事。

等过了几个月再回来看,它已经学会了用种种匪夷所思的方式完成 KPI。

比如推荐模型眼睛里只盯着点击率,渐渐地就会滑向更加耸人听闻、更加标题党的内容。

风控模型一心只想压低坏账,也许就会把大批清白无辜的正常用户冷冷地挡在门外。

客服分流模型只执着于自动解决率,便可能把复杂沉重的难题反复踢给无助的机器人,让用户体验陷入永无尽头的循环地狱。

数据漂移,往往只是浮在水面上的表象。

目标漂移、业务漂移、用户漂移、系统漂移,这些更深层的移位,都会通过数据这个窗口,若隐若现地透出形迹。

因此,会看数据的人,不能只满足于在训练前画几幅漂亮的图。

还要能在上线后,死死盯住趋势。

看分布有没有发生不易察觉的位移。

看指标有没有出现悬崖式跌落。

看异常样本有没有在某一个时间角落里暗暗堆积。

看用户反馈有没有悄悄转向了另一个方向。

看模型输出是不是越来越缩手缩脚,越来越保守,或者反过来,越来越激进,像一匹脱缰的野马。

模型,绝不是发完版本就尘埃落定的功能模块。

它更像一台嗡嗡运转的机器。

有噪声,有磨损,有误差,有不可抗拒的老化。

你不能把它往那一搁,就天真地指望它永远维持青春期时的巅峰状态。

看数据要带着一肚子问号

说到底,看数据不是为了把全部图形都一个不落地画一遍。

也不是为了把 notebook 折腾得像一份装帧精美的体检报告。

真正有效的看数据,必须揣着一肚子的问题走进去。

这份数据能不能稳稳地支撑既定的任务。

标签的定义是不是铁板一块,经不经得起时间推敲。

特征到了预测的那一刻,还能不能如数拿到手中。

样本有没有覆盖住未来的真实场景。

训练集与测试集的划分,有没有切切实实地模拟出将来的使用方式。

类别空间未来会不会像吹气球一样膨胀。

缺失值里有没有藏着业务逻辑的难言之隐。

异常值究竟代表错误,还是代表至关重要的对象。

评估指标有没有真实折射出业务要付出的代价。

上线以后,还能不能持续不断地拿到同一口径、同一品质的数据。

这些问题,比“模型该选哪一个”来得更早,也更性命攸关。

很多初学者按捺不住地觉得,看数据太慢了,慢得让人心焦。

可真正慢的,往往是跳过了看数据这一关之后,不得不再掉转头去补救的那些冤枉路。

前期不追问字段含义,后期就会发现特征根本不可用。

前期不核查标签口径,后期就会发现模型学得歪歪扭扭。

前期不留意时间切分方式,后期就会发现评估结果虚高得像空中楼阁。

前期不管缺失模式,后期就会发觉线上近一半的请求缺失关键字段。

前期不搭建一个朴素的基线,后期所有复杂模型的提升都变得毫无参照,不知道究竟强在哪里。

这就像装修之前不先仔细丈量房屋,便兴冲冲地去购置家具。

买的时候满心欢喜,安装的时候精彩纷呈,退货的时候才开始参透人生的曲折。

机器学习项目,何尝不是同一个道理。

早一些看透数据,便早一些发现陷阱,早一些摆正方向。

看晚了,模型便会毫不犹豫地带着你,一起偿还这笔滚雪球般的连环债。

初学者可以从一套固定拳法练起

如果刚刚踏入机器学习的大门,大可不必把看数据想象成玄而又玄的内功心法。

倒不如先养成一套固定的拳路,按部就班地演练起来。

第一步,追本溯源看数据来路

是谁采集的,在什么时候采集的,经由哪一套系统采集,字段中途有没有经历过改版,样本是不是经历过某种有意无意的筛选过滤。

第二步,细读字段说明书

每一个字段代表什么含义,使用什么单位,取值范围大致如何,是否可能存在空值,到了预测环节是否确凿可以拿到手。

第三步,审视目标标签

标签是怎样定义的,由谁来标注的,标注标准是否始终保持一致,正负样本比例是否悬殊,标签是否具有滞后性,标签里有没有混入来自未来的信息。

第四步,浏览基本统计量

行数、列数、缺失率、重复率、唯一值数目、最大值、最小值、分位数、类别频率、时间跨度。这些看似平淡的数字,常常能一把揪住最明显的暗病。

第五步,观察分布与关联

数值字段借助直方图、箱线图去感受长尾形态和突兀的异常点。类别字段细看头部类别与尾部类别,并推敲未来可能新增的类别。特征与标签之间的关联也可以悄悄打量一番,但千万要把嘴边那句轻率的因果关系咽回去。

第六步,审慎确定划分策略

随机划分是否足够合理。时间序列任务能不能按时间切分。围绕用户的任务能不能按用户切分。围绕设备的任务能不能按设备切分。涉及地区泛化的任务,不妨考虑按地区独立切分。

第七步,建立一个朴素至极的基线方案

先用清晰的数据、简单的特征、基础的模型跑通整个流程,为后续一切实验提供一个可以放心比较的参照系。没有参照,复杂模型的提升就很容易变成一场自我陶醉的独角戏。

这些动作听起来毫无惊世骇俗之处。

然而它们足够救人性命。

真正上手做项目的时候,许多惊天动地的大问题,恰恰就潜伏在这些最基础的普查动作里。

你用一个微不足道的统计量,发现某一列竟然是滴水不进的常数,这比你在神经网络里苦调半天要立竿见影。

你发现测试集和训练集里存在重复样本,这比更换十个模型更为釜底抽薪。

你查出某一个亮眼的强特征在预测时根本获取不到,这比你继续头脑发热地堆叠特征重要一百倍。

很多时候,力挽狂澜的,并不是一个更加尖端复杂的模型。而是更早一步,发现了数据里到底哪里不对劲。

写在最后

学习机器学习,很容易滋生一种虚妄的错觉,仿佛越靠近模型结构的核心,就越靠近技术的至高殿堂。

于是人们争相追逐算法,追逐框架,追逐前沿论文,追逐不断更迭的排行榜。今天钻研 Transformer,明天追捧扩散模型,后天又被智能体工作流搅得心潮澎湃。

看起来一路高歌猛进,实际上,连自己手里那份训练数据究竟是何方神圣,都还没来得及看清。

这就像一个人对赛车空气动力学研究得头头是道,唾沫横飞,结果上车之前,竟然没有察觉轮胎早已瘪得贴了地。

机器学习,从来不是从模型开始起跑的。

它从数据起步,从字段含义起步,从标签定义起步,从业务问题起步,从一次足够沉静的认真观察起步。

看数据这件事,没有什么发布会般的聚光灯效果,也很难截图四处炫耀。它没有大模型那股子锣鼓喧天的热闹,没有新算法那般摄人心魄的性感,更没有调参曲线那种坐过山车般的刺激。可恰恰是它,决定了后面的模型到底是在诚诚恳恳地学习规律,还是在糊里糊涂地继承混乱。

数据看不明白,模型越强大,问题就越会被成倍地放大。

数据观看得越透彻,模型才越有机会成长为一件趁手的工具,而不是一台自动制造幻觉的分数印刷机。

因此,在继续深入研习算法之前,请先反复锤炼自己的数据直觉。

看到一个字段,先问一声:你从哪里来,要往哪里去。

看到一个标签,先问一句:你是如何被定义出来的,那些边界又在哪里。

看到一个高分,先问一遭:你有没有在哪个环节,偷看过本不该看到的答案。

看到一个异常值,先分辨清楚:你是一场低级错误,还是一次尖锐的信号。

看到一张干净得毫无瑕疵的数据表,先在心里暗暗生出一丝警觉。

因为真实世界,很少会主动把自己收拾得一尘不染。

它通常只是把那些棘手的不堪,暗暗地藏进了更深的地方。

4 个帖子 - 2 位参与者

阅读完整话题

来源: LinuxDo 最新话题查看原文