机器学习面试题
机器学习面试题
简介
机器学习是人工智能的核心领域,涵盖监督学习、无监督学习、模型评估、特征工程等多个方面。本篇覆盖机器学习的高频面试话题,包括算法原理、模型选择、过拟合处理、评估指标等,帮助开发者系统性地准备机器学习相关的技术面试。
特点
面试题目
1. 监督学习和无监督学习的区别是什么?
答: 监督学习使用带标签的数据训练模型,目标是学习输入到输出的映射;无监督学习使用无标签数据,目标是发现数据中的隐藏结构。
| 维度 | 监督学习 | 无监督学习 |
|---|---|---|
| 数据 | 有标签(X, y) | 无标签(只有 X) |
| 目标 | 预测/分类 | 聚类/降维/生成 |
| 典型算法 | 线性回归、SVM、决策树 | K-Means、PCA、自编码器 |
| 评估 | 准确率、RMSE、F1 | 轮廓系数、重建误差 |
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.metrics import accuracy_score, silhouette_score
import numpy as np
# 监督学习示例 - 分类
def supervised_learning_example():
# 生成模拟数据
np.random.seed(42)
X = np.random.randn(1000, 10)
y = (X[:, 0] + X[:, 1] > 0).astype(int)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42)
# 训练随机森林分类器
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
# 预测和评估
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"分类准确率: {accuracy:.4f}")
# 特征重要性
for name, importance in zip(
[f"feature_{i}" for i in range(10)],
model.feature_importances_
):
print(f" {name}: {importance:.4f}")
# 无监督学习示例 - 聚类 + 降维
def unsupervised_learning_example():
np.random.seed(42)
X = np.random.randn(500, 10)
# K-Means 聚类
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
labels = kmeans.fit_predict(X)
score = silhouette_score(X, labels)
print(f"轮廓系数: {score:.4f}")
# PCA 降维
pca = PCA(n_components=2)
X_reduced = pca.fit_transform(X)
print(f"解释方差比: {pca.explained_variance_ratio_}")
print(f"累计解释方差: {sum(pca.explained_variance_ratio_):.4f}")2. 什么是过拟合?如何防止?
答: 过拟合是指模型在训练数据上表现很好,但在新数据上表现差,即模型"记住"了训练数据的噪声而非真正的规律。
from sklearn.datasets import make_moons
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
# 过拟合演示
def demonstrate_overfitting():
X, y = make_moons(n_samples=200, noise=0.3, random_state=42)
# 深度很大的树 - 容易过拟合
deep_tree = DecisionTreeClassifier(max_depth=None, random_state=42)
# 限制深度的树 - 正则化
shallow_tree = DecisionTreeClassifier(max_depth=3, random_state=42)
# 交叉验证比较
deep_scores = cross_val_score(deep_tree, X, y, cv=5)
shallow_scores = cross_val_score(shallow_tree, X, y, cv=5)
print(f"深树 (无限制): {deep_scores.mean():.4f} +/- {deep_scores.std():.4f}")
print(f"浅树 (max_depth=3): {shallow_scores.mean():.4f} +/- {shallow_scores.std():.4f}")
# 防止过拟合的方法
def regularization_methods():
"""防止过拟合的常用方法"""
# 1. 正则化(L1/L2)
from sklearn.linear_model import Ridge, Lasso
ridge = Ridge(alpha=1.0) # L2 正则化
lasso = Lasso(alpha=0.1) # L1 正则化(特征选择)
# 2. Dropout(神经网络)
import torch
import torch.nn as nn
class NetWithDropout(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(784, 256)
self.dropout1 = nn.Dropout(0.5) # 50% dropout
self.fc2 = nn.Linear(256, 128)
self.dropout2 = nn.Dropout(0.3) # 30% dropout
self.fc3 = nn.Linear(128, 10)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = self.dropout1(x)
x = torch.relu(self.fc2(x))
x = self.dropout2(x)
return self.fc3(x)
# 3. 早停(Early Stopping)
from sklearn.model_selection import train_test_split
def train_with_early_stopping(X, y, model_class, patience=10):
X_train, X_val, y_train, y_val = train_test_split(
X, y, test_size=0.2)
best_score = 0
best_epoch = 0
no_improve = 0
for epoch in range(1000):
model = model_class(max_iter=epoch + 1, random_state=42)
model.fit(X_train, y_train)
val_score = model.score(X_val, y_val)
if val_score > best_score:
best_score = val_score
best_epoch = epoch
no_improve = 0
best_model = model
else:
no_improve += 1
if no_improve >= patience:
print(f"早停于第 {best_epoch} 轮,最佳分数: {best_score:.4f}")
break
return best_model
# 4. 数据增强(Data Augmentation)
from torchvision import transforms
augment = transforms.Compose([
transforms.RandomHorizontalFlip(),
transforms.RandomRotation(10),
transforms.ColorJitter(brightness=0.2, contrast=0.2),
])
# 5. 交叉验证
from sklearn.model_selection import GridSearchCV
param_grid = {'max_depth': [3, 5, 7, 10], 'min_samples_split': [2, 5, 10]}
grid_search = GridSearchCV(
DecisionTreeClassifier(), param_grid, cv=5, scoring='accuracy')3. 常用的模型评估指标有哪些?
答: 评估指标的选择取决于问题类型和业务需求。
from sklearn.metrics import (
accuracy_score, precision_score, recall_score, f1_score,
roc_auc_score, confusion_matrix, classification_report,
mean_squared_error, mean_absolute_error, r2_score
)
import numpy as np
# 分类指标
def classification_metrics():
y_true = [1, 0, 1, 1, 0, 1, 0, 0, 1, 0]
y_pred = [1, 0, 1, 0, 0, 1, 1, 0, 1, 0]
print("=== 分类指标 ===")
print(f"准确率 (Accuracy): {accuracy_score(y_true, y_pred):.4f}")
print(f"精确率 (Precision): {precision_score(y_true, y_pred):.4f}")
print(f"召回率 (Recall): {recall_score(y_true, y_pred):.4f}")
print(f"F1 分数: {f1_score(y_true, y_pred):.4f}")
print("\n混淆矩阵:")
print(confusion_matrix(y_true, y_pred))
print("\n完整报告:")
print(classification_report(y_true, y_pred, target_names=['负类', '正类']))
"""
指标选择指南:
- 均衡数据集 -> 准确率
- 关注假阳性(如垃圾邮件)-> 精确率
- 关注假阴性(如癌症检测)-> 召回率
- 不均衡数据集 -> F1 或 AUC-ROC
"""
# 回归指标
def regression_metrics():
y_true = np.array([3.0, -0.5, 2.0, 7.0, 4.2])
y_pred = np.array([2.5, 0.0, 2.1, 7.8, 4.0])
print("=== 回归指标 ===")
print(f"MAE (平均绝对误差): {mean_absolute_error(y_true, y_pred):.4f}")
print(f"MSE (均方误差): {mean_squared_error(y_true, y_pred):.4f}")
print(f"RMSE (均方根误差): {np.sqrt(mean_squared_error(y_true, y_pred)):.4f}")
print(f"R-squared: {r2_score(y_true, y_pred):.4f}")
# 多分类指标
def multiclass_metrics():
from sklearn.metrics import cohen_kappa_score, matthews_corrcoef
y_true = [0, 1, 2, 0, 1, 2]
y_pred = [0, 2, 1, 0, 0, 1]
print(f"Cohen's Kappa: {cohen_kappa_score(y_true, y_pred):.4f}")
print(f"Matthews相关系数: {matthews_corrcoef(y_true, y_pred):.4f}")4. 什么是交叉验证?为什么需要它?
答: 交叉验证通过将数据分成多个子集,轮流使用不同的子集作为验证集,以获得更可靠的模型评估。
from sklearn.model_selection import (
KFold, StratifiedKFold, cross_val_score,
learning_curve, validation_curve
)
from sklearn.datasets import load_iris
from sklearn.svm import SVC
def cross_validation_example():
data = load_iris()
X, y = data.data, data.target
# 1. K 折交叉验证
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
model = SVC(kernel='rbf', random_state=42)
scores = cross_val_score(model, X, y, cv=kfold, scoring='accuracy')
print(f"K-Fold 准确率: {scores.mean():.4f} +/- {scores.std():.4f}")
# 2. 分层 K 折(保证每折的类别比例一致)
stratified = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=stratified, scoring='accuracy')
print(f"Stratified K-Fold: {scores.mean():.4f} +/- {scores.std():.4f}")
# 3. 学习曲线 - 判断过拟合/欠拟合
train_sizes, train_scores, val_scores = learning_curve(
model, X, y, cv=5, train_sizes=np.linspace(0.1, 1.0, 10))
print(f"\n学习曲线:")
for size, train_score, val_score in zip(
train_sizes, train_scores.mean(axis=1), val_scores.mean(axis=1)):
gap = train_score - val_score
status = "过拟合" if gap > 0.1 else "欠拟合" if train_score < 0.8 else "合适"
print(f" 训练量 {size:3.0f}: 训练={train_score:.3f}, "
f"验证={val_score:.3f}, 差距={gap:.3f} ({status})")5. 什么是梯度下降?有哪些变体?
答: 梯度下降是最常用的优化算法,通过沿损失函数梯度的反方向更新参数来最小化损失。
import torch
import torch.nn as nn
import torch.optim as optim
def gradient_descent_variants():
"""梯度下降的变体对比"""
model = nn.Sequential(
nn.Linear(784, 256),
nn.ReLU(),
nn.Linear(256, 10)
)
# 1. SGD(随机梯度下降)
optimizer_sgd = optim.SGD(model.parameters(), lr=0.01)
# 2. SGD + Momentum(动量)
optimizer_momentum = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 3. Adam(自适应学习率)
optimizer_adam = optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))
# 4. AdamW(带权重衰减的 Adam,更好的正则化)
optimizer_adamw = optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)
# 5. 学习率调度器
model_example = nn.Linear(10, 2)
optimizer = optim.Adam(model_example.parameters(), lr=0.01)
# 余弦退火
scheduler_cosine = optim.lr_scheduler.CosineAnnealingLR(
optimizer, T_max=100)
# 步进衰减
scheduler_step = optim.lr_scheduler.StepLR(
optimizer, step_size=30, gamma=0.1)
# OneCycleLR
scheduler_onecycle = optim.lr_scheduler.OneCycleLR(
optimizer, max_lr=0.01, total_steps=100)
"""
优化器选择指南:
- 默认选择: Adam 或 AdamW
- 需要 fine-tuning: SGD + Momentum + 学习率调度
- 大模型训练: AdamW + Cosine Annealing + Warmup
- 快速收敛: Adam (lr=3e-4)
- 最佳泛化: SGD + Momentum + 学习率调度
"""
# 手动实现梯度下降
def manual_gradient_descent():
"""手动实现线性回归的梯度下降"""
np.random.seed(42)
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
# 添加偏置项
X_b = np.c_[np.ones((100, 1)), X]
# 梯度下降
theta = np.random.randn(2, 1)
learning_rate = 0.1
n_iterations = 1000
m = len(X)
for i in range(n_iterations):
gradients = 2/m * X_b.T.dot(X_b.dot(theta) - y)
theta -= learning_rate * gradients
print(f"截距: {theta[0][0]:.4f} (真实值: 4)")
print(f"斜率: {theta[1][0]:.4f} (真实值: 3)")6-15. 更多机器学习面试题简答
6. 什么是偏差-方差权衡(Bias-Variance Tradeoff)? 偏差是模型预测值与真实值的系统性误差(欠拟合),方差是模型对不同训练数据的敏感程度(过拟合)。模型复杂度增加时偏差减小、方差增大,需要找到平衡点。
7. 随机森林和梯度提升树的区别? 随机森林通过 Bagging(并行训练多棵独立树取平均)降低方差;梯度提升树通过 Boosting(串行训练,每棵树修正前一棵的残差)降低偏差。随机森林更难过拟合,GBDT 通常精度更高。
8. 什么是特征工程?如何做? 特征工程是从原始数据中构造有用特征的过程。包括:缺失值处理、异常值处理、特征缩放(标准化/归一化)、类别编码(One-Hot/Label Encoding)、特征交叉、时间特征提取等。
9. SVM 的原理是什么? 支持向量机寻找最大化间隔的超平面来分类数据。通过核函数(RBF、多项式)处理非线性问题。SVM 适合中小规模数据集,高维特征空间表现优秀。
10. 什么是 PCA? 主成分分析通过正交变换将高维数据投影到方差最大的方向上,实现降维。步骤:数据中心化 -> 计算协方差矩阵 -> 特征值分解 -> 选择前 k 个主成分。
11. 集成学习有哪些方法? Bagging(随机森林)、Boosting(AdaBoost、GBDT、XGBoost、LightGBM)、Stacking(多层模型堆叠)。集成方法通常比单一模型性能更好。
12. 如何处理类别不均衡? 过采样少数类(SMOTE)、欠采样多数类、调整类别权重、使用 Focal Loss、选择合适的评估指标(F1、AUC 而非准确率)。
13. 什么是卷积神经网络(CNN)的核心思想? 局部连接(感受野)、权重共享(减少参数)、池化(空间不变性)。适合图像、时序等具有空间/时间局部性的数据。
14. 什么是 Transformer 的自注意力机制? 自注意力通过 Query、Key、Value 计算输入序列中每个位置对其他位置的关注度,捕获长距离依赖关系。多头注意力允许模型同时关注不同子空间的信息。
15. 如何选择合适的机器学习算法? 根据数据量、特征维度、问题类型、实时性要求、可解释性需求来选择。小数据简单模型优先,大数据可尝试深度学习;高可解释性选决策树/线性模型;高精度选集成方法或神经网络。
16-25. 进阶机器学习面试题
16. 什么是正则化?L1 和 L2 有什么区别? 正则化通过在损失函数中添加惩罚项来限制模型复杂度。L1(Lasso)产生稀疏权重,可用于特征选择;L2(Ridge)缩小权重但不产生稀疏,更平滑。ElasticNet 结合了两者的优点。
# 正则化对比示例
from sklearn.linear_model import Ridge, Lasso, ElasticNet
from sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score
import numpy as np
X, y = make_regression(n_samples=200, n_features=50, n_informative=10, random_state=42)
# L2 正则化(Ridge)— 缩小所有特征的权重
ridge = Ridge(alpha=1.0)
ridge_scores = cross_val_score(ridge, X, y, cv=5, scoring='r2')
# L1 正则化(Lasso)— 部分权重变为 0(特征选择)
lasso = Lasso(alpha=0.1)
lasso_scores = cross_val_score(lasso, X, y, cv=5, scoring='r2')
# ElasticNet(L1 + L2 组合)
elastic = ElasticNet(alpha=0.1, l1_ratio=0.5)
elastic_scores = cross_val_score(elastic, X, y, cv=5, scoring='r2')
print(f"Ridge R2: {ridge_scores.mean():.4f}")
print(f"Lasso R2: {lasso_scores.mean():.4f}")
print(f"ElasticNet R2: {elastic_scores.mean():.4f}")
# 查看 Lasso 的特征选择效果
lasso.fit(X, y)
n_selected = np.sum(np.abs(lasso.coef_) > 0.001)
print(f"Lasso 选择的特征数: {n_selected}/50")17. 什么是 Batch Normalization?为什么有效? 批归一化对每一层的输入做标准化(均值 0、方差 1),然后通过可学习的参数缩放和平移。效果包括:允许更大学习率、减少对初始化的敏感性、一定程度上起到正则化作用。
18. 学习率过大或过小会怎样? 学习率过大导致损失震荡甚至发散,模型无法收敛;学习率过小导致收敛极慢,可能陷入局部最优。推荐使用学习率调度器(Cosine Annealing、OneCycleLR)或自适应优化器(Adam)自动调整。
19. 什么是梯度消失和梯度爆炸? 在深层网络反向传播时,梯度逐层相乘。如果每层梯度小于 1,多层连乘后趋近于 0(梯度消失,前面的层学不到);如果大于 1,连乘后趋向无穷大(梯度爆炸,参数飞掉)。解决方案:ReLU 激活函数、残差连接(ResNet)、梯度裁剪、Batch Normalization、Xavier/He 初始化。
20. 随机森林的超参数有哪些?如何调优? 关键超参数:n_estimators(树的数量,越多越好但边际收益递减)、max_depth(树的最大深度,控制过拟合)、min_samples_split(分裂最小样本数)、max_features(每次分裂考虑的特征数)、bootstrap(是否有放回采样)。调优方法:先用 RandomizedSearchCV 缩小范围,再用 GridSearchCV 精细搜索。
21. XGBoost 和 LightGBM 的区别? XGBoost 使用按层生长(Level-wise),每层所有节点都分裂,适合精确但较慢;LightGBM 使用按叶子生长(Leaf-wise),只分裂增益最大的叶子,速度快但容易过拟合。LightGBM 还支持类别特征直方图优化,减少内存和计算量。两者都支持 GPU 加速。
# XGBoost vs LightGBM 训练示例
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import numpy as np
X, y = make_classification(n_samples=10000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
# XGBoost
from xgboost import XGBClassifier
xgb_model = XGBClassifier(
n_estimators=200,
max_depth=6,
learning_rate=0.1,
subsample=0.8,
colsample_bytree=0.8,
use_label_encoder=False,
eval_metric='logloss',
random_state=42
)
xgb_model.fit(X_train, y_train)
xgb_pred = xgb_model.predict(X_test)
print(f"XGBoost 准确率: {accuracy_score(y_test, xgb_pred):.4f}")
# LightGBM
from lightgbm import LGBMClassifier
lgb_model = LGBMClassifier(
n_estimators=200,
max_depth=6,
learning_rate=0.1,
subsample=0.8,
colsample_bytree=0.8,
num_leaves=31,
random_state=42,
verbose=-1
)
lgb_model.fit(X_train, y_train)
lgb_pred = lgb_model.predict(X_test)
print(f"LightGBM 准确率: {accuracy_score(y_test, lgb_pred):.4f}")22. 如何评估聚类效果? 因为没有标签,聚类评估依赖内部指标:轮廓系数(Silhouette Score,范围 [-1, 1],越大越好)、Calinski-Harabasz 指数(类间/类内方差比)、Davies-Bouldin 指数(越小越好)。也可用肘部法则(Elbow Method)确定最佳 K 值。
23. 什么是注意力机制? 注意力机制让模型对输入的不同部分赋予不同的权重,集中关注重要信息。自注意力(Self-Attention)通过 Q/K/V 计算序列内部的相关性,多头注意力(Multi-Head Attention)同时关注多个子空间。Transformer 的核心就是多头自注意力。
24. 迁移学习如何应用? 迁移学习利用在大数据集上预训练好的模型,迁移到目标任务上。常见方法:冻结预训练层只训练分类头(Feature Extraction)、解冻部分层微调(Fine-tuning)。在 CV 中常用 ImageNet 预训练模型,在 NLP 中常用 BERT/GPT 等预训练模型。
# 迁移学习示例:使用预训练 ResNet 微调
import torch
import torch.nn as nn
from torchvision import models
# 加载预训练模型
model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
# 方法1:特征提取(冻结所有预训练层)
for param in model.parameters():
param.requires_grad = False
# 替换最后的全连接层
num_classes = 5 # 自定义类别数
model.fc = nn.Linear(model.fc.in_features, num_classes)
# 方法2:微调(解冻部分层)
for param in model.parameters():
param.requires_grad = True # 解冻所有层
# 只对最后几层设置不同的学习率
optimizer = torch.optim.Adam([
{'params': model.fc.parameters(), 'lr': 1e-3}, # 新层用较大学习率
{'params': model.layer4.parameters(), 'lr': 1e-4}, # 浅层用较小学习率
])
print(f"模型参数量: {sum(p.numel() for p in model.parameters()):,}")
print(f"可训练参数量: {sum(p.numel() for p in model.parameters() if p.requires_grad):,}")25. 如何处理缺失值? 缺失值处理策略:删除(缺失率低于 5% 时可接受)、填充均值/中位数/众数(简单快速)、使用 KNN 填充(考虑相似样本)、使用模型预测填充(如 IterativeImputer)、作为特征保留(某些场景缺失本身有意义)。关键是理解缺失的原因(随机缺失 vs 非随机缺失)。
# 缺失值处理示例
import numpy as np
import pandas as pd
from sklearn.impute import SimpleImputer, KNNImputer
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
# 创建含缺失值的数据
data = pd.DataFrame({
'age': [25, 30, np.nan, 35, 40, np.nan, 28],
'salary': [50000, 60000, 55000, np.nan, 70000, 65000, np.nan],
'score': [85, 90, 88, 92, np.nan, 78, 85]
})
print("原始数据(含缺失值):")
print(data)
print(f"\n缺失率:\n{data.isnull().mean()}")
# 方法 1:均值填充
imputer_mean = SimpleImputer(strategy='mean')
data_mean = pd.DataFrame(imputer_mean.fit_transform(data), columns=data.columns)
print(f"\n均值填充后:\n{data_mean}")
# 方法 2:中位数填充(对异常值更鲁棒)
imputer_median = SimpleImputer(strategy='median')
data_median = pd.DataFrame(imputer_median.fit_transform(data), columns=data.columns)
# 方法 3:KNN 填充(基于相似样本)
imputer_knn = KNNImputer(n_neighbors=3)
data_knn = pd.DataFrame(imputer_knn.fit_transform(data), columns=data.columns)
print(f"\nKNN 填充后:\n{data_knn}")
# 方法 4:多重插补(IterativeImputer,使用其他特征预测缺失值)
imputer_iter = IterativeImputer(max_iter=10, random_state=42)
data_iter = pd.DataFrame(imputer_iter.fit_transform(data), columns=data.columns)
print(f"\n迭代插补后:\n{data_iter}")26-30. 系统设计与场景题
26. 如何设计一个实时推荐系统? 推荐系统分为召回(粗排)和排序(精排)两阶段。召回阶段使用协同过滤、内容匹配或向量检索从百万候选中选出数百个;排序阶段使用深度学习模型(如 DeepFM、DIN)对候选打分。需要关注的工程指标:延迟(P99 < 100ms)、QPS、特征新鲜度和 A/B 测试框架。
27. 如何处理数据不平衡? 从三个层面处理:数据层面(过采样 SMOTE、欠采样、数据增强)、算法层面(类别权重、Focal Loss、代价敏感学习)、评估层面(使用 F1、AUC 而非准确率)。极端不平衡场景(1:1000)可以考虑异常检测方法替代分类。
# 数据不平衡处理示例
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
from imblearn.pipeline import Pipeline as ImbPipeline
import numpy as np
# 创建不平衡数据集(1:10)
X, y = make_classification(
n_samples=10000, n_features=20,
n_informative=10, n_redundant=5,
weights=[0.9, 0.1], random_state=42
)
print(f"原始类别分布: 0={sum(y==0)}, 1={sum(y==1)}")
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 方法 1:使用 class_weight 平衡
model_balanced = RandomForestClassifier(n_estimators=100, class_weight='balanced', random_state=42)
model_balanced.fit(X_train, y_train)
print("\nclass_weight='balanced':")
print(classification_report(y_test, model_balanced.predict(X_test), target_names=['多数类', '少数类']))
# 方法 2:SMOTE 过采样
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)
print(f"\nSMOTE 后: 0={sum(y_resampled==0)}, 1={sum(y_resampled==1)}")
model_smote = RandomForestClassifier(n_estimators=100, random_state=42)
model_smote.fit(X_resampled, y_resampled)
print("SMOTE + RandomForest:")
print(classification_report(y_test, model_smote.predict(X_test), target_names=['多数类', '少数类']))
# 方法 3:组合过采样和欠采样
pipeline = ImbPipeline([
('oversample', SMOTE(sampling_strategy=0.5, random_state=42)), # 少数类到 50%
('undersample', RandomUnderSampler(sampling_strategy=0.8, random_state=42)) # 多数类到 80%
])
X_combo, y_combo = pipeline.fit_resample(X_train, y_train)
print(f"\n组合采样后: 0={sum(y_combo==0)}, 1={sum(y_combo==1)}")28. 模型部署的常见方式有哪些? 在线推理(REST/gRPC API、适合低延迟场景)、批量推理(离线跑批、适合推荐排序)、边缘部署(TensorRT/ONNX Runtime、适合移动端和 IoT)、模型服务化框架(TF Serving、Triton Inference Server、BentoML)。关键权衡:延迟 vs 吞吐量 vs 成本。
29. 如何监控线上模型的效果? 模型监控包括:数据漂移(特征分布变化,用 PSI/KS 检测)、概念漂移(标签分布变化)、预测分布偏移、性能指标下降。建议建立基线,设置自动告警,并定期用标注数据计算实际效果。
30. 特征工程在生产环境中的最佳实践? 使用特征存储(Feature Store,如 Feast)统一离线和在线特征,保证一致性。特征版本化、可追溯、可复用。注意特征穿越(泄露未来信息)问题。在线特征要控制计算延迟,离线特征要处理历史对齐。
优点
缺点
总结
机器学习面试需要掌握监督/无监督学习的核心算法、模型评估方法、过拟合处理策略和优化算法。建议在理解原理的基础上,通过 Kaggle 项目积累实战经验,重点关注特征工程、模型调参和业务指标对齐。在面试中展示对算法原理的理解和实际应用能力比记忆公式更重要。
这组题真正考什么
- AI 面试题通常在考你是否能把术语和工程落地连起来。
- 很多题目的关键不在模型名字,而在数据、评估和成本权衡。
- 答题时如果能提到失败场景和安全边界,会更有深度。
60 秒答题模板
- 先解释概念本身。
- 再说它解决什么问题和有什么限制。
- 最后补工程落地时的指标、成本或风险点。
容易失分的点
- 只记英文缩写,不会中文解释。
- 只谈效果,不谈评估和成本。
- 把不同模型或不同阶段混为一谈。
刷题建议
- 把模型原理、训练方法、评估方式和工程落地分层复习。
- 回答 AI 题时尽量同时提到数据、模型、效果和成本。
- 对热门术语要准备“是什么、解决什么问题、有什么限制”三个层次。
高频追问
- 这个方法在效果、延迟和成本上的权衡是什么?
- 如果模型输出不稳定,你会从哪些环节开始排查?
- 这个概念在企业落地时最容易踩的坑是什么?
复习重点
- 把每道题的关键词整理成自己的知识树,而不是只背原句。
- 对容易混淆的概念要做横向比较,例如机制差异、适用边界和性能代价。
- 复习时优先补“为什么”,其次才是“怎么用”和“记住什么术语”。
面试作答提醒
- 避免只背英文缩写,尽量用一句中文把核心机制讲明白。
- 说效果时最好带上评估方式或具体指标。
- 不确定的模型细节可以明确说明假设前提。
