通过率 0% · 提交 0 · 通过 0
风控系统要用历史请求训练一个二分类器。先用训练集每列的最小值和最大值做 Min-Max 归一化(常量列归一化为 0),再从零参数出发执行固定轮数的批量梯度下降:每轮先对全部样本计算概率 p=sigmoid(b+w·x),再用平均梯度同步更新参数,即 b 减去 eta·(1/n)·Σ(p−y),w_j 减去 eta·(1/n)·Σ(p−y)·x_j。训练结束后输出参数,并对查询样本输出预测概率;查询样本用训练集的范围归一化,超出范围不截断。sigmoid 需要写成数值稳定的形式,避免大数溢出。
这类题属于算法机考高频题型中「华为 AI 岗 / 逻辑回归」方向的高频题型,通常考察对「华为 AI 岗 / 逻辑回归」的建模能力与边界条件处理。掌握本题的解题思路后,可举一反三应对同类真题方向,稳步提升机考通过率。
第一行输入 n d m e,分别为训练样本数、特征维数、查询样本数和训练轮数。第二行输入学习率 eta。接下来 n 行,每行 d 个整数特征和一个标签(0 或 1)。随后 m 行,每行 d 个整数,表示查询样本。
第一行输出 d+1 个保留四位小数的实数:b w_1 … w_d。接下来 m 行,每行输出一个保留四位小数的预测概率。绝对值小于 0.00005 时输出 0.0000。
示例 1
输入示例
2 1 2 1 1 0 0 10 1 0 10
输出示例
0.0000 0.2500 0.5000 0.5622
一轮更新后 b=0,w=0.25;两个查询的归一化值为 0 和 1。
示例 2
输入示例
2 2 1 0 0.5 0 3 0 10 7 1 5 5
输出示例
0.0000 0.0000 0.0000 0.5000
训练轮数为 0,参数保持为 0,任何查询概率都是 0.5。
时间限制 3000 ms · 内存限制 256 MB
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。
这些是真正决定能不能 AC、但通用题解里常被略过的点。
逻辑回归的完整训练管线,骨架与线性回归判题完全同构:Min-Max 归一化、固定轮数批量梯度下降、同步更新。差别集中在两处——梯度换了口径、sigmoid 必须数值稳定。
交叉熵损失配 sigmoid 的梯度是干净的 (1/n)·Σ(p−y)·x(偏置对应 x=1)。它和线性回归 MSE 的 (2/n)·Σ(pred−y)·x 形式几乎相同,但没有 2——两个损失求导后系数恰好不同,把 MSE 的 2 带过来是这道题最高频的 WA 来源。
更新纪律不变:一轮内全部梯度基于旧参数计算,算完统一更新;归一化参数只来自训练集,查询超范围不截断,常量列归 0。
查询样本特征可以到 ±10000,若干轮训练后 |z| = |b + w·x| 可以冲到 1e5 量级。教科书式的 1/(1+exp(-z)) 在 z = −100000 时要算 exp(100000)——Python 直接 OverflowError,C++ 得到 inf。按符号分支:
def sigmoid(z):
if z >= 0:
e = math.exp(-z) # z>=0 时 exp(-z)<=1,永不溢出
return 1.0 / (1.0 + e)
e = math.exp(z) # z<0 时 exp(z)<1
return e / (1.0 + e)两个分支里 exp 的参数都不为正,数学上与原式完全等价。训练循环和查询预测走的是同一个 sigmoid,一处不稳两处都炸。
1. 训练集统计 min/max → 归一化训练集与查询集(常量列归 0)。 2. 零参数出发跑 e 轮:p = sigmoid(b + w·x̂),累加 (p−y) 与 (p−y)·x̂,除以 n 乘 eta 同步更新。 3. 输出参数一行 + 每个查询的概率,四位小数,绝对值小于 0.00005 输出 0.0000。
训练 O(e·n·d),预测 O(m·d)。
-0.0000 未钳制。样例 1:n=2、d=1、e=1、eta=1,训练对 (x=0, y=0) 和 (x=10, y=1),归一化后 x̂ 为 0 和 1。零参数下两个概率都是 sigmoid(0)=0.5:
输出第一行 0.0000 0.2500。查询 x=0 → sigmoid(0) = 0.5;x=10 → x̂=1 → sigmoid(0.25) = 0.5622。同一组数字用 MSE 的 2 倍系数走一遍会得到 w=0.5、概率 0.6225——第一行就分岔,这正是「梯度口径」用例的设计意图。
逻辑回归的面试灵魂问题是「为什么配交叉熵不配 MSE」。可复述的答案有两层:交叉熵配 sigmoid 求导后梯度恰好是 (p−y)·x,形式干净且错得越离谱梯度越大;MSE 配 sigmoid 的梯度里会多乘一个 p(1−p),预测错得极端时这个因子趋近 0,梯度反而消失,模型在最该学习的样本上学不动。数值稳定的 sigmoid 则是工程素养题——按符号分支让 exp 的参数永不为正,一行分支换来任意量级输入下的稳定,这个写法值得当成肌肉记忆。
# 与线性回归同骨架:训练集 Min-Max(常量列归 0)+固定轮数批量 GD 同步更新;梯度 (1/n)Σ(p−y)x,没有 MSE 的 2 倍系数。
# sigmoid 按符号分支保证 exp 参数永不为正,|z| 到 1e5 也不溢出。
import math
import sys
def stable_sigmoid(z: float) -> float:
if z >= 0:
e = math.exp(-z)
return 1.0 / (1.0 + e)
e = math.exp(z)
return e / (1.0 + e)
def fmt(value: float) -> str:
if abs(value) < 0.00005:
value = 0.0
return f"{value:.4f}"
def solve() -> None:
data = sys.stdin.buffer.read().split()
if not data:
return
it = iter(data)
n, d, m, epochs = (int(next(it)) for _ in range(4))
eta = float(next(it))
x, y = [], []
for _ in range(n):
x.append([float(next(it)) for _ in range(d)])
y.append(float(next(it)))
query = [[float(next(it)) for _ in range(d)] for _ in range(m)]
lo = [min(row[j] for row in x) for j in range(d)]
hi = [max(row[j] for row in x) for j in range(d)]
def norm(row):
return [0.0 if hi[j] == lo[j] else (row[j] - lo[j]) / (hi[j] - lo[j]) for j in range(d)]
train = [norm(row) for row in x]
weights = [0.0] * d
bias = 0.0
for _ in range(epochs):
grad_w = [0.0] * d
grad_b = 0.0
for row, target in zip(train, y):
z = bias
for j in range(d):
z += weights[j] * row[j]
error = stable_sigmoid(z) - target
grad_b += error
for j in range(d):
grad_w[j] += error * row[j]
scale = 1.0 / n
bias -= eta * scale * grad_b
for j in range(d):
weights[j] -= eta * scale * grad_w[j]
out = [" ".join(fmt(v) for v in [bias, *weights])]
for row in query:
row = norm(row)
z = bias
for j in range(d):
z += weights[j] * row[j]
out.append(fmt(stable_sigmoid(z)))
print("\n".join(out))
if __name__ == "__main__":
solve()
登录后可查看你在本题的历史提交,以及每次的各用例通过情况。
© 2026 广州慕课网络科技有限公司 · 吴师兄学算法官网 版权所有