Combining LLM Embeddings with Tabular Features in a Unified Scikit-learn Pipeline
TL;DR · AI 摘要
本文展示如何将LLM生成的文本嵌入与表格特征整合到scikit-learn管道中,使用ColumnTransformer处理多类型数据并构建分类模型。
核心要点
- 使用Hugging Face的sentence-transformers库生成文本嵌入并向量化
- 通过ColumnTransformer并行处理文本、数值和分类特征
- 结合真实SMS数据集与合成表格特征构建用户分类场景
结构提纲
按章节快速跳转。
- §引言
介绍混合数据场景下构建统一机器学习管道的必要性
演示使用sentence-transformers库创建自定义scikit-learn转换器
通过ColumnTransformer并行处理文本、数值和分类特征
结合真实SMS数据与合成表格特征创建混合数据集
- ·管道部署
展示完整分类管道的评估与部署准备流程
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- LLM嵌入与表格特征整合
- 文本嵌入生成
- sentence-transformers库
- 自定义转换器
- 特征处理
- ColumnTransformer
- 并行处理
- 数据集构建
- SMS数据集
- 合成特征
金句 / Highlights
值得收藏与分享的关键句。
使用ColumnTransformer可同时处理文本、数值和分类特征,提升特征工程效率
sentence-transformers库能生成高质量文本嵌入,且无需依赖昂贵的API服务
混合真实SMS数据与合成特征可创建更贴近实际的用户分类场景
将LLM嵌入与表格特征结合到统一的scikit-learn管道中 - MachineLearningMastery.com
将LLM嵌入与表格特征结合到统一的scikit-learn管道中
作者:
Iván Palomares Carrascosa
于
2026年8月31日
分类:
语言模型
0
分享
发布
在本文中,你将学习如何构建一个统一的scikit-learn管道,该管道将轻量级开源语言模型生成的文本嵌入与结构化表格特征结合,用于分类任务。
我们将涵盖的主题包括:
- 如何使用Hugging Face的sentence-transformers库生成文本嵌入,并将其封装到自定义的scikit-learn转换器类中。
- 如何使用ColumnTransformer并行处理文本、数值和分类特征的预处理分支。
- 如何在包含真实文本数据和合成表格特征的混合数据集上组装和评估一个完整、可部署的分类管道。
引言
像工单分类或客户流失预测这样的现实任务通常通过构建分类模型来解决。然而,在数据无处不在的时代,用于构建这些模型和进行推理的数据很少以单一形式存在。我们经常面临混合数据的情况:既有数值和定性性质的表格结构化数据,也有文本等非结构化数据(例如工单描述或客户消息)。将这些数据类型同时输入机器学习模型需要有效且统一的管道,以适应最新的数据细微差别和处理技术。
本文将向你展示如何构建一个干净且可部署的解决方案,将开源LLM(语言模型)生成的嵌入封装到统一的scikit-learn管道中,将文本表示和不同类型的表格特征结合在一起——这一切都基于ColumnTransformer的使用。为了说明其应用,我们将考虑一个分类场景:在客户群体中检测垃圾用户。
先决条件
我们不会使用OpenAI或Google Gemini等付费API,也不会使用LLaMA 3等大型开源LLM,而是采用更轻量级、对CPU友好的解决方案来从文本集合中生成嵌入:Hugging Face的sentence-transformers。根据你的运行环境,你可能只需要安装以下库和依赖项:
!pip install -q sentence-transformers scikit-learn pandas numpy
1
!
pip
install
-
q
sentence
transformers
scikit
learn
pandas
numpy
如果你在自己的Python IDE中工作,而不是在Google Colab等云笔记本环境中,可以删除!。
import pandas as pd import numpy as np # 1. 从GitHub加载基础文本数据集 url = "https://raw.githubusercontent.com/justmarkham/pycon-2016-tutorial/master/data/sms.tsv" df = pd.read_csv(url, sep='\t', header=None, names=['label', 'message']) # 2. 首先对原始目标变量进行编码(正常/ham为0,spam为1) df['target'] = df['label'].map({'ham': 0, 'spam': 1}) # 3. 合成具有现实重叠(噪声)的有意义表格特征 # 如果没有噪声和一定程度的重叠,我们将构建的分类器 # 很容易达到完美表现:这在实际中并不现实 np.random.seed(42) # 账户年龄:正常用户可能是新用户,而垃圾信息发送者有时会使用被入侵的旧账户 df['account_age_days'] = np.where( df['target'] == 1, np.random.randint(1, 365, df.shape[0]), # 垃圾信息:1至365天 np.random.randint(1, 1500, df.shape[0]) # 正常信息:1至1500天(大量重叠) ) # 高级会员状态:这里添加更多噪声 df['is_premium'] = np.where( df['target'] == 1, np.random.choice(['no', 'yes'], df.shape[0], p=[0.95, 0.05]), # 垃圾信息:95%非会员 np.random.choice(['no', 'yes'], df.shape[0], p=[0.80, 0.20]) # 正常信息:80%非会员,20%高级会员 ) # 优先级评分:重叠分布使模型不能仅依赖此特征进行分类 df['priority_score'] = np.where( df['target'] == 1, np.random.uniform(0.4, 1.0, df.shape[0]), # 垃圾信息:0.4至1.0 np.random.uniform(0.0, 0.7, df.shape[0]) # 正常信息:0.0至0.7(0.4至0.7区间重叠) ) # 查看逻辑连贯的混合数据样本 df.head(3)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import
as
pd
np
1. 从GitHub加载基础文本数据集
url
=
"https://raw.githubusercontent.com/justmarkham/pycon-2016-tutorial/master/data/sms.tsv"
df
.
read_csv
(
,
sep
'\t'
header
None
names
[
'label'
'message'
]
)
2. 首先对原始目标变量进行编码(0为正常/ham,1为spam)
'target'
map
{
'ham'
:
'spam'
}
3. 合成具有现实重叠(噪声)的有意义表格特征
如果没有噪声和一定程度的重叠,我们将构建的分类器会
很容易达到完美表现:这在实际中并不现实。
random
seed
42
账户年龄:正常用户可能是新用户,而垃圾信息发送者有时会使用被入侵的旧账户
'account_age_days'
where
==
randint
365
shape
垃圾信息:1至365天
1500
正常信息:1至1500天(大量重叠)
高级会员状态:这里添加更多噪声
'is_premium'
choice
'no'
'yes'
p
0.95
0.05
垃圾信息:95%非会员
0.80
0.20
正常信息:80%非会员,20%高级会员
优先级评分:重叠分布使模型不能仅依赖此特征进行分类
'priority_score'
uniform
0.4
1.0
垃圾信息:0.4至1.0
0.0
0.7
正常信息:0.0至0.7(0.4至0.7区间重叠)
查看逻辑连贯的混合数据样本
head
Example output:
下一步至关重要,因为这是我们要创建自定义文本转换器的地方——请参见上图中的最左侧分支。在scikit-learn中,这是通过创建一个继承自TransformerMixin和BaseEstimator的自定义类来实现的。要求是定义fit()和transform()方法,就像库中任何现有的数据转换类(例如标准缩放器和独热编码器)一样。
from sklearn.base import BaseEstimator, TransformerMixin from sentence_transformers import SentenceTransformer
class TextEmbedder(BaseEstimator, TransformerMixin): def __init__(self, model_name='all-MiniLM-L6-v2'): self.model_name = model_name self.model = None
def fit(self, X, y=None):
在 fit() 中初始化模型以符合 sklearn 的克隆规则
if self.model is None: self.model = SentenceTransformer(self.model_name) return self
def transform(self, X, y=None):
处理 pandas DataFrame(提取第一列作为字符串列表)
if isinstance(X, pd.DataFrame): texts = X.iloc[:, 0].astype(str).tolist() else: texts = pd.Series(X).astype(str).tolist()
使用指定的 LLM 生成并返回嵌入表示作为二维 numpy 数组
return self.model.encode(texts, show_progress_bar=False)
我们注意到在构造方法中指定了要使用的 Hugging Face 的 sentence-transformer 模型(即 all-MiniLM-L6-v2),并在 transform() 方法中调用该模型将文本映射为嵌入表示。
接下来,当我们获得嵌入表示后,需要应用其他特征所需的并行数据预处理。由于这完全依赖于 scikit-learn 中已实现的类,我们可以直接将所有类型特定的预处理步骤整合到一个统一的管道中。我们区分数值列和分类列,对前者应用标准缩放,对后者应用独热编码。结合之前实现的文本嵌入步骤,这为我们提供了三个并行处理分支。实现这一目标的方法是通过一个包含三个“处理分支”列表的 ColumnTransformer 对象。这种机制可以保持整个数据集的完整性,无需手动拆分和重新合并特征。
之后,我们添加最终阶段:随机森林分类器。整个流程如下所示:
from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report # 拆分数据 X = df[['message', 'account_age_days', 'priority_score', 'is_premium']] y = df['target'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 定义列分组 text_features = ['message'] numeric_features = ['account_age_days', 'priority_score'] categorical_features = ['is_premium'] # 构建ColumnTransformer预处理器 preprocessor = ColumnTransformer( transformers=[ ('text', TextEmbedder(), text_features), ('num', StandardScaler(), numeric_features), ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features) ], remainder='drop' # 删除任何未明确定义的列 ) # 组装最终流水线 pipeline = Pipeline(steps=[ ('preprocessor', preprocessor), ('classifier', RandomForestClassifier(n_estimators=100, random_state=42)) ])
compose
ColumnTransformer
pipeline
preprocessing
StandardScaler
OneHotEncoder
ensemble
RandomForestClassifier
model_selection
train_test_split
metrics
classification
_
report
拆分数据
X_train
X_test
y_train
y_test
test_size
0.2
random_state
定义列分组
text_features
numeric_features
categorical_features
构建ColumnTransformer
preprocessor
'text'
'num'
'cat'
handle_unknown
'ignore'
remainder
'drop'
删除任何未明确定义的列
组装最终流水线
steps
'preprocessor'
'classifier'
n_estimators
100
现在我们已经组装好了完整的流水线,是时候尝试使用它了!最后一段代码将训练模型——这个过程由于流水线封装的特性,会隐式地执行所有先前的数据预处理步骤——并评估它在我们之前预留的测试集上的表现:
训练模型(这将花费一些时间下载HF模型并嵌入文本) print("训练流水线...") pipeline.fit(X_train, y_train) # 在测试样本上进行评估 print("预测和评估...") y_pred = pipeline.predict(X_test) print(classification_report(y_test, y_pred))
训练模型(这将花费一些时间下载HF模型并嵌入文本)
"训练流水线..."
在测试样本上进行评估
"预测和评估..."
y_pred
predict
classification_report
结果:
预测和评估... precision recall f1-score support 0 0.99 1.00 0.99 966 1 1.00 0.91 0.95 149 accuracy 0.99 1115 macro avg 0.99 0.95 0.97 1115 weighted avg 0.99 0.99 0.99 1115
预测
和
评估
precision
recall
f1
score
support
0.99
1.00
966
0.91
149
accuracy
1115
macro
avg
0.97
weighted
这些结果相当不错。部分原因在于,用于标记文本的真实数据集以易于类别分离而闻名,因此用高准确率进行分类并不困难。我们故意在创建其他合成属性时添加了噪声和重叠,以给分类器带来一些挑战——否则,它可能会达到100%的准确率,这将不会提供太多信息。
结论
本文探讨了人工智能和数据科学领域日益常见的一个问题:如何利用文本数据并将其与传统用于下游机器学习模型的结构化数据特征相结合,用于分类等预测任务。我们使用了 scikit-learn 的 transformer 类和预训练语言模型,构建了一个统一的处理流程,能够优雅高效地处理混合数据类型,最终形成了一个稳健且易于复用的解决方案。
更多相关内容
- 结合 XGBoost 和嵌入向量:混合语义建模
- 如何将大语言模型嵌入向量 + TF-IDF + 元数据结合使用
- 10 种将嵌入向量用于表格机器学习任务的方法
- 表格数据特征工程中的词嵌入
- 构建端到端情感分析处理流程
- 从文本到表格:基于大语言模型的特征工程