大模型应用:大模型时代的XGBoost:传统梯度提升树与大模型的协同应用.103

简介: 本文详解XGBoost与大模型融合方法:利用大模型提取文本等非结构化数据的语义Embedding,与XGBoost处理的结构化特征拼接建模,兼顾高精度、强可解释性与语义理解能力,显著提升预测性能。

一、前言

       在人工智能技术体系中,XGBoost作为经典的梯度提升树模型,凭借高效的特征学习能力和优秀的结构化数据处理性能,长期占据机器学习应用的核心地位;而大模型则以其强大的语义理解、上下文建模和通用推理能力,成为自然语言处理、多模态分析等领域的颠覆性技术。将XGBoost与大模型结合,既能发挥XGBoost在结构化数据建模上的精准性和可解释性,又能借助大模型处理非结构化数据(文本、语音、图像)的优势,构建更全面、更强大的 AI 系统,今天我们由浅入深拆解 XGBoost 与大模型融合的全链路知识,深度了解其核心原理和应用实践。

103.2-大模型时代的XGBoost融合2.jpg

二、基础知识

1. XGBoost 核心概念

1.1 梯度提升树(GBT)基础

       梯度提升树是集成学习的核心分支,其核心思想是“逐步修正错误”:通过串行训练多个弱分类器,通常是决策树,每个新的弱分类器都专注于修正前一轮模型的预测误差,最终将所有弱分类器的预测结果加权求和,得到强分类器。

举个通俗的例子,假设我们要预测一个商品的销量:

  • 第一个决策树根据“价格”特征预测销量为1000件,但实际销量是1200件,误差为200 件;
  • 第二个决策树则专门学习“价格 + 促销活动”特征来修正这200件的误差,预测补充值为180件;
  • 第三个决策树再学习“价格 + 促销 + 季节”特征修正剩余20件误差,最终三个树的结果相加得到精准预测。

1.2 XGBoost 的核心优势

XGBoost是梯度提升树的优化版本,相比传统 GBT,其核心优势体现在:

  • 1. 正则化优化:在损失函数中加入 L1(Lasso)和 L2(Ridge)正则项,有效防止过拟合;
  • 2. 并行化训练:在构建决策树时,对特征的分裂点选择进行并行计算,大幅提升训练速度;
  • 3. 缺失值处理:自动学习缺失值的最优分裂方向,无需手动填充;
  • 4. 预排序与直方图优化:支持预排序和直方图两种分裂策略,平衡精度与效率;
  • 5. 剪枝策略:采用 “贪心 + 正则” 的剪枝方式,从叶子节点向上剪枝,保留最优树结构。

1.3 XGBoost 的关键参数

掌握以下核心参数是使用 XGBoost 的基础:

  • n_estimators:弱学习器数量,常用值100-1000
  • max_depth:决策树最大深度,常用值3-10
  • learning_rate:学习率,即步长,常用值0.01-0.3
  • subsample:样本采样比例,常用值0.7-1.0
  • colsample_bytree:特征采样比例,常用值0.7-1.0
  • reg_alpha:L1 正则化系数,常用值0-10
  • reg_lambda:L2 正则化系数,常用值1-10
  • objective:目标函数,常用值的分类函数:binary:logistic/multi:softmax;回归函数:reg:squarederror

2. XGBoost 与大模型结合

2.1 大模型的核心痛点

尽管大模型能力强大,但在实际应用中存在明显短板:

  • 1. 结构化数据处理能力弱:大模型擅长处理文本类非结构化数据,但对表格、数值型结构化数据的建模能力远不如XGBoost;
  • 2. 计算成本高:训练和推理大模型需要昂贵的GPU/TPU资源,单条推理成本远高于传统机器学习模型;
  • 3. 可解释性差:大模型的黑箱特性导致其预测结果难以解释,无法满足金融、医疗等领域的合规要求;
  • 4. 过拟合特定模式:在小样本、强规律的结构化数据任务中,大模型的泛化能力不如XGBoost;
  • 5. 数值计算精度低:大模型对数值的精准计算能力弱,无法替代传统模型完成高精度的回归、分类任务。

2.2 结合的核心逻辑

将 XGBoost 与大模型结合,本质是扬长避短、优势互补:

  • 大模型负责处理非结构化数据,如用户评论、商品描述、文档内容,将其转化为高质量的语义特征(Embedding);
  • XGBoost负责处理结构化数据(如用户年龄、商品价格、交易金额)+ 大模型输出的语义特征,完成精准的预测或分类任务;
  • 同时,XGBoost 的可解释性可以弥补大模型黑箱的缺陷,大模型的语义理解能力可以拓展 XGBoost 的特征维度。

103.3-融合方案vs单一模型性能对比 model_performance_comparison.png

举个实际场景:电商平台的用户购买预测;

  • 大模型将用户的历史评论、商品标题、客服对话转化为语义 Embedding;
  • XGBoost 结合用户的消费金额、购买频次、商品类别等结构化数据,以及大模型输出的 Embedding 特征;最终预测用户是否会购买某商品。
  • 这种融合方案的准确率远高于单独使用 XGBoost,缺少语义特征,也高于单独使用大模型,因为大模型的数值建模能力弱。

三、融合的核心原理

1. 特征融合原理

