二分类的意图判定

题意

给定 条训练样本和 条测试样本。每个样本是一个由大写字母 A-G 组成的字符串,训练样本带有标签 0 或 1。要求用单层逻辑回归模型训练后,对测试样本进行预测。

模型的具体规格:

  • 特征编码:7 维 one-hot 存在编码,字母 A-G 分别对应一个维度,存在为 1,不存在为 0
  • 初始权重和偏置均为 0
  • 激活函数:sigmoid
  • 损失函数:二元交叉熵
  • 优化方式:梯度下降,学习率 0.1,训练 20 个 epoch,batch size 为 1(即 SGD)
  • 预测阈值:大于 0.5 输出 1,否则输出 0

思路

这道题没有什么算法设计的空间,就是老老实实把逻辑回归的训练和推理过程模拟出来。关键是把梯度计算搞对。

特征编码怎么做? 字符串里每个字符映射到维度 ,对应位置设为 1。比如 "ABC" 编码成

前向传播: 计算 ,再过 sigmoid 得到预测值 。sigmoid 实现要注意数值稳定性—— 为负数时用 避免溢出。

梯度更新: 二元交叉熵对 的梯度推导很简洁,最终结果就是 。所以权重更新为:

$$

$$

其中 是学习率。

训练流程: 外层循环 20 个 epoch,内层按顺序遍历每条训练样本,逐条做前向 + 更新。这就是 batch size 为 1 的 SGD。

预测: 训练完后,对每条测试样本做一次前向传播, 输出 1,否则输出 0。

复杂度

  • 时间:,其中 是特征维度
  • 空间:,只需要存权重向量

代码

import math

def solve():
    n, m = map(int, input().split())

    train_data = []
    for _ in range(n):
        parts = input().split()
        s = parts[0]
        label = int(parts[1])
        features = [0] * 7
        for ch in s:
            features[ord(ch) - ord('A')] = 1
        train_data.append((features, label))

    test_data = []
    for _ in range(m):
        s = input().strip()
        features = [0] * 7
        for ch in s:
            features[ord(ch) - ord('A')] = 1
        test_data.append(features)

    w = [0.0] * 7
    b = 0.0
    lr = 0.1

    for epoch in range(20):
        for features, label in train_data:
            z = sum(w[i] * features[i] for i in range(7)) + b
            if z >= 0:
                pred = 1.0 / (1.0 + math.exp(-z))
            else:
                ez = math.exp(z)
                pred = ez / (1.0 + ez)
            error = pred - label
            for i in range(7):
                w[i] -= lr * error * features[i]
            b -= lr * error

    for features in test_data:
        z = sum(w[i] * features[i] for i in range(7)) + b
        if z >= 0:
            pred = 1.0 / (1.0 + math.exp(-z))
        else:
            ez = math.exp(z)
            pred = ez / (1.0 + ez)
        print(1 if pred > 0.5 else 0)

solve()