通过率 0% · 提交 0 · 通过 0
单标签多分类任务,类别编号 0 到 k-1。给定 n 个样本的真实标签与预测标签,对每个类别 c:TP 是真实与预测都为 c 的样本数,FP 是预测为 c 但真实不是的样本数,FN 是真实为 c 但预测不是的样本数。precision = TP / (TP + FP),recall = TP / (TP + FN),F1 = 2TP / (2TP + FP + FN);任何一个分母为 0 时,对应指标按 0 处理。宏平均 F1 是全部 k 个类别 F1 的算术平均(数据中没出现过的类别同样计入);微平均 F1 = 2·ΣTP / (2·ΣTP + ΣFP + ΣFN),其中求和跑遍全部类别。
这类题属于算法机考高频题型中「华为 AI 岗 / F1」方向的高频题型,通常考察对「华为 AI 岗 / F1」的建模能力与边界条件处理。掌握本题的解题思路后,可举一反三应对同类真题方向,稳步提升机考通过率。
第一行输入 n k。第二行 n 个整数,表示真实标签。第三行 n 个整数,表示预测标签。
输出 k 行,第 c 行是类别 c 的 precision recall F1,各按四舍五入保留 4 位小数;最后再输出一行 macroF1 microF1,各按四舍五入保留 6 位小数,用单个空格分隔。
示例 1
输入示例
8 3 0 0 1 1 2 2 0 1 0 1 1 1 2 0 0 2
输出示例
0.6667 0.6667 0.6667 0.6667 0.6667 0.6667 0.5000 0.5000 0.5000 0.611111 0.625000
三分类的一次评估
示例 2
输入示例
6 2 1 0 1 1 0 0 1 0 0 1 0 1
输出示例
0.6667 0.6667 0.6667 0.6667 0.6667 0.6667 0.666667 0.666667
二分类退化
时间限制 2000 ms · 内存限制 256 MB
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。
这些是真正决定能不能 AC、但通用题解里常被略过的点。
把混淆矩阵四格延伸到多分类:每个类各算一遍 P/R/F1,再用两种方式汇总。宏平均和微平均的区别是评估岗面试的常客,这道题让你把两种口径都亲手算一遍,以后被问到就不是背答案了。
对类别 c:TP[c] = 真实和预测都是 c;FP[c] = 预测是 c 但真实不是;FN[c] = 真实是 c 但预测不是。实现上扫一遍样本就够:真实 == 预测时给 TP[真实] 加一;不等时给 FP[预测] 和 FN[真实] 各加一。O(n + k) 收工,n ≤ 8 万也毫无压力。
precision 的分母 TP+FP 为 0(这个类从没被预测过)、recall 的分母 TP+FN 为 0(数据里没这个类的真实样本)、F1 的分母 2TP+FP+FN 为 0(两者皆无)——一律按 0 输出。这是课程第 12 天的口径,写一个「分母为零返回 0」的小函数,三处复用。
前 k 行每行三个数保留 4 位,最后一行两个数保留 6 位。两种精度别串,这是格式分,丢了冤枉。
参考实现三个长度为 k 的数组计数,一遍扫完样本;一个 safe_div(a, b) 小函数统一处理 0/0;宏平均循环全部 k 个类求 F1 均值,微平均对三个数组分别求和再套一次 F1 公式。全程 O(n + k),n = 8 万瞬间跑完。
1. 全对(预测 == 真实):每个出现过的类 P = R = F1 = 1,微平均 = 1.000000;没出现的类是 0,宏平均被幽灵类拉低——这正是宏/微的分岔现场。 2. k = 3 但数据里只有类 0、1:类 2 一行输出 0.0000 0.0000 0.0000,且宏平均分母仍是 3。 3. 微平均 = 准确率:数出预测对的样本数除以 n,和你的微平均 F1 对一下,不等就是计数错了。
按这三组过一遍,四格计数和两种平均的口径就都验证到了。
这是第 12 天评估口径的多分类延伸:那天的二分类四格在这里变成 k 套,0/0 按 0 的约定原样沿用。面试里被追问「宏平均和微平均什么时候差别大」,答案就在幽灵类和类不平衡里——少数类表现差时宏平均掉得快,微平均被多数类托着;这道题的倾斜用例就是现成的演示数据。
# 一遍扫出每类 TP/FP/FN:预测对给 TP,错给 FP[预测]与 FN[真实]
# 0/0 一律按 0;宏平均分母是全部 k 类(幽灵类计入);微平均先求和再算 F1
import sys
def fmt(v, d):
s = 10 ** d
n = int(v * s + 0.5)
return "%d.%0*d" % (n // s, d, n % s)
def main():
data = sys.stdin.buffer.read().split()
n = int(data[0])
k = int(data[1])
tp = [0] * k
fp = [0] * k
fn = [0] * k
for i in range(n):
a = int(data[2 + i])
b = int(data[2 + n + i])
if a == b:
tp[a] += 1
else:
fp[b] += 1
fn[a] += 1
lines = []
f1_sum = 0.0
for c in range(k):
p = tp[c] / (tp[c] + fp[c]) if tp[c] + fp[c] > 0 else 0.0
r = tp[c] / (tp[c] + fn[c]) if tp[c] + fn[c] > 0 else 0.0
f1 = 2 * tp[c] / (2 * tp[c] + fp[c] + fn[c]) if 2 * tp[c] + fp[c] + fn[c] > 0 else 0.0
f1_sum += f1
lines.append("%s %s %s" % (fmt(p, 4), fmt(r, 4), fmt(f1, 4)))
tps = sum(tp)
fps = sum(fp)
fns = sum(fn)
micro = 2 * tps / (2 * tps + fps + fns) if 2 * tps + fps + fns > 0 else 0.0
lines.append("%s %s" % (fmt(f1_sum / k, 6), fmt(micro, 6)))
sys.stdout.write("\n".join(lines) + "\n")
main()
登录后可查看你在本题的历史提交,以及每次的各用例通过情况。
© 2026 广州慕课网络科技有限公司 · 吴师兄学算法官网 版权所有