XGBoost 与大模型的融合本质是特征级融合,核心步骤为:

  • 1. 特征提取:
  • 结构化数据:直接提取数值型 / 类别型特征(如年龄、性别、价格),类别型特征需进行编码(One-Hot/Label Encoding);
  • 非结构化数据:通过大模型提取 Sentence Embedding,转化为固定维度的数值向量(如 768 维)。
  • 2. 特征拼接:将结构化特征向量与大模型输出的 Embedding 向量拼接,形成融合特征矩阵;
  • 3. 特征训练:将融合特征矩阵输入 XGBoost,利用 XGBoost 的梯度提升机制进行训练,得到最终模型。

103.4-XGBoost融合模型特征重要性分层分析 feature_importance_stratified.png

这种融合方式的优势在于:

  • 保留了结构化数据的精准数值信息;
  • 融入了非结构化数据的语义信息;
  • XGBoost 能够自动学习不同特征的重要性,权重高的特征会被优先分裂。

2. 模型互补原理

XGBoost 与大模型的互补性体现在多个维度:

维度 XGBoost 大模型 融合优势
数据类型 擅长结构化数据 擅长非结构化数据 同时处理两类数据
可解释性 高(特征重要性、决策路径) 低(黑箱) 用 XGBoost 提升整体可解释性
计算成本 低(CPU 即可训练) 高(需 GPU) 仅用大模型做 Embedding 提取,降低整体成本
数值精度 高(精准拟合数值规律) 低(数值计算误差大) 用 XGBoost 保证预测精度
语义理解 无(无法处理文本语义) 高(强语义建模) 用大模型拓展特征维度

3. 数据一致性处理

在实际融合过程中,会遇到一些数据匹配度的问题,以下提供了一些常规的解决方案:

3.1特征维度匹配

  • 大模型输出的 Embedding 维度通常较高,如768维,而结构化特征维度较低,如几十维,可能导致特征分布不均衡。
  • 解决方案:对 Embedding 进行降维(PCA/TSNE)或特征选择(如基于方差的筛选);

3.2 特征尺度差异

  • 结构化特征(如年龄:0-100)与 Embedding 特征(如 - 1~1 之间的浮点数)尺度差异大,可能影响 XGBoost 的分裂决策。
  • 解决方案:对所有特征进行标准化、归一化;

3.3 过拟合风险

  • 高维度的 Embedding 特征可能导致XGBoost过拟合。
  • 解决方案:增加 XGBoost 的正则化参数(reg_alpha/reg_lambda)、降低树深度(max_depth)、使用早停(early stopping);

3.4. Embedding 一致性

  • 不同批次的文本输入大模型,可能输出分布略有差异的 Embedding,导致 XGBoost 模型泛化能力下降。
  • 解决方案:对大模型的 Embedding 进行归一化(L2 归一化),保证向量长度一致。

四、融合的执行流程

1. 执行流程

XGBoost 与大模型融合的完整执行流程可分为 6 个核心步骤:

103.5-XGBoost与大模型融合的完整执行流程 deepseek_mermaid_20260301_b07b56.png

2. 分步详解

步骤 1:数据收集

数据收集是融合模型的基础,需要同时收集两类数据:

2.1 结构化数据:

  • 数值型:如用户年龄、消费金额、商品价格、交易次数、评分等;
  • 类别型:如用户性别、商品类别、地区、支付方式等;
  • 时间型:如购买时间、注册时间、活动时间等(需转化为数值特征,如时间差、小时 / 天 / 月等)。

示例结构化数据集(电商用户购买预测):

用户 ID 年龄 性别 消费金额 购买频次 商品类别 评分 是否购买(标签)
1001 25 500 10 电子产品 4.5 1
1002 32 1200 25 美妆 4.8 1
1003 45 800 5 服装 3.2 0

2. 非结构化数据:

  • 文本型:如用户评论(“这款手机续航太差了”)、商品标题(“2024 新款华为 Mate60 Pro 12GB+512GB”)、客服对话、用户画像描述等;
  • 其他类型:如商品图片,可通过视觉大模型转化为 Embedding、用户语音,可通过语音大模型转化为文本再提取 Embedding。

示例非结构化数据(对应上述结构化数据):

用户 ID 用户评论 商品标题
1001 这款手机性能很好,值得购买 2024 新款华为 Mate60 Pro 12GB+512GB
1002 这款粉底液遮瑕效果超棒,推荐! 兰蔻持妆粉底液 PO-01 30ml
1003 这件衣服尺码偏小,材质一般 优衣库男士纯棉 T 恤 458762

步骤 2:数据预处理

预处理的目标是将原始数据转化为模型可处理的格式,分为两部分:

1. 结构化数据预处理:

  • 缺失值处理:数值型特征用均值、中位数、众数填充,类别型特征用“未知”填充或基于业务逻辑填充;
  • 类别特征编码:二分类特征(如性别)用Label Encoding(0/1),多分类特征(如商品类别)用 One-Hot Encoding或Target Encoding;
  • 数值特征归一化:对数值型特征进行标准化(Z-Score)或归一化(Min-Max),使特征尺度统一;
  • 时间特征转化:将时间戳转化为小时、天、周、月、季度等特征,或计算时间差。

2. 非结构化数据预处理:

  • 文本清洗:去除特殊字符、标点、多余空格,统一大小写,纠正错别字;
  • 分词:将文本拆分为单词、中文分词,如使用Jieba分词;
  • 去停用词:去除无意义的词汇,如“的”、“了”、“a”、“the”;
  • 文本长度统一:对过长、过短的文本进行截断、补全,保证输入大模型的文本长度一致。

步骤 3:大模型 Embedding 提取

这是融合的核心步骤,目标是将文本转化为语义Embedding:

