文章目录
第14章:编程与代码实现(机试核心)
本章是为机试环节量身打造的实战训练场。夏令营机试的特点是:时间紧、任务重,题目通常不会像 LeetCode Hard 那样追求极致的技巧,而是更侧重于考察你是否能准确、快速地实现机器学习中的核心算法模块、调用API完成数据处理任务,或搭建一个简单的深度学习模型。
因此,本章的训练目标非常明确:
- “肌肉记忆”:通过从零实现,将核心算法的逻辑内化为你的编程直觉。
- “工具熟练”:熟练掌握 Scikit-learn 和 PyTorch/TensorFlow 的常用API,做到“召之即来,来之能战”。
- “避坑指南”:熟悉机试环境的特点和常见陷阱,避免在非算法因素上失分。
让我们开始吧!
14.1 机试环境与心态准备
- 常见机试平台特点:国内夏令营最常见的平台是牛客网和赛码网。它们的共同特点是采用 VIM / Sublime Text 编辑器模式和 标准输入输出(Standard I/O)。
- 编辑器:通常没有强大的自动补全和调试功能,因此你必须对库函数和代码逻辑有清晰的记忆。
- 标准输入输出:代码需要从标准输入流(如
sys.stdin或input())读取数据,并将结果打印到标准输出(print())。这意味着你不能使用pandas.read_csv()等直接读取文件的方式,除非题目明确说明。
- 时间分配策略:
- 通读题目(5-10分钟):快速浏览所有题目,评估难度,确定做题顺序(先易后难)。
- 分块击破:为每道题设定一个大致的时间上限。如果一道题长时间没有思路,果断跳过,先完成其他有把握的题目。
- 预留调试时间(15-20分钟):不要把所有时间都用来写新代码。调试是机试的一部分,务必留出时间检查、优化和处理边界情况。
- Debug 技巧:
print()是你最好的朋友:在关键步骤(如数据读取后、特征处理后、模型预测前)打印变量的shape、type和前几行的值,这是最快定位问题的方法。- 本地测试:在自己的IDE(如 PyCharm, VSCode)中编写和测试代码,使用题目给出的示例输入进行验证,通过后再粘贴到网页。
- 关注错误提示:仔细阅读平台的报错信息,它会告诉你是“编译错误”、“运行错误”还是“答案错误”,并可能提供出错的测试用例编号。
- 代码风格:
- 清晰胜于炫技:使用有意义的变量名(如
learning_rate而非lr),适当添加注释,尤其是在核心逻辑部分。 - 模块化:将功能独立的逻辑封装成函数,使主程序流程清晰。
- 清晰胜于炫技:使用有意义的变量名(如
14.2 从零实现核心算法 (Hand-coding from Scratch)
这部分是考察算法理解深度的“试金石”。题目通常会给出一个类或函数的框架,让你填充核心部分。
【机试代码填空专栏 1】k-近邻算法 (k-NN)
- 考点: 距离计算(欧氏距离)、数据结构(用于存储距离和标签)、排序与选择 Top-K。
- 代码框架与待填空部分
import numpy as np
from collections import Counter
class KNNClassifier:
def __init__(self, k):
self.k = k
self.X_train = None
self.y_train = None
def fit(self, X_train, y_train):
self.X_train = X_train
self.y_train = y_train
def _euclidean_distance(self, x1, x2):
# --- START OF CODE TO FILL ---
# 计算两个样本点之间的欧氏距离
return np.sqrt(np.sum((x1 - x2)**2))
# --- END OF CODE TO FILL ---
def predict(self, X_test):
predictions = [self._predict_single(x) for x in X_test]
return np.array(predictions)
def _predict_single(self, x):
# 1. 计算测试样本 x 与所有训练样本的距离
# --- START OF CODE TO FILL ---
distances = [self._euclidean_distance(x, x_train) for x_train in self.X_train]
# --- END OF CODE TO FILL ---
# 2. 获取距离最近的 k 个点的索引
# --- START OF CODE TO FILL ---
k_indices = np.argsort(distances)[:self.k]
# --- END OF CODE TO FILL ---
# 3. 获取这 k 个点的标签
# --- START OF CODE TO FILL ---
k_nearest_labels = [self.y_train[i] for i in k_indices]
# --- END OF CODE TO FILL ---
# 4. 投票选出最常见的标签
# --- START OF CODE TO FILL ---
most_common = Counter(k_nearest_labels).most_common(1)
return most_common[0][0]
# --- END OF CODE TO FILL ---
# 示例
# X_train = np.array([[1, 2], [1.5, 1.8], [5, 8], [8, 8], [1, 0.6], [9, 11]])
# y_train = np.array([0, 0, 1, 1, 0, 1])
# X_test = np.array([[3, 4], [7, 9]])
# knn = KNNClassifier(k=3)
# knn.fit(X_train, y_train)
# predictions = knn.predict(X_test)
# print(predictions) # 预期输出 [0 1]
【机试代码填空专栏 2】线性回归的梯度下降
- 考点: 假设函数 h θ ( x ) h_\theta(x) hθ(x)、损失函数 J ( θ ) J(\theta) J(θ)、梯度更新 θ j : = θ j − α ∂ ∂ θ j J ( θ ) \theta_j := \theta_j - \alpha \frac{\partial}{\partial \theta_j} J(\theta) θj:=θj−α∂θj∂J(θ)。特别注意矩阵运算的维度匹配。
- 代码框架与待填空部分
import numpy as np
class LinearRegressionGD:
def __init__(self, learning_rate=0.01, n_iters=1000):
self.lr = learning_rate
self.n_iters = n_iters
self.weights = None
self.bias = None
def fit(self, X, y):
n_samples, n_features = X.shape
# 初始化参数
self.weights = np.zeros(n_features)
self.bias = 0
# 梯度下降
for _ in range(self.n_iters):
# 1. 计算预测值 y_pred = X * w + b
# --- START OF CODE TO FILL ---
y_pred = np.dot(X, self.weights) + self.bias
# --- END OF CODE TO FILL ---
# 2. 计算梯度
# 损失函数 J = (1/2m) * sum((y_pred - y)^2)
# dJ/dw = (1/m) * X^T * (y_pred - y)
# dJ/db = (1/m) * sum(y_pred - y)
# --- START OF CODE TO FILL ---
dw = (1 / n_samples) * np.dot(X.T, (y_pred - y))
db = (1

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



