
简介面向校招算法岗学生和算法竞赛选手的机器学习资源整合包覆盖机器学习算法、大厂面经、coding、算法比赛四大方向将分散的算法原理、面试真题、代码实战与比赛经验集中整理便于系统性备战。内容涵盖NLP预训练模型从BERT、XLNet到MPNet的发展梳理PCA、KMeans、朴素贝叶斯等经典算法详解以及K近邻方法中KDTree、Annoy、HNSW的实现对比还有GBDT/XGBoost常考问题与决策树随机森林的总结可作为算法岗面试复习的知识索引。资源共482个文件压缩包约26.8MB文件类型以228张原理图解png、120个Python代码脚本py、112个Org-mode笔记org和14篇Markdown文档为主图解便于理解公式与流程脚本可直接运行验证笔记和文档则适合按主题快速翻阅。目前已有234人学习下载适合需要在校招前查漏补缺、强化coding能力并系统回顾机器学习重点的读者。1. 机器学习算法资源越攒越多面试却越来越没底我看到太多人和三年前的我一样收藏夹里躺着几十个 GitHub 仓库网盘里存着几百页面经 PDFKaggle 奖牌墙截了图LeetCode 刷了三百题但真到大厂面试官问“你讲一下 XGBoost 的分裂增益是怎么算的”“你比赛里怎么做特征筛选”却只能说出个大概。问题不在资料不够而在没有把机器学习算法、coding、面经、比赛这四摊事串成一条可执行的主线。这篇文章就是我按照自己带人的经验把这条主线完整写出来先立理论主干再定 coding 训练方案然后用比赛验证工程能力最后把面经拆成可复现的复习清单并给出一套资源整合的方式。适合准备校招、社招转算法岗、以及想通过比赛补齐项目经验的人。不整虚的全是能直接用的路径、命令和代码。2. 机器学习算法主线先立骨架再谈覆盖面2.1 用 20% 的算法覆盖 80% 的面试题选型顺序比数量重要机器学习算法面试和学术研究不一样面试官考察的不是你知道多少种算法而是你能否在限定时间内把一个问题从数据到模型讲圆。我一般建议按这个顺序建立主线线性模型线性回归、逻辑回归→ 树模型决策树、随机森林、GBDT、XGBoost、LightGBM→ 聚类与降维KMeans、PCA→ 深度学习基础多层感知机、CNN、RNN/Transformer 的直觉。这个顺序的设计逻辑是越靠前的算法越能解释“机器学习在做什么”越靠后的算法越接近业务落地时的真实选择。不要一上来就扎进 SVM 的核函数推导或者 EM 算法的收敛性证明那些是锦上添花不是雪中送炭。大厂面试里逻辑回归和树模型被问到的概率远高于其他算法因为它们直接对应推荐、风控、搜索这些核心业务场景。你把这两个算法吃透再去看深度学习会发现很多概念是相通的比如损失函数、正则化、梯度下降这些在任何模型里都是同一个东西。2.2 建立一个可检索的算法速查表把公式和代码绑在一起光看书不写代码知识点是飘的。我自己维护了一个算法速查表每学一个算法就做三件事写清适用场景、贴出核心公式、附上最小可运行代码。这份速查表不追求排版精美追求的是让三天后的自己能一眼看懂。算法适用场景核心要点面试高频追问逻辑回归二分类、基线模型sigmoid 输出、交叉熵损失为什么用交叉熵不用 MSE决策树可解释性要求高的场景信息增益、基尼系数分裂点怎么选怎么剪枝GBDT表格数据默认选择负梯度拟合残差和随机森林的本质区别XGBoost比赛与工业落地二阶泰勒展开、正则项分裂增益公式推导KMeans无监督聚类、用户分群距离度量、K 值选择如何评估聚类效果这张表建好之后每次复习只看表里最薄弱的行。下面是我用来验证逻辑回归梯度下降实现是否正确的代码这也是面试手撕代码的高频题import numpy as np def sigmoid(z): return 1 / (1 np.exp(-z)) def compute_loss(y, y_pred): # 交叉熵损失加一个极小值防止 log(0) eps 1e-15 return -np.mean(y * np.log(y_pred eps) (1 - y) * np.log(1 - y_pred eps)) def gradient_descent(X, y, lr0.01, epochs1000): m, n X.shape w np.zeros(n) b 0.0 for i in range(epochs): z np.dot(X, w) b y_pred sigmoid(z) dw np.dot(X.T, (y_pred - y)) / m db np.mean(y_pred - y) w - lr * dw b - lr * db if i % 200 0: print(fepoch {i}, loss: {compute_loss(y, y_pred):.4f}) return w, b逻辑很简单前向传播算出预测值用交叉熵衡量预测和真实的差距然后对 w 和 b 求梯度沿负方向更新。这里有两个面试官常挖的细节为什么梯度是X.T.dot(y_pred - y) / m而不是别的形式以及学习率过大或过小的表现分别是什么。你把这两句话说清楚比背十遍公式有用。2.3 损失函数与评估指标的错位是最容易被问倒的地方很多人把损失函数和评估指标混为一谈面试官稍微追问就卡壳。损失函数是训练时用来优化模型的要求可导、光滑评估指标是上线后用来衡量业务效果的只关心最终结果。比如排序场景训练时用 Listwise 损失评估却看 AUC 或者 GAUC这两者之间存在一个 Gap。最常见的例子是类别不平衡业务中正样本只有 1%你用准确率评估模型全预测为负样本也能拿到 99%。这时候损失函数要用 Focal Loss 或者给样本加权重评估指标要换成 PR 曲线下的面积或者 RecallK。面试官问“你怎么评估一个风控模型”你只要说出“训练用加权交叉熵评估用 Recall 和 Precision 的 Trade-off并画出 PR 曲线”这个层级就已经能区分开只会调包的人。建议你手写一遍 PR 曲线的计算逻辑这对理解阈值如何影响结果非常有帮助。3. coding 训练从 LeetCode 到手写机器学习代码的衔接3.1 按面试频率给 LeetCode 题目分优先级而不是按题号刷LeetCode 刷题最大的误区是从第 1 题刷到第 800 题实际上大厂面试考的题目类型非常集中。我把题目分成三个优先级这个分法多次验证过有效P0 是数组与哈希表、双指针、二叉树、链表P1 是动态规划、回溯、堆与优先队列、二分查找P2 是图论、线段树、并查集这些冷门但偶尔出现的类型。P0 必须做到闭着眼睛能写出来因为这些是面试手撕代码环节最常出的类型。P1 要求掌握套路比如动态规划先想状态定义、再想转移方程、最后想边界条件。P2 只需要会模板题因为面试中极少深入考察。下面的表格是我给自己定的每周训练计划你可以直接拿去改。星期训练主题题量要求额外任务周一数组与哈希表4 题每题两种解法手写一遍 LRU 缓存周二双指针与滑动窗口4 题写出时间复杂度分析总结窗口收缩条件周三二叉树遍历与递归4 题迭代和递归都要会手写 Morris 遍历周四动态规划入门3 题写出状态转移图对比记忆化和递推周五链表操作4 题画图理清指针关系手写链表反转的递归版周六综合模拟5 题限时 90 分钟复盘错题的卡点周日休息与复盘0 题整理本周错误清单重写所有卡壳题目这里的核心不是题量而是每道题做完之后要能回答三个问题这题属于什么类型、最优解的时间复杂度是多少、为什么不能用别的数据结构。我见过太多人刷了五百题面试遇到一个“二维矩阵中找岛屿数量”的变体就懵了因为他之前是背的解法而不是理解的思路。每次做完题把思路用三句话写下来这个习惯比多刷五十道题更有价值。3.2 手写高频机器学习算法不只是背代码要能讲清每一步大厂 coding 面试这两年越来越爱考机器学习算法的手写实现尤其是逻辑回归、KMeans、PCA、决策树这类代码量不大但能考察基本功的算法。手写的意义不在于生产可用而在于确认你理解梯度怎么算、中心怎么更新、特征值分解在做什么。class KMeans: def __init__(self, n_clusters3, max_iter100): self.n_clusters n_clusters self.max_iter max_iter self.centroids None def fit(self, X): # 随机初始化中心点 n_samples X.shape[0] idx np.random.choice(n_samples, self.n_clusters, replaceFalse) self.centroids X[idx] for _ in range(self.max_iter): # 分配每个样本到最近的中心 distances np.linalg.norm(X[:, np.newaxis, :] - self.centroids, axis2) labels np.argmin(distances, axis1) # 更新中心为簇内样本均值 new_centroids np.array([X[labels k].mean(axis0) for k in range(self.n_clusters)]) if np.allclose(new_centroids, self.centroids): break self.centroids new_centroids return self面试官看完这段代码通常会追问三个问题KMeans 会收敛到局部最优怎么办、K 值怎么选、距离度量能不能换成余弦相似度。你能答出“多跑几次随机初始化选成本最低的、用肘部法则或轮廓系数选K、换度量时更新公式不变但分配结果会变”基本就过关了。平时练习时建议每写完一个算法就顺手在 sklearn 的同一数据集上对比一遍结果验证自己有没有写错。3.3 用“说题 写码 验证”的节奏模拟真实面试环境很多人自己刷题能写出来一到面试就卡壳因为缺少“边说边写”的训练。真实面试中面试官会要求你先说思路再动手中途还会打断问复杂度。我建议你在家练习时开着录音规定每道题先花两分钟说清思路然后开始写代码写完立刻口述验证一个测试用例。这个流程很痛苦但非常有效。进度方面从零到能应付大厂手撕环节P0 需要四到六周P1 需要六到八周P2 看个人余力。不要一天刷十题然后歇三天保持每天三到四题的节奏大脑对算法模式形成肌肉记忆需要持续刺激。遇到卡了二十分钟还没有思路的题直接看题解看懂后合上答案自己重写一遍比死磕一小时效率高得多。4. 算法比赛用 Kaggle 和国内比赛补上项目经验的缺口4.1 比赛的价值不是奖牌而是逼你走完一个完整的机器学习项目流程很多人的简历上没有正式的项目经历算法比赛就是填补这个空白的最高效方式。但比赛的意义不在排名而在于它强制你走完数据清洗、特征工程、模型训练、调参、融合、复盘这一整条流水线。面试官问比赛经历时最想听到的是“我从数据里发现了什么规律”“我做了哪些尝试哪些有效哪些没用”而不是“我排名前 5%”。我建议第一次参加比赛的人选择 Kaggle 上的表格数据类比赛或者国内平台上的入门赛这类比赛数据量适中、评价指标明确、社区讨论丰富。第一次完整走完一轮的预期耗时是两到三周每天投入两小时。不要上来就打新赛道的比赛比如多模态或者强化学习因为你连处理表格数据的完整流程都没有建立直接上复杂任务只会打击信心。4.2 把验证策略放在整个流程的最前面而不是最后比赛中新手最容易犯的错误是先做一大堆特征工程然后随便切一个训练集就开训最后结果忽高忽低根本不知道改进方向。正确的顺序是先确定验证策略再做任何特征或模型实验。对于回归类比赛5 折交叉验证是标配对于时间序列类比赛必须按时间顺序切分否则会造成数据泄漏让验证分数虚高。from sklearn.model_selection import KFold from sklearn.metrics import mean_squared_error import lightgbm as lgb # 5折交叉验证每折训练模型并记录 OOF 预测 kf KFold(n_splits5, shuffleTrue, random_state42) oof_pred np.zeros(len(X_train)) for fold, (train_idx, valid_idx) in enumerate(kf.split(X_train)): trn_data lgb.Dataset(X_train[train_idx], y_train[train_idx]) val_data lgb.Dataset(X_train[valid_idx], y_train[valid_idx]) params { objective: regression, metric: rmse, learning_rate: 0.05, num_leaves: 31, verbose: -1 } model lgb.train(params, trn_data, num_boost_round1000, valid_sets[val_data]) oof_pred[valid_idx] model.predict(X_train[valid_idx]) print(fOOF RMSE: {mean_squared_error(y_train, oof_pred, squaredFalse):.4f})这段代码的关键是 OOF 预测每一折只预测验证集部分最终拼成完整的样本外预测然后用它来计算一个可信的评估分数。这样做的意义在于当你增加特征或调整参数时OOF 分数的变化趋势基本能代表线上分数的变化趋势。你每改一次特征工程就重新跑一遍这段代码记录 OOF 分数形成自己的实验日志。比赛结束复盘时这些日志就是你面试时最有价值的弹药。4.3 特征工程从三张表开始统计特征、交叉特征、目标编码特征工程听起来玄但有固定的套路。结构化数据比赛里我的起点永远是三个方向对数值特征做统计最大值、最小值、均值、方差、对有意义的类别特征做交叉组合、对高基数类别特征做目标编码。先把这三个方向做完模型分数通常就能达到一个不错的水平再去想更复杂的方案。特征类型做法适用场景注意事项统计特征groupby 后求 mean/std/count用户行为序列、商品销售记录注意时间顺序避免泄漏交叉特征两个类别特征拼接成新类别用户城市 × 商品类目会增大稀疏性配合正则目标编码用目标均值替代类别值高基数类别如商品 ID必须做 K 折内编码否则过拟合目标编码是最容易被忽略但效果最明显的特征工程手段同时也是最高危的。如果不做 K 折内编码直接用全量目标均值替代类别值训练集分数会虚高很多线上直接崩。你可以把 4.2 的 KFold 代码改一下在每一折内部再切出一小部分计算目标均值这样既保住信息又不至于泄漏。补充一点EDA 阶段用 pandas 的df.groupby().agg()快速算这些特征比写循环快至少十倍简历里写“数据规模百万级用 pandas 完成特征工程”才站得住。5. 大厂面经的拆解方式把碎片化成体系把问题变考点5.1 用考点聚类代替按公司搜集面经我知道很多人从牛客和论坛上下载了上百篇面经但存完之后就再也没打开过。面经的正确用法不是背题而是从里面提取考点频率。我做了个统计近一年的大厂算法岗面经里机器学习基础占 40%coding 占 30%项目与比赛经历占 20%基础数学与工程能力占 10%。这个比例在不同公司略有浮动但大方向不会变。所以最有效的方式是每个月找十五到二十篇近期面经不要记题目而是记录每道题考察的知识点标签。比如“请解释 GBDT 和 XGBoost 的区别”记作“树模型对比”“请手写 LRU”记作“手写数据结构”“比赛里怎么做特征筛选”记作“特征工程方法”。一个月后你就有了一张高频考点表按频次排序就知道该往哪里投入时间。5.2 每道面经题目都要能写出一段“从现象到本质”的答案面经只背结论是没用的面试官一个追问就能戳穿。我给自己定了一个标准每当遇到一道题我要能写出三层回答——先给结论再讲原理最后给出工程建议。比如 SVM 和逻辑回归的区别结论是“两者损失函数不同导致决策边界差异”原理是“hinge loss 关注支持向量、交叉熵关注所有样本”工程建议是“特征量大优先用 LR样本量适中且边界非线性用 SVM”。面经高频题结论层原理层工程层为什么 LR 不用 MSE 做损失MSE 非凸容易陷入局部最优交叉熵在 sigmoid 输出下是凸函数分类问题默认交叉熵回归才用 MSE随机森林和 GBDT 区别Bagging vs Boosting独立并行 vs 串行拟合残差高方差场景用 RF高偏差用 GBDT特征相关性高会导致什么树模型影响小线性模型影响大特征共线性导致权重不稳定线性模型先做相关性筛选或加 L2整理的时候尽量用表格形式因为表格强制你提炼关键词而不是抄一大段话。当你把三十道高频题都整理成这个格式再去看新的面经会发现大部分新题都是旧考点的变体只是套了不同的业务场景。没有真实比赛经历的人可以把比赛的方案按这个分层结构写出来同样能掩盖一部分简历上的空白。5.3 面试前两周的复习节奏三轮压缩越到后面越少面经资料整理好之后怎么复习也有讲究。我一般把考前两周分成三个阶段第一周按考点覆盖所有内容每看完一个考点就闭卷复述一遍说给自己听或者写下来第二周只做高频题模拟对着手机录音回答每道题控制在三分钟以内训练表达结构最后两天只看整理出的表格和错误清单不再接触新内容。这个方法能有效避免“看了很多、但一问就卡”的情况。6. 资源整合的最终状态一键还原的个人知识库6.1 用文本文件代替收藏夹构建可检索、可更新的知识库这里的“资源整合”不是把资料堆在一起而是把所有材料和心得变成一个可持续维护的系统。我用的是一个根目录加三类子目录的结构notes/放算法笔记coding/放题目记录competition/放每个比赛的方案和代码。好处是所有东西都是纯文本Markdown可以用 grep 命令全局搜索也可以用 git 做版本管理换电脑一键克隆就能还原。# 初始化个人知识库结构 mkdir -p ml_interview/{notes,coding,competition} cd ml_interview git init # 搜索所有笔记中带偏差方差的内容 grep -r 偏差方差 notes/ # 统计 coding 目录下已完成的题目数量 grep -c 完成 coding/*.md这套方案的核心逻辑是把沉淀内容当成仓库管理而不是当成电子书收藏。面经里的高频考点、比赛里的实验日志、coding 的错题记录都分散写入对应的文件。面试前只需要做一件事全文搜索关键词快速定位所有与之相关的内容。6.2 每周日做一次十五分钟的索引更新防止知识库失效很多人的知识库建起来之后两周就荒废了因为整理是一件反人性的事情。我给自己的约束是每周日花十五分钟更新一个全局索引文件不写内容只做三件事——把本周新学的知识归类到目录下、更新高频考点表的次数统计、删掉已经烂熟于心不需要再看的旧内容。索引文件本身就是一个数据库面试前两周只看索引指向的重点效率能提高一倍。最后一件事值得单独说资源整合的核心不是拥有多少材料而是任何一份材料都能在三步之内找到并派上用场。哪怕你的知识库里只有五十个文件只要索引清晰、内容精炼效果远好于网盘里一万个从未打开的 PDF。本文还有配套的精品资源点击获取