1. 选择合适的大模型:

  • 开源模型:LLaMA2、ChatGLM、Qwen等,适合本地部署;
  • 闭源 API:OpenAI Embedding、通义Embedding 等,适合快速开发。
  • 推荐使用开源的 BERT-base 模型,中文的为bert-base-chinese,参数量小(110M),部署成本低,Embedding效果好。

2. Embedding 提取流程:

  • 加载预训练大模型和 Tokenizer;
  • 将预处理后的文本输入 Tokenizer,转化为模型可识别的 token;
  • 将 token 输入大模型,获取输出的 Hidden States;
  • 对 Hidden States 进行池化,如均值池化、最大值池化、[CLS] token等,得到 Sentence Embedding;
  • 对 Embedding 进行 L2 归一化,保证向量长度为 1,提升稳定性。

3. Embedding 降维:

  • 如果 Embedding 维度过高,如768维,可使用 PCA 进行降维,保留 95% 以上的方差,减少特征维度,提升 XGBoost 训练速度。

103.6-大模型Embedding降维可视化 embedding_visual.png

步骤 4:特征融合

特征融合的目标是将结构化特征与 Embedding 特征结合:

  • 1. 特征拼接:将预处理后的结构化特征矩阵(n_samples × n_structured_features)与 Embedding 特征矩阵(n_samples × n_embedding_features)按列拼接,得到融合特征矩阵(n_samples × (n_structured_features + n_embedding_features));
  • 2. 特征选择:
  • 方差筛选:去除方差过小的特征,如全部为0的特征;
  • 相关性筛选:计算特征与标签的相关性,去除相关性极低的特征;
  • 递归特征消除(RFE):使用 XGBoost 的特征重要性,递归去除不重要的特征;
  • 3. 特征验证:检查融合后的特征是否存在缺失值、异常值,确保数据质量。

103.7-融合模型特征重要性 feature_importance.png

步骤 5:XGBoost 模型训练

这一步是传统 XGBoost 的训练流程,但需要针对融合特征进行参数调优:

  • 1. 数据集划分:将融合特征矩阵按 7:2:1 的比例划分为训练集、验证集、测试集;
  • 2. 参数初始化:设置 XGBoost 的基础参数,如n_estimators=100、max_depth=5、learning_rate=0.1;
  • 3. 模型训练:使用训练集训练模型,验证集监控过拟合,通过早停策略:当验证集损失连续 n 轮不下降时停止训练;
  • 4. 参数调优:使用网格搜索、随机搜索、贝叶斯优化调优核心参数,如max_depth、learning_rate、reg_alpha、reg_lambda,提升模型性能;
  • 5. 模型保存:将训练好的 XGBoost 模型保存为文件,如 JSON/PMML 格式,方便后续部署。

103.8-XGBoost 训练曲线(含早停) training_curve.png

步骤 6:模型评估与部署

1. 模型评估:

  • 分类任务:计算准确率(ACC)、精确率(Precision)、召回率(Recall)、F1 值、AUC-ROC 等指标;
  • 回归任务:计算均方误差(MSE)、平均绝对误差(MAE)、R² 等指标;
  • 可解释性分析:输出 XGBoost 的特征重要性,分析哪些特征对预测结果影响最大,包括结构化特征和 Embedding 特征;
  • 对比实验:与单独使用 XGBoost(无 Embedding)、单独使用大模型直接预测的结果对比,验证融合方案的优势。

2. 模型部署:

  • 离线部署:将模型集成到批处理系统中,处理离线数据;
  • 在线部署:搭建 API 服务,如 FastAPI/Flask,接收结构化特征和文本数据,实时提取 Embedding 并调用 XGBoost 模型预测;
  • 性能优化:对 Embedding 提取过程进行缓存,对 XGBoost 模型进行量化,提升在线推理速度。

流程简化总结:

103.9-XGBoost 与大模型融合的简单执行流程 deepseek_mermaid_20260301_6274ae.png

五、完整实例实现

步骤 1:导入库

import os
import re
import numpy as np
import pandas as pd
import jieba
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.decomposition import PCA
from sklearn.metrics import accuracy_score, classification_report, roc_auc_score, confusion_matrix
from sklearn.feature_selection import VarianceThreshold
import xgboost as xgb
from xgboost import callback as xgb_callback
from transformers import BertTokenizer, BertModel
import torch
import warnings
warnings.filterwarnings('ignore')
# 设置中文字体(解决matplotlib中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 设置设备(优先使用GPU)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"使用设备:{device}")

image.gif

输出结果:

使用设备:cpu

步骤 2:数据准备与预处理

