
数据预处理这个活做好了没人夸做砸了全组陪你加班。我在大数据这行干了十多年见过太多项目死在预处理阶段不是模型不够先进不是集群算力不够而是喂进去的数据压根就是脏的、偏的、口径乱的。这篇文章不聊那些教科书上人云亦云的定义我把这么多年在实际项目里沉淀下来的数据预处理技术要点、踩坑经历、排查思路全部摊开来讲希望能帮你少走几年弯路。1. 先决定做不做这件事数据采样与数据裁剪很多刚入行的朋友有个执念既然是“大数据”那必须全量处理采样就是偷懒。但这个想法在大数据场景下往往是有问题的。全量处理意味着全量存储、全量计算、全量传输当你的数据量到了PB级哪怕跑一遍简单的过滤也要耗费大量集群资源。我见过一个模拟项目明明只需要做趋势分析非要把三年的全量点击流日志每天都灌进特征库结果集群排队时间比实际计算时间还长。所以数据预处理的第一步不是“怎么处理”而是“有没有必要处理这么多”。1.1 采样策略数据形态决定采样方式采样不是随机抽几行那么简单关键要看数据形态。如果你的数据是用户行为日志时间序列特征很强那就不能纯随机抽否则会把连续的行为链切断后续做会话识别时全是碎片。这种情况下需要按会话或按用户ID进行整段采样保证抽出来的每条记录在时间轴上都是完整的。如果是做模型训练分类问题要注意正负样本比例。直接随机采样往往会得到极度不平衡的数据负样本占99.9%正样本只有可怜的几条这种采样结果拿去训练模型直接学成一个“永远预测负样本”的傻瓜分类器。我常用的做法是分层采样先按标签分层每层内部再随机抽最后按比例合并。1.2 抽样陷阱随机不是万能药随机采样听起来很安全但在某些场景下会出大问题。比如你要做异常检测异常本来就是小概率事件随机采样很可能把仅有的几十条异常样本全部漏掉采样后的数据集里异常率为零模型训练直接失去意义。这种场景不能依赖随机采样得用有偏采样或者直接对异常样本做全量保留。还有一种情况是时间序列的周期性。某跨平台系统的数据有明显的节假日效应如果你在非节假日随机采样做出来的模型到了节假日上线必然失灵。我通常会在采样时保留完整的时间周期比如至少包含两个完整的周一至周日遇到促销季或特殊事件周期还要单独把这段时间的数据全量拿出来不能裁掉。1.3 采样后的粒度还原采样会带来一个隐蔽问题统计口径变了。全量数据下的均值、总量、比例在采样数据下需要做还原。比如你从100亿条日志里抽了1亿条做分析算出来的用户数、点击量都是缩水的必须乘以采样比例的倒数做放大。但如果你的采样是按用户整段抽的那用户总数不用还原人均行为次数则需要校正。很多分析报告数据对不上就是栽在这个还原环节上。提示做任何采样操作之前先在原始数据上跑几个核心指标总量、去重数、均值采样后再跑一遍同样的指标做对比。如果偏差超过5%说明采样方案有问题不要急着往下走。2. 数据质量检测既要查“脏”也要查“偏”很多人在数据预处理时只会做清洗把空值填掉、把格式统一就以为完事了。但实际上数据质量检测的价值远不止于此。脏数据指的是格式错误、乱码、缺失这类问题而偏数据指的是数据分布不合理、口径不一致、时效性过期这类更难发现的问题。脏数据好查偏数据难防。2.1 脏数据的三大来源大数据场景下脏数据的来源无非三种采集端异常、传输链路问题、业务系统本身就是混乱的。采集端出问题最常见的是埋点缺失。某次前端代码上线时漏了一个参数导致一周内的用户设备类型字段全部为空。这种脏数据往往不是零星的而是成片出现的排查看上去像是一个时间段内的系统性缺失。传输链路导致的脏数据我印象很深某次消息队列积压严重消费端处理不过来出现了数据乱序时间字段完全错乱了明明应该按时间递增的日志出现了大量“未来时间”和“过去时间”穿插的记录。业务系统的问题就更复杂了。同一个枚举字段有的接口返回1和0有的接口返回true和false甚至有的返回“是”和“否”。这些到了数据仓库里全是坑不整理根本没法用。2.2 不要只看空值率要看分布空值率是大家最常用的质量指标但光看空值率远远不够。某个字段空值率只有1%但如果这些空值全部集中在某一个特定渠道或特定时间段那这个字段在分析该渠道或该时段的数据时就已经不可用了。所以检测要按维度拆开看按日期看、按渠道看、按业务线看。还有一种偏是时间偏移。比如你用某天的数据做实时推荐特征但这个字段实际更新延迟了72小时那这个特征就是“过去的数据”模型推送的内容必然过时。检测这种问题需要校验数据新鲜度比较数据中的最大时间戳和当前时间的差值如果差值超过阈值就要告警。字段口径不一致是最隐蔽的质量问题。A同学在某个项目里把“活跃用户”定义为“当天有登录行为的用户”B同学在另一个项目里把“活跃用户”定义为“当天有购买行为的用户”。两边的数据合并在一起做分析出来的结论能对吗所以数据质量检测归根结底查的是“定义是否统一”这需要数据字典和完善的元数据管理靠脚本查不出来。2.3 一个可行的质检清单我在实际项目中习惯沉淀一套自动化质检规则每次数据接入后自动跑一遍大致包括以下内容检测项检测方法判定标准完整性空值率统计、必填字段校验核心字段空值率不超过1%成片缺失直接阻断唯一性主键去重计数比对重复率超过阈值则告警可能是重复上报时效性MAX(时间戳)与当前时间对比延迟超过设定阈值则告警数据不可用一致性枚举值分布、同字段多源对比出现未知枚举值或两源结果偏差超过5%则排查准确性抽样人工核对、与业务报表交叉验证不一致必须追溯不能直接放行这套清单不一定适合所有场景但对于大多数数据仓库接入来说是个不错的起步框架。3. 数据清洗的常规操作与非常规手段清洗是最“体力活”的部分但体力活里面也藏着很多讲究。直接填充空值、删除异常值、统一格式这三板斧谁都会但具体怎么填、怎么删、怎么统一背后的逻辑直接决定后面分析建模的质量。3.1 缺失值处理不要无脑填平均值缺失值处理的第一原则是先搞清楚“为什么缺失”。如果是因为用户没有这个属性比如未婚人士的配偶姓名字段为空那空值本身就是信息不应该被填充。如果是因为采集故障导致的缺失那才需要考虑用其他值补上。填平均值是最常见的方案但也是最容易出问题的。假设你要分析不同收入群体的消费行为而收入字段有5%的缺失你直接填全体平均值结果就是把高收入人群的缺失项全部拉低、低收入人群的缺失项全部拉高硬生生制造了一批“不存在的中产”。这种情况我会用分组填充先按城市级别、职业类型分组用组内平均值填充比全局平均值更接近真实。如果能拿到历史数据用上一个周期的数值填充往往效果更好。对时间序列数据插值法是比较常用的方案。线性插值、拉格朗日插值都能处理连续缺失但要记住一个边界如果你的数据缺失段太长插值就是虚构数据。连续缺失超过总长度10%的字段我的建议是直接放弃这个特征不要硬造。还有一类高价值字段缺失不需要填充而是加一个标志位。比如“是否欠款”字段缺失了你既不知道是没欠款还是数据没采集到那就把缺失转成一个新的枚举值“未知”。这样模型能学到“未知”本身的含义比硬填0或1要稳得多。3.2 噪音数据的识别与处理3σ和IQR不是万能的噪音数据异常值是清洗环节的重头戏。课本上最常见的3σ原则——超出均值加减三倍标准差视为异常这个方法在正态分布的数据上效果不错但遇到长尾分布就失灵了。互联网数据几乎全是长尾分布点击量、下单金额、访问时长这些指标都是少数人贡献大部分数值的形态用3σ会把大量正常的“头部用户”误杀。更稳的方案是分位数法IQR。用四分位距识别异常把数据按升序排列取Q125%分位和Q375%分位IQRQ3-Q1低于Q1-1.5×IQR或高于Q31.5×IQR的点视为异常。这个方法不要求正态分布对长尾数据更友好。但真正碰到业务上的强异常时统计方法只是辅助。比如某天某个商品的销量突然暴涨100倍统计上它绝对是异常值但业务上这可能是活动促销的真实结果。这种数据不能直接删掉删除就是抹掉了业务真相。我遇到这种情况会先打标、再隔离而不是直接清洗掉。等业务确认完再决定是保留还是修正。聚类方法也可以用来识别异常值比如DBSCAN它能把密度低的孤立点识别出来不需要预设数据分布形态。在大数据量场景下可以先对数据做一次采样在采样集上训练聚类模型再在全量数据上打分标记这样能省不少计算资源。3.3 格式统一的细节别小看一个时区格式统一里最烦人的不是手机号、邮箱、日期这类常见字段而是时区。某跨平台系统的数据分别从三个国家采集日志里记录的时间有的带时区标识有的是UTC还有的直接用服务器本地时间。如果不在清洗阶段统一换算成UTC存储等到做时间序列分析时你会发现午夜0点的数据会诡异地分成两半。日期格式也是重灾区。同一个日期字段有的系统存的是“2024-01-15”有的是“2024/1/15”还有的是时间戳。做数据接入时一定要有一套标准的日期解析库统一转成标准格式再入库。另外字符串里隐藏的不可见字符、全角半角混用也常让join时明明看起来一样的数据匹配不上这种情况需要通过字符编码检测工具处理。4. 数据集成与去重多源数据的“同人不同号”难题数据预处理有个环节是集成把多个业务系统的数据合并到一起。听起来很简单union一下就好但真正做起来到处是坑。多源数据最大的问题是实体对齐即“同一个用户在不同系统里的ID不一样”。这个问题的技术含量不低是数据预处理里最需要动脑的部分之一。4.1 字段命名冲突只是第一关先处理最简单的字段命名冲突。订单系统里用户的字段叫user_id会员系统里同一个含义的字段叫uid内容系统里叫member_id。集成时必须做字段映射。这个环节看似机械但容易出错我见过有项目因为把“user_id”和“uid”直接按位置合并结果两个不同用户的记录被拼到一起后面所有分析全乱套。字段映射要有明确的映射表和类型转换规则。一个稳健的做法是建一个数据接入层的中间模型定义标准字段名和标准类型所有上游数据都要转换成这个标准模型才能进入下游。这样就不会出现“同一个概念在不同表里叫不同名字”的问题。4.2 ID-Mapping核心技术点ID-Mapping要解决的核心问题是手机号、微信号、设备ID、CookieID、邮箱这些都是同一个人的不同标识怎么把它们关联到同一个人身上这个技术点直接决定用户画像的准确性。常规做法是建设ID-Mapping关系图。每条数据进来先提取所有能标识用户的ID然后查这张关系图如果这些ID中的任何一个已存在于图中就把这批ID全部归到该用户ID下如果全部不在就新建一个用户ID。听起来简单但几个关键细节要注意多个ID之间的关联权重不同。设备ID和CookieID的关联强度远不如手机号和身份证号的关联强度强关联才值得直接合并弱关联合并了容易出“串号”问题。有些ID是共享的比如家庭WiFi下的设备ID如果强行归到一个用户一家三口就被合并成“一个人”了所以共享型ID只能作为辅助维度不能做唯一身份标识。ID关系图要用支持高并发查询的存储比如HBase或者图数据库否则每天几亿条增量进来关联查询会直接拖垮入库速度。4.3 去重看似简单实则要分场景去重也是一个极具迷惑性的简单操作。最容易的是完全去重多字段完全相同就保留一条用Hive里的ROW_NUMBER()窗口函数就好。但更多时候是部分去重同一用户在同一天内重复点击了100次“购买”按钮要做的去重逻辑是保留一次真实的购买记录而不是简单地去重掉99条。部分去重最稳妥的方案是先定义“一条合法记录”的业务口径什么情况下算新记录、什么情况下算重复记录分别以什么字段作为判断依据。定义清楚之后再用窗口函数按用户ID和业务主键排序去重。另外一个大数据场景下的去重优化思路不要在全量数据上做全局去重而是先按天分区去重再做跨周期去重。日去重只处理当天数据的重复问题跨周期去重只处理历史累积数据与新到数据的冲突问题这样计算量能大幅下降效果也不会打折扣。5. 数据变换与特征工程从原始数据到可用特征的最后一公里清洗完的数据仍然不适合直接喂养模型必须经过变换。这一节是预处理的技术核心也是最容易和建模环节脱节的地方特别考验对业务和数据形态的把握。5.1 类型推断不要被“显式声明”骗了数据仓库里表的字段类型往往是建表时人为声明的。声明成string的字段可能是数值型数据声明成int的字段可能真实取值范围远超int上限。我在某模拟项目中就见过类似的情况某个金额字段因为历史原因被定义为string结果后面要做聚合统计时所有金额都被当成了字符串拼接导致统计结果完全偏差。正确的做法是在做数据接入时用框架自动做类型探测例如用Spark的spark.read加载时让推断器自动识别字段类型。对于已存在的表需要做一步“类型校准”抽取样本数据看实际值的分布范围是否匹配声明类型不匹配的要做隐式转换。这里特别要注意溢出问题一个long型字段存了超过int范围的值如果强行转int数据直接溢出变成负数或错误值。5.2 编码与归一化什么时候用、什么时候别用对于机器学习模型来说类别型特征需要编码。最常见的独热编码如果类别数量少几十个以内且没有明显的序关系直接用就好。但如果类别数量达到几千甚至几万个独热编码会让特征矩阵稀疏到爆炸内存根本扛不住这种情况改用哈希编码或Embedding更现实。数值型特征要不要归一化取决于模型类型。树模型对量纲不敏感特征范围再大也不影响分裂点选择但线性模型和神经网络模型对量纲敏感两个特征一个取值范围是0-1另一个是0-100000模型训练时梯度会被大数特征主导收敛极其困难。常用的归一化方法有Min-Max缩放和Z-score标准化。Min-Max容易受极端值影响如果数据里有较大噪音我更推荐用Z-score它能把数据变成均值0、方差1的形态对后续算法更友好。注意归一化是在训练集上拟合参数、再应用到验证集和测试集不能在全体数据上统一做归一化。否则会把测试集的信息泄露到训练过程中导致模型评估结果虚高。5.3 日期与时间变换特征设计的富矿时间字段直接拿来用效果有限需要拆解成更精细的特征。我常做的拆解包括年、月、日、星期几、是否是周末、小时、是否是节假日、距离最近节假日的天数。有时候还会做一个“业务周期内的时间位置”特征比如“本月第几天”“本周第几天”这些特征对周期性业务特别有效。时区问题在这里会再次出现。如果上游数据用了不同的时区记录时间在特征计算前必须统一成同一个参照时区否则“星期几”这种特征都会错位。另外在跨时区业务中“用户本地时间”和“系统标准时间”要分别保留因为很多业务规律的周期性是跟着用户作息走的不是跟着系统时间走的。5.4 UDF的幂等性与确定性大数据平台上的预处理往往通过UDF用户自定义函数实现。这里的核心要求是UDF必须是确定性的。同一输入在任何时间、任何节点上运行输出必须完全一致。我在造数据管道时遇到过一个问题某个UDF里依赖了系统当前时间导致同一条数据在重跑时被算进不同的时间窗口中。这类问题会直接影响数据的可重跑性管道的产出结果不一致下游所有分析都得跟着遭殃。所以写UDF时所有对外部环境的依赖时间、随机数、全局状态都必须显式作为参数传入不能藏在函数内部闭包或全局变量里。这样才能保证同样输入产出同样输出数据管道才能安全重放。6. 数据倾斜与并行效率预处理跑不动多半是这出了问题大数据预处理和单机数据处理最大的不同在于它跑在分布式集群上。分布式框架的理想状态是“每人领一块数据各干各的互不干扰”。但现实中经常出现这样的情况99%的节点已经跑完了就卡在最后1%的节点上死活跑不动拖得整个任务超时。这不是集群不行而是数据倾斜。6.1 倾斜的三大常见场景join操作中的热点key。比如用户表按城市join北京上海这种超大城市的用户量是其他城市的几十倍负责这些key的reduce节点就会被压垮。groupBy操作中的特殊分组。比如按渠道分组统计某个头部渠道的数据量比其他渠道大两个数量级。count distinct操作。这个操作在很多分布式框架里都容易产生严重的数据倾斜因为所有key的distinct值都要集中到一个节点去重。6.2 常规解法与进阶思路最常用的解法是加盐salting。对热点key做拆分把一个大key拆成N个加盐后缀的子key分散到N个节点计算最后再汇总。比如key为“北京”的数据拆成“北京_0”到“北京_99”这100个子key10个节点每个处理10个子key肯定比1个节点处理全部要快得多。这个方法简单有效但要注意N不能太大否则会产生大量小文件。另一个常见思路是广播join。如果小表足够小比如几MB级别可以直接广播到每个节点在map端完成join彻底绕过shuffle。这一步能极大提升效率。但前提是小表必须真的小否则广播本身也是灾难。还有一招是改写法。有些倾斜是由SQL本身的写法导致的先join再聚合改成先聚合缩窄数据量再join倾斜情况就能缓解。比如先按用户维度把点击量聚合好再拿聚合表和用户维表join计算量会小很多。6.3 倾斜不是唯一的性能瓶颈预处理跑得慢除了数据倾斜还要检查分区策略。常见的分区方式有日分区、哈希分区、范围分区。日分区适合按时间筛选的查询哈希分区能让数据比较均匀地散列到各节点范围分区则适合经常做范围扫描的场景。选错分区策略即使不倾斜查询效率也会差很多。文件格式和压缩格式也是性能关键。在大数据集群上行式存储的普通文本文件如果数据量很大读盘就占满了IO。换成列式存储如ORC或Parquet再结合压缩如Snappy或ZSTD无论是存储成本还是读取效率都会有明显提升。我的习惯是数据仓库内的明细层用列式存储加压缩交互式查询只读取需要的列速度能快出好几倍。压缩格式的选择也需要平衡——ZSTD压缩率高但解压速度稍逊于Snappy如果后续有频繁读取的场景用Snappy可能综合体验更好如果存储成本压力大用ZSTD更划算。6.4 预处理的流水线血缘与可重跑性预处理不是跑一次就结束了而是每天、每小时的例行公事。一旦调度起来有两个东西必须要维护好。第一是数据血缘。也就是每张表、每个字段是从哪来的、经过什么步骤变成现在的样子的。出了数据质量问题要能顺着血缘快速追踪到源头。血缘关系可以通过元数据系统记录规范的做法是每次调度任务启动时自动记录上游表名、下游表名、SQL脚本版本号。第二是可重跑性。数据管道要做到今天跑挂了修复之后可以安全地从断点重跑不产生重复数据不污染下游。这需要每个任务具备幂等性先清空目标分区的数据再重新写入新数据。我见过不少项目省略了清空这一步结果某天任务失败重跑后目标表里出现了双倍数据整个下游直接崩掉。清空再写入这看起来是多此一举其实是数据管道安全运行的护身符。7. 缓存、增量和Checkpoint大数据预处理的工程化细节很多人只关注清洗逻辑不关注工程实现最终导致一个能跑但完全跑不动的管道。这一节聊聊工程化的三个关键点缓存策略、增量处理和断点续跑。7.1 缓存策略重复计算是最大的浪费在Spark或者Flink这类框架里如果一份中间结果要被多个下游复用一定要在内存中缓存避免每个下游都重新计算一遍这份数据。Spark里调用cache()或persist()即可关键变量用persist(StorageLevel.MEMORY_AND_DISK)有备无患。但缓存也分场景。如果一份数据只有单个下游使用缓存纯属浪费内存不如直接透传。另外缓存是有时效性的如果一个预处理任务要依赖前一天的中间结果而这个中间结果当天已经被新的数据覆盖了必须重新计算缓存就没有意义。我在项目里踩过这种时间的坑换了缓存策略才恢复正常。7.2 增量处理全量重跑是“懒人的陷阱”做过一段时间预处理的人都会发现全量重跑最省脑子——每天把过去三年的数据全部重新算一遍逻辑简单结果一致。但当数据量到达一定规模后全量重跑的计算成本会高到不可接受比如每天跑一次三年的全量聚合白天上线的任务到第二天早上还没跑完那这条管道就没有实时性可言了。增量处理的核心思路是只处理自上次处理以来新到的数据然后结合上一个周期的结果更新出本周期结果。这样做能大幅减少计算成本但需要维护一个比较可靠的状态每个分区处理到哪个偏移量了上次聚合的中间结果在哪里。这个状态如果丢了整个增量链就得从全量重跑开始恢复。7.3 Checkpoint让管道“断点续跑”分布式计算框架都提供了Checkpoint机制定时把计算状态快照到持久化存储里。任务挂了之后重启能从最近的Checkpoint恢复而不是从头再来。尤其是流式处理任务如Flink作业Checkpoint几乎是标配没有Checkpoint的流式任务一旦失败可能面临大量数据丢失或者重放导致重复计算。Checkpoint的频率要权衡太频繁写快照的负担太重太稀疏恢复时回溯的数据量太大。一般我建议在保证可接受恢复时间的前提下尽量降低Checkpoint频率例如每处理5到10分钟的数据量做一次。8. 避坑实录几个真实踩过的预处理大坑写到这里我想分享几个实际的案例都是我在不同项目里真正踩过的坑。这些坑单看每一个都觉得“不至于这么蠢”但把它们串起来你会发现数据预处理的水远比想象中深。8.1 字段截断导致城市维度“神秘丢失”某次做订单分析发现华东某省的数据占比异常低怎么排查都找不到原因。最后查到底才发现上游业务系统的省市区字段长度有限制省名超过五个字就被截断该省的名字正好被截掉了一部分入库后乱码清洗逻辑匹配不上过滤掉了。这种问题哪怕质检规则再完善也难发现因为它是“合规的脏数据”——格式正常、无空值、非异常值但值本身就是错的。所以我对所有上游字段都默认不信任入库前做全字段长度校验和边界扫描特别是那些业务系统里带“长度限制”的字段。8.2 会话ID被复用用户行为数据全串线有一次做用户画像分析发现同一时间段内一个“用户”的活跃设备横跨了三个城市、五种机型。一开始以为是数据采集漏了设备信息排查后发现是会话ID的生成逻辑有问题应用在某种异常状态下会复用旧的会话ID导致多个真实用户共享同一个会话标识。如果只在会话维度上做去重这些独立用户的全部行为就被错误地合并成一个人了。解决这类问题的核心是不能只依赖单一ID做主键必须用复合标识比如会话ID设备ID用户ID来锁定一条独立记录并且在ID-Mapping时设置关联权重避免弱关联ID把不同实体强行合并。8.3 异常值本身可能反映了“采集异常”我的习惯是每次新接入一个数据源先不急着做清洗而是花时间观察数据的原始分布。比如某个字段突然出现大量0值而且集中在某段时间——这大概率是采集逻辑出了问题而不是业务上的真实变化。先处理采集异常再继续往下做预处理这是顺序问题。否则你辛辛苦苦清洗完的数据本质上还是在清洗一批本身就错误的原材料。提示做清洗之前先做“采集健康度检查”。检查每个字段的有效值比例、取值范围、时间连续性发现异常先解决采集问题再继续处理数据内容。否则预处理做得再精细也是白搭。8.4 增量链断裂后的恢复顺序增量管道最怕的不是失败而是失败后不知道以什么顺序恢复。某次因为磁盘写满HDFS上的中间结果部分损坏我先恢复了下游依赖的日汇总表但中间层明细数据还没有补完导致日汇总表跑出来的数据本身是残缺的。等明细数据补齐后我没有重新跑日汇总表而是直接当作“已恢复”继续往下游送。结果下游报表的数据全是少了半天的。自那以后我对增量恢复定了一条铁律先恢复底层明细数据再逐层向上恢复汇总层千万不能跳层恢复。恢复完成后还要做数据校验对账一下总量。9. 写在最后的几个小习惯数据预处理从来不是一个一次性动作它是一条持续运转的数据管道会一直陪伴业务演进。我个人有几个坚持了很多年的小习惯分享给大家。第一任何数据字段都要有“业务口径文档”不是只写字段名和类型而是把“这个字段是什么意思、谁负责更新、什么叫合理值、什么叫脏值”全部写清楚。文档写得好不好直接决定后来接手的同学能不能快速上手。第二预处理任务必须带质量校验和告警。不是任务跑成功就万事大吉而是要校验产出结果的关键指标是否在合理范围内记录数、去重数、关键字段空值率。任何一个指标出现异常波动都要触发告警让值班同学去排查。数据质量靠的是监控而不是靠运气。第三每个季度固定做一次“数据资产盘点”把半年没被访问的表、没被调用的字段全部下线。数据资产是有维护成本的留着不用的表每天都在花存储和计算的钱。清理掉它们集群负载会低很多出问题时的排查范围也会小很多。数据预处理这个岗位的特点就是做好了没人注意到你的存在做砸了所有人都会来找你。但也正因为这样这个岗位能学到的东西极其扎实。你会在一次次救火中把数据链路、业务逻辑、框架原理全部吃透。希望这篇文章能帮你在做数据预处理时少踩几个坑少熬几个夜。