不使用SKlearn,用Python实现基于TF-IDF的应用类别多分类逻辑回归
不用Sklearn实现多分类逻辑回归(TF-IDF多标签分类)
嘿,咱们一步步来搞定不用Sklearn的多分类逻辑回归实现!我会把核心逻辑、代码落地,还有你可能碰到的坑都讲清楚。
1. 先搞定标签编码
多分类问题首先得把「健康」「社交」这类文本标签转成模型能识别的数值格式,one-hot编码是最常用的方式——每个标签对应一个独热向量,比如「健康」对应[1,0,0],「社交」对应[0,1,0]。
import numpy as np import pandas as pd # 假设你的DataFrame名为df,包含'data'(TF-IDF数组)和'labels'(类别标签)列 unique_labels = df['labels'].unique() label_to_idx = {label: idx for idx, label in enumerate(unique_labels)} num_classes = len(unique_labels) # 定义标签转独热向量的函数 def label_to_onehot(label): onehot = np.zeros(num_classes) onehot[label_to_idx[label]] = 1 return onehot # 转换标签为one-hot矩阵,同时把TF-IDF数组转成二维特征矩阵 y = np.array([label_to_onehot(label) for label in df['labels']]) X = np.array(df['data'].tolist()) # 确保X形状是(样本数, 特征数)
2. 实现多分类逻辑回归的核心函数
多分类逻辑回归依赖Softmax函数输出每个类别的概率(保证所有类别概率和为1),用交叉熵损失衡量预测值和真实值的差异,再通过梯度下降更新模型参数。
def softmax(z): # 减去每行最大值防止指数爆炸(数值稳定技巧) exp_z = np.exp(z - np.max(z, axis=1, keepdims=True)) return exp_z / np.sum(exp_z, axis=1, keepdims=True) def cross_entropy_loss(y_pred, y_true): # 加极小值避免log(0)报错 epsilon = 1e-10 return -np.sum(y_true * np.log(y_pred + epsilon)) / y_true.shape[0] def compute_gradients(X, y_true, y_pred): m = X.shape[0] # 权重梯度:(特征矩阵转置 @ 预测与真实值的差) / 样本数 dw = np.dot(X.T, (y_pred - y_true)) / m # 偏置梯度:预测与真实值的差的均值 db = np.sum(y_pred - y_true, axis=0) / m return dw, db
3. 模型训练流程
初始化权重和偏置,然后用梯度迭代更新参数:
def train_multinomial_logreg(X, y, learning_rate=0.01, epochs=1000): n_samples, n_features = X.shape n_classes = y.shape[1] # 小随机值初始化权重(避免梯度消失/爆炸),偏置初始化为0 np.random.seed(42) # 固定随机种子,方便结果复现 w = np.random.randn(n_features, n_classes) * 0.01 b = np.zeros(n_classes) loss_history = [] for epoch in range(epochs): # 前向传播:计算预测概率 z = np.dot(X, w) + b y_pred = softmax(z) # 计算并记录损失 loss = cross_entropy_loss(y_pred, y) loss_history.append(loss) # 反向传播:计算梯度 dw, db = compute_gradients(X, y, y_pred) # 更新参数 w -= learning_rate * dw b -= learning_rate * db # 每100轮打印一次损失,监控训练进度 if epoch % 100 == 0: print(f"Epoch {epoch:4d} | Loss: {loss:.4f}") return w, b, loss_history
4. 预测函数
训练完成后,用模型对新的TF-IDF数据做预测:
def predict(X, w, b): z = np.dot(X, w) + b y_pred = softmax(z) # 取概率最大的类别索引,再转回原标签 pred_idx = np.argmax(y_pred, axis=1) idx_to_label = {v: k for k, v in label_to_idx.items()} return [idx_to_label[idx] for idx in pred_idx]
你可能碰到的坑&解决办法
- TF-IDF数组形状错误:如果
X不是二维矩阵,检查df['data']里的每个元素是否是一维特征数组,用np.array(df['data'].tolist())强制转换 - 标签编码混乱:确保每个标签对应唯一索引,可打印
label_to_idx验证 - 损失不下降/震荡:调整学习率(比如从0.01改成0.1或0.001),或者增加训练轮数;也可以试试学习率衰减(比如每轮乘以0.99)
- 数值不稳定:Softmax里一定要加「减去每行最大值」的操作,否则大的指数值会导致溢出
快速测试
假设你有测试集的TF-IDF数组X_test,可以这样用:
# 训练模型(根据你的数据调整学习率和轮数) w, b, loss_history = train_multinomial_logreg(X, y, learning_rate=0.1, epochs=1500) # 预测测试数据 test_predictions = predict(X_test, w, b)
内容的提问来源于stack exchange,提问作者Yikai
相关产品推荐
相关产品推荐