# ====================== 1. 生成示例数据(电商用户购买预测) ======================
def generate_sample_data():
    """生成示例结构化数据和文本数据"""
    # 结构化数据
    structured_data = pd.DataFrame({
        'user_id': range(1000, 1500),
        'age': np.random.randint(18, 60, size=500),
        'gender': np.random.choice(['男', '女'], size=500, p=[0.5, 0.5]),
        'consumption_amount': np.random.normal(1000, 300, size=500).round(2),
        'purchase_frequency': np.random.randint(1, 30, size=500),
        'product_category': np.random.choice(['电子产品', '美妆', '服装', '食品', '家居'], size=500),
        'rating': np.random.uniform(1, 5, size=500).round(1),
        'is_purchase': np.random.choice([0, 1], size=500, p=[0.4, 0.6])
    })
    
    # 文本数据(用户评论 + 商品标题)
    comments = [
        "这款产品性能很好,值得购买",
        "质量一般,价格偏高",
        "使用体验很棒,推荐!",
        "物流很慢,包装破损",
        "性价比超高,会回购",
        "尺寸不合适,材质差",
        "比预期的好,满意",
        "售后服务差,不推荐"
    ]
    
    product_titles = [
        "2024新款华为Mate60 Pro 12GB+512GB",
        "兰蔻持妆粉底液PO-01 30ml",
        "优衣库男士纯棉T恤458762",
        "三只松鼠坚果大礼包1500g",
        "小米空气净化器4 Pro",
        "美的电饭煲5L大容量",
        "苹果AirPods Pro 2代",
        "Nike Air Max 270运动鞋"
    ]
    
    text_data = pd.DataFrame({
        'user_id': range(1000, 1500),
        'user_comment': np.random.choice(comments, size=500),
        'product_title': np.random.choice(product_titles, size=500)
    })
    
    # 合并文本数据(将评论和标题拼接)
    text_data['combined_text'] = text_data['user_comment'] + " " + text_data['product_title']
    
    # 合并结构化数据和文本数据
    data = pd.merge(structured_data, text_data, on='user_id')
    
    return data
# 生成数据
data = generate_sample_data()
print("数据基本信息:")
print(data.info())
print("\n数据前5行:")
print(data.head())

image.gif

输出结果:

数据基本信息:

RangeIndex: 500 entries, 0 to 499

Data columns (total 11 columns):

#   Column              Non-Null Count  Dtype

---  ------              --------------  -----

0   user_id             500 non-null    int64

1   age                 500 non-null    int32

2   gender              500 non-null    str

3   consumption_amount  500 non-null    float64

4   purchase_frequency  500 non-null    int32

5   product_category    500 non-null    str

6   rating              500 non-null    float64

7   is_purchase         500 non-null    int64

8   user_comment        500 non-null    str

9   product_title       500 non-null    str

10  combined_text       500 non-null    str

dtypes: float64(2), int32(2), int64(2), str(5)

memory usage: 100.2 KB

None

数据前5行:

  user_id  age gender  consumption_amount  ...  is_purchase user_comment        product_title                  combined_text      

0     1000   36      男             1508.83  ...            1    物流很慢,包装破损  Nike Air Max 270运动鞋  物流很慢,包装破损 Nike Air Max 270运动鞋

1     1001   50      女              370.92  ...            1    售后服务差,不推荐  Nike Air Max 270运动鞋  售后服务差,不推荐 Nike Air Max 270运动鞋

2     1002   22      男              451.52  ...            0    尺寸不合适,材质差     苹果AirPods Pro 2代     尺寸不合适,材质差  苹果AirPods Pro 2代

3     1003   55      女              716.35  ...            0    质量一般,价格偏高         小米空气净化器4 Pro         质量一般,价格偏高 小米空气净化器4 Pro

4     1004   53      男             1442.72  ...            0    尺寸不合适,材质差       三只松鼠坚果大礼包1500g       尺寸不合适,材质差 三只松鼠坚果大礼包1500g

[5 rows x 11 columns]

步骤 3:大模型 Embedding 提取

# ====================== 2. 结构化数据预处理 ======================
print("====================== 2. 结构化数据预处理 ======================")
def preprocess_structured_data(data):
    """预处理结构化数据"""
    # 分离特征和标签
    X_structured = data[['age', 'gender', 'consumption_amount', 'purchase_frequency', 'product_category', 'rating']]
    y = data['is_purchase']
    
    # 定义数值特征和类别特征
    numeric_features = ['age', 'consumption_amount', 'purchase_frequency', 'rating']
    categorical_features = ['gender', 'product_category']
    
    # 数值特征处理管道:缺失值填充 + 标准化
    numeric_transformer = Pipeline(steps=[
        ('imputer', SimpleImputer(strategy='median')),  # 中位数填充缺失值
        ('scaler', StandardScaler())  # 标准化
    ])
    
    # 类别特征处理管道:缺失值填充 + One-Hot编码
    categorical_transformer = Pipeline(steps=[
        ('imputer', SimpleImputer(strategy='most_frequent')),  # 众数填充缺失值
        ('onehot', OneHotEncoder(handle_unknown='ignore'))  # One-Hot编码,忽略未知类别
    ])
    
    # 组合预处理管道
    preprocessor = ColumnTransformer(
        transformers=[
            ('num', numeric_transformer, numeric_features),
            ('cat', categorical_transformer, categorical_features)
        ])
    
    # 执行预处理
    X_structured_processed = preprocessor.fit_transform(X_structured)
    # 转换为DataFrame(方便后续拼接)
    # 获取特征名称
    num_feature_names = numeric_features
    cat_feature_names = preprocessor.named_transformers_['cat'].named_steps['onehot'].get_feature_names_out(categorical_features)
    feature_names = list(num_feature_names) + list(cat_feature_names)
    # 根据输出类型选择合适的转换方式
    if hasattr(X_structured_processed, 'toarray'):
        X_structured_df = pd.DataFrame(X_structured_processed.toarray(), columns=feature_names)
    else:
        X_structured_df = pd.DataFrame(X_structured_processed, columns=feature_names)
    
    return X_structured_df, y, preprocessor
# 预处理结构化数据
X_structured, y, structured_preprocessor = preprocess_structured_data(data)
print("\n预处理后的结构化特征:")
print(X_structured.head())
print(f"\n结构化特征形状:{X_structured.shape}")
# ====================== 3. 文本数据预处理 ======================
def preprocess_text(text):
    """预处理单条文本"""
    # 去除特殊字符
    text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\s]', '', text)
    # 分词
    words = jieba.lcut(text)
    # 去停用词(简单停用词表)
    stopwords = ['的', '了', '是', '我', '你', '他', '她', '它', '在', '有', '就', '都', '和', '与', '及', 'a', 'an', 'the']
    words = [word for word in words if word not in stopwords and len(word) > 0]
    # 拼接为字符串
    processed_text = ' '.join(words)
    return processed_text
# 预处理所有文本
data['processed_text'] = data['combined_text'].apply(preprocess_text)
print("\n预处理后的文本示例:")
print(data[['combined_text', 'processed_text']].head())

image.gif

输出结果:

预处理后的结构化特征:

       age  consumption_amount  purchase_frequency  ...  product_category_电子产品  product_category_美妆  product_category_食品

0 -0.198386          1.565593            0.142051  ...              1.0                  0.0                  0.0

1  0.968590         -2.000561            0.866802  ...              0.0                  1.0                  0.0

2 -1.365362         -1.747964           -0.945075  ...             0.0                  0.0                  0.0

3  1.385368         -0.918000            1.591552  ...              0.0                  0.0                  1.0

4  1.218657          1.358407           -0.945075  ...              0.0                  0.0                  0.0

[5 rows x 11 columns]

结构化特征形状:(500, 11)

Building prefix dict from the default dictionary ...

Loading model from cache C:\Users\Admin\AppData\Local\Temp\jieba.cache

Loading model cost 0.387 seconds.

Prefix dict has been built successfully.

预处理后的文本示例:

                  combined_text                             processed_text

0  物流很慢,包装破损 Nike Air Max 270运动鞋  物流 很 慢 包装 破损   Nike   Air   Max   270 运动鞋

1  售后服务差,不推荐 Nike Air Max 270运动鞋   售后服务 差 不 推荐   Nike   Air   Max   270 运动鞋

2     尺寸不合适,材质差 苹果AirPods Pro 2代      尺寸 不 合适 材质 差   苹果 AirPods   Pro   2 代

3         质量一般,价格偏高 小米空气净化器4 Pro            质量 一般 价格 偏高   小米 空气 净化器 4   Pro

4       尺寸不合适,材质差 三只松鼠坚果大礼包1500g          尺寸 不 合适 材质 差   三只 松鼠 坚果 大礼包 1500g

步骤 4:XGBoost 模型训练与评估

class BertEmbeddingExtractor:
    """BERT Embedding提取器"""
    def __init__(self, model_name='bert-base-chinese'):
        self.tokenizer = BertTokenizer.from_pretrained(model_name)
        self.model = BertModel.from_pretrained(model_name).to(device)
        self.model.eval()  # 设置为评估模式
    
    def get_embedding(self, text, max_length=32):
        """提取单条文本的Embedding"""
        # 编码文本
        inputs = self.tokenizer(
            text,
            max_length=max_length,
            padding='max_length',
            truncation=True,
            return_tensors='pt'
        ).to(device)
        
        # 前向传播(不计算梯度)
        with torch.no_grad():
            outputs = self.model(**inputs)
        
        # 获取最后一层的Hidden States
        last_hidden_state = outputs.last_hidden_state  # [1, max_length, 768]
        
        # 均值池化得到句子Embedding
        embedding = torch.mean(last_hidden_state, dim=1).squeeze(0)  # [768]
        
        # L2归一化
        embedding = torch.nn.functional.normalize(embedding, p=2, dim=0)
        
        return embedding.cpu().numpy()
    
    def batch_get_embedding(self, texts, batch_size=32):
        """批量提取Embedding"""
        embeddings = []
        for i in range(0, len(texts), batch_size):
            batch_texts = texts[i:i+batch_size]
            
            # 批量编码
            inputs = self.tokenizer(
                batch_texts,
                max_length=32,
                padding='max_length',
                truncation=True,
                return_tensors='pt'
            ).to(device)
            
            # 前向传播
            with torch.no_grad():
                outputs = self.model(**inputs)
            
            # 均值池化
            batch_embeddings = torch.mean(outputs.last_hidden_state, dim=1)  # [batch_size, 768]
            # L2归一化
            batch_embeddings = torch.nn.functional.normalize(batch_embeddings, p=2, dim=1)
            
            embeddings.extend(batch_embeddings.cpu().numpy())
        
        return np.array(embeddings)
# 初始化Embedding提取器
embedding_extractor = BertEmbeddingExtractor()
# 提取文本Embedding
print("\n开始提取文本Embedding...")
texts = data['processed_text'].tolist()
X_embedding = embedding_extractor.batch_get_embedding(texts)
# Embedding降维(PCA)
print(f"\n原始Embedding形状:{X_embedding.shape}")
pca = PCA(n_components=0.95)  # 保留95%的方差
X_embedding_pca = pca.fit_transform(X_embedding)
print(f"降维后的Embedding形状:{X_embedding_pca.shape}")
# 转换为DataFrame
embedding_feature_names = [f'embedding_{i}' for i in range(X_embedding_pca.shape[1])]
X_embedding_df = pd.DataFrame(X_embedding_pca, columns=embedding_feature_names)
# ====================== 4. 特征融合 ======================
# 拼接结构化特征和Embedding特征
X_combined = pd.concat([X_structured.reset_index(drop=True), X_embedding_df.reset_index(drop=True)], axis=1)
# 特征选择:去除方差过小的特征
variance_selector = VarianceThreshold(threshold=0.01)
X_combined_selected = variance_selector.fit_transform(X_combined)
# 获取选择后的特征名称
selected_feature_indices = variance_selector.get_support(indices=True)
selected_feature_names = [X_combined.columns[i] for i in selected_feature_indices]
print(f"\n融合后的特征形状(原始):{X_combined.shape}")
print(f"融合后的特征形状(特征选择后):{X_combined_selected.shape}")
print(f"选择后的特征数量:{len(selected_feature_names)}")
# 转换为DataFrame
X_combined_df = pd.DataFrame(X_combined_selected, columns=selected_feature_names)

image.gif

输出结果:

Loading weights: 100%|████████████████████████████████| 199/199 [00:00<00:00, 4484.75it/s, Materializing param=pooler.dense.weight]

BertModel LOAD REPORT from: bert-base-chinese

Key                                        | Status     |  |

-------------------------------------------+------------+--+-

cls.predictions.transform.LayerNorm.bias   | UNEXPECTED |  |

cls.seq_relationship.bias                  | UNEXPECTED |  |

cls.seq_relationship.weight                | UNEXPECTED |  |

cls.predictions.transform.dense.weight     | UNEXPECTED |  |

cls.predictions.transform.dense.bias       | UNEXPECTED |  |

cls.predictions.transform.LayerNorm.weight | UNEXPECTED |  |

cls.predictions.bias                       | UNEXPECTED |  |

Notes:

- UNEXPECTED    :can be ignored when loading from different task/architecture; not ok if you expect identical arch.

开始提取文本Embedding...

原始Embedding形状:(500, 768)

降维后的Embedding形状:(500, 16)

融合后的特征形状(原始):(500, 27)

融合后的特征形状(特征选择后):(500, 16)

选择后的特征数量:16

步骤 5:在线推理示例

# ====================== 1. 划分数据集 ======================
X_train, X_test, y_train, y_test = train_test_split(
    X_combined_df, y, test_size=0.2, random_state=42, stratify=y
)
X_train, X_val, y_train, y_val = train_test_split(
    X_train, y_train, test_size=0.25, random_state=42, stratify=y_train
)
print(f"\n训练集形状:{X_train.shape}")
print(f"验证集形状:{X_val.shape}")
print(f"测试集形状:{X_test.shape}")
# ====================== 2. 定义XGBoost模型 ======================
# 设置参数
xgb_params = {
    'objective': 'binary:logistic',  # 二分类任务
    'max_depth': 5,                  # 树最大深度
    'learning_rate': 0.1,            # 学习率
    'n_estimators': 200,             # 树的数量
    'subsample': 0.8,                # 样本采样比例
    'colsample_bytree': 0.8,         # 特征采样比例
    'reg_alpha': 0.1,                # L1正则化
    'reg_lambda': 1,                 # L2正则化
    'eval_metric': 'auc',            # 评估指标
    'seed': 42,                      # 随机种子
    'verbosity': 1                   # 输出日志级别
}
# 初始化模型
model = xgb.XGBClassifier(**xgb_params)
# ====================== 3. 训练模型 ======================
print("\n开始训练XGBoost模型...")
model.fit(X_train, y_train, verbose=True)
# ====================== 4. 模型评估 ======================
# 预测
y_pred = model.predict(X_test)
y_pred_proba = model.predict_proba(X_test)[:, 1]
# 计算评估指标
accuracy = accuracy_score(y_test, y_pred)
auc = roc_auc_score(y_test, y_pred_proba)
classification_rep = classification_report(y_test, y_pred)
print("\n====================== 模型评估结果 ======================")
print(f"准确率(ACC):{accuracy:.4f}")
print(f"AUC-ROC:{auc:.4f}")
print("\n分类报告:")
print(classification_rep)
# ====================== 5. 特征重要性分析 ======================
# 获取特征重要性
feature_importance = model.get_booster().get_score(importance_type='weight')
# 转换为DataFrame
feature_importance_df = pd.DataFrame({
    'feature': list(feature_importance.keys()),
    'importance': list(feature_importance.values())
})
# 按重要性排序
feature_importance_df = feature_importance_df.sort_values('importance', ascending=False).head(20)
# 绘制特征重要性图
plt.figure(figsize=(12, 8))
sns.barplot(x='importance', y='feature', data=feature_importance_df)
plt.title('XGBoost特征重要性(Top 20)', fontsize=14)
plt.xlabel('重要性得分', fontsize=12)
plt.ylabel('特征名称', fontsize=12)
plt.tight_layout()
plt.savefig('feature_importance.png', dpi=300)
plt.show()
# ====================== 6. 混淆矩阵 ======================
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', 
            xticklabels=['未购买', '购买'], 
            yticklabels=['未购买', '购买'])
plt.title('混淆矩阵', fontsize=14)
plt.xlabel('预测标签', fontsize=12)
plt.ylabel('真实标签', fontsize=12)
plt.tight_layout()
plt.savefig('confusion_matrix.png', dpi=300)
plt.show()
# ====================== 7. 对比实验(仅使用结构化特征) ======================
print("\n====================== 对比实验:仅使用结构化特征 ======================")
# 仅使用结构化特征训练XGBoost
X_train_struct = X_train[X_structured.columns] if set(X_structured.columns).issubset(X_train.columns) else X_train.iloc[:, :len(X_structured.columns)]
X_test_struct = X_test[X_structured.columns] if set(X_structured.columns).issubset(X_test.columns) else X_test.iloc[:, :len(X_structured.columns)]
# 训练模型
model_struct = xgb.XGBClassifier(**xgb_params)
model_struct.fit(X_train_struct, y_train, verbose=False)
# 评估
y_pred_struct = model_struct.predict(X_test_struct)
y_pred_proba_struct = model_struct.predict_proba(X_test_struct)[:, 1]
accuracy_struct = accuracy_score(y_test, y_pred_struct)
auc_struct = roc_auc_score(y_test, y_pred_proba_struct)
print(f"仅结构化特征 - 准确率(ACC):{accuracy_struct:.4f}")
print(f"仅结构化特征 - AUC-ROC:{auc_struct:.4f}")
print(f"\n融合模型 vs 仅结构化特征:")
print(f"准确率提升:{(accuracy - accuracy_struct)*100:.2f}%")
print(f"AUC提升:{(auc - auc_struct)*100:.2f}%")
# ====================== 8. 保存模型 ======================
# 保存XGBoost模型
model.save_model('xgboost_llm_fusion.model')
print("\n模型已保存为:xgboost_llm_fusion.model")
# 保存特征名称
with open('feature_names.txt', 'w', encoding='utf-8') as f:
    for name in selected_feature_names:
        f.write(f"{name}\n")
class XGBoostLLMFusionInference:
    """XGBoost+大模型融合推理类"""
    def __init__(self, model_path, feature_names_path, embedding_extractor, structured_preprocessor):
        # 加载模型
        self.model = xgb.XGBClassifier()
        self.model.load_model(model_path)
        
        # 加载特征名称
        with open(feature_names_path, 'r', encoding='utf-8') as f:
            self.feature_names = [line.strip() for line in f.readlines()]
        
        # Embedding提取器
        self.embedding_extractor = embedding_extractor
        
        # 结构化数据预处理器
        self.structured_preprocessor = structured_preprocessor
        
        # PCA模型(这里简化,实际应保存训练好的PCA模型)
        self.pca = pca
    
    def preprocess_input(self, structured_data, text):
        """预处理输入数据"""
        # 1. 预处理结构化数据
        structured_df = pd.DataFrame([structured_data])
        structured_processed = self.structured_preprocessor.transform(structured_df)
        # 根据输出类型选择合适的转换方式
        if hasattr(structured_processed, 'toarray'):
            structured_df_processed = pd.DataFrame(structured_processed.toarray(),
                                                  columns=self.structured_preprocessor.get_feature_names_out())
        else:
            structured_df_processed = pd.DataFrame(structured_processed,
                                                  columns=self.structured_preprocessor.get_feature_names_out())
        # 2. 预处理文本并提取Embedding
        processed_text = preprocess_text(text)
        embedding = self.embedding_extractor.get_embedding(processed_text)
        embedding_pca = self.pca.transform([embedding])
        # 3. 特征融合
        embedding_df = pd.DataFrame(embedding_pca, columns=[f'embedding_{i}' for i in range(embedding_pca.shape[1])])
        combined_df = pd.concat([structured_df_processed, embedding_df], axis=1)
        # 4. 确保所有需要的特征都存在,缺失的填充为0
        for col in self.feature_names:
            if col not in combined_df.columns:
                combined_df[col] = 0
        # 5. 选择模型训练时的特征
        combined_df = combined_df[self.feature_names]
        return combined_df
    
    def predict(self, structured_data, text):
        """预测"""
        # 预处理输入
        input_data = self.preprocess_input(structured_data, text)
        
        # 预测
        pred_proba = self.model.predict_proba(input_data)[0]
        pred_label = self.model.predict(input_data)[0]
        
        return {
            'pred_label': int(pred_label),
            'pred_prob': float(pred_proba[1]),
            'label_name': '购买' if pred_label == 1 else '未购买'
        }
# 初始化推理类
inference = XGBoostLLMFusionInference(
    model_path='xgboost_llm_fusion.model',
    feature_names_path='feature_names.txt',
    embedding_extractor=embedding_extractor,
    structured_preprocessor=structured_preprocessor
)
# 示例推理
sample_structured_data = {
    'age': 28,
    'gender': '女',
    'consumption_amount': 1500.0,
    'purchase_frequency': 20,
    'product_category': '美妆',
    'rating': 4.8
}
sample_text = "这款粉底液遮瑕效果超棒,持妆久,推荐! 兰蔻持妆粉底液PO-01 30ml"
# 推理
result = inference.predict(sample_structured_data, sample_text)
print("\n====================== 在线推理示例 ======================")
print(f"输入结构化数据:{sample_structured_data}")
print(f"输入文本:{sample_text}")
print(f"预测结果:{result['label_name']}")
print(f"  - 购买概率:{result['pred_prob']:.4f} ({result['pred_prob']*100:.2f}%)")
print(f"  - 未购买概率:{1-result['pred_prob']:.4f} ({(1-result['pred_prob'])*100:.2f}%)")
# 测试多个样本
print("\n====================== 多样本对比测试 ======================")
test_cases = [
    {
        'structured': {'age': 35, 'gender': '女', 'consumption_amount': 2000.0, 'purchase_frequency': 25, 'product_category': '美妆', 'rating': 4.9},
        'text': "产品非常棒,会继续购买! 兰蔻持妆粉底液PO-01 30ml"
    },
    {
        'structured': {'age': 22, 'gender': '男', 'consumption_amount': 500.0, 'purchase_frequency': 2, 'product_category': '服装', 'rating': 2.5},
        'text': "质量太差,不建议购买 优衣库男士纯棉T恤458762"
    },
    {
        'structured': {'age': 45, 'gender': '女', 'consumption_amount': 3000.0, 'purchase_frequency': 15, 'product_category': '电子产品', 'rating': 4.5},
        'text': "性能出色,推荐购买 2024新款华为Mate60 Pro 12GB+512GB"
    }
]
for i, test_case in enumerate(test_cases, 1):
    pred = inference.predict(test_case['structured'], test_case['text'])
    print(f"\n样本{i}:")
    print(f"  预测: {pred['label_name']} (购买概率: {pred['pred_prob']:.4f})")
    print(f"  评论: {test_case['text']}")

image.gif

输出结果:

训练集形状:(300, 16)

验证集形状:(100, 16)

测试集形状:(100, 16)

开始训练XGBoost模型...

====================== 模型评估结果 ======================

准确率(ACC):0.6500

AUC-ROC:0.6419

分类报告:

             precision    recall  f1-score   support

          0       0.56      0.46      0.51        39

          1       0.69      0.77      0.73        61

   accuracy                           0.65       100

  macro avg       0.63      0.62      0.62       100

weighted avg       0.64      0.65      0.64       100

103.10-XGBoost特征重要性(Top 20) feature_importance.png

====================== 对比实验:仅使用结构化特征 ======================

仅结构化特征 - 准确率(ACC):0.5400

仅结构化特征 - AUC-ROC:0.5254

融合模型 vs 仅结构化特征:

准确率提升:11.00%

AUC提升:11.64%

模型已保存为:xgboost_llm_fusion.model

103.11-混淆矩阵  confusion_matrix.png

====================== 在线推理示例 ======================

输入结构化数据:{'age': 28, 'gender': '女', 'consumption_amount': 1500.0, 'purchase_frequency': 20, 'product_category': '美妆', 'rating': 4.8}

输入文本:这款粉底液遮瑕效果超棒,持妆久,推荐! 兰蔻持妆粉底液PO-01 30ml

预测结果:购买

 - 购买概率:0.9326 (93.26%)

 - 未购买概率:0.0674 (6.74%)

样本1:

 预测: 购买 (购买概率: 0.8819)

 评论: 产品非常棒,会继续购买! 兰蔻持妆粉底液PO-01 30ml

样本2:

 预测: 未购买 (购买概率: 0.3257)

 评论: 质量太差,不建议购买 优衣库男士纯棉T恤458762

样本3:

 预测: 购买 (购买概率: 0.9219)

 评论: 性能出色,推荐购买 2024新款华为Mate60 Pro 12GB+512GB

六、总结

       XGBoost 结合大模型核心就是两者优势互补,大模型搞定文本这类非结构化数据,提取语义特征,XGBoost 擅长结构化数据建模,把两者的特征结合起来,既解决了大模型处理数值差、成本高的问题,又弥补了 XGBoost 不懂语义的短板。传统模型和大模型不是替代关系,而是协同关系。以前总觉得大模型很高大上,传统模型过时了,现在才明白,能落地、能解决实际问题的组合才是最好的。整个学习过程不用死磕复杂公式,从原理到代码一步步来,就能慢慢理解。不管是学 XGBoost 还是大模型,打好基础、注重实战,比盲目追求高大上的技术更重要。

相关文章
|
5天前
|
人工智能 JSON 供应链
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
LucianaiB分享零成本畅用JVS Claw教程(学生认证享7个月使用权),并开源GeoMind项目——将JVS改造为科研与产业地理情报可视化AI助手,支持飞书文档解析、地理编码与腾讯地图可视化,助力产业关系图谱构建。
23324 3
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
|
14天前
|
缓存 人工智能 自然语言处理
我对比了8个Claude API中转站,踩了不少坑,总结给你
本文是个人开发者耗时1周实测的8大Claude中转平台横向评测,聚焦Claude Code真实体验:以加权均价(¥/M token)、内部汇率、缓存支持、模型真实性及稳定性为核心指标。
5086 25
|
10天前
|
人工智能 JSON BI
DeepSeek V4 来了!超越 Claude Sonnet 4.5,赶紧对接 Claude Code 体验一把
JeecgBoot AI专题研究 把 Claude Code 接入 DeepSeek V4Pro 的真实体验与避坑记录 本文记录我将 Claude Code 对接 DeepSeek 最新模型(V4Pro)后的真实体验,测试了 Skills 自动化查询和积木报表 AI 建表两个场景——有惊喜,也踩
3627 12
|
9天前
|
人工智能 缓存 BI
Claude Code + DeepSeek V4-Pro 真实评测:除了贵,没别的毛病
JeecgBoot AI专题研究 把 Claude Code 接入 DeepSeek V4Pro,跑完 Skills —— OA 审批、大屏、报表、部署 5 大实战场景后的真实体验 ![](https://oscimg.oschina.net/oscnet/up608d34aeb6bafc47f
2961 10
Claude Code + DeepSeek V4-Pro 真实评测:除了贵,没别的毛病
|
26天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
本文介绍了Claude Code终端AI助手的使用指南,主要内容包括:1)常用命令如版本查看、项目启动和更新;2)三种工作模式切换及界面说明;3)核心功能指令速查表,包含初始化、压缩对话、清除历史等操作;4)详细解析了/init、/help、/clear、/compact、/memory等关键命令的使用场景和语法。文章通过丰富的界面截图和场景示例,帮助开发者快速掌握如何通过命令行和交互界面高效使用Claude Code进行项目开发,特别强调了CLAUDE.md文件作为项目知识库的核心作用。
20860 63
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)

热门文章

最新文章