📢 转载信息
原文作者:Iván Palomares Carrascosa
在本文中,你将学习如何使用一个预训练的大型语言模型来从文本中提取结构化特征,并将它们与数值型列结合起来训练一个监督式分类器。
我们将涵盖的主题包括:
- 创建一个包含混合文本和数值字段的玩具数据集以用于分类
- 使用Groq托管的LLaMA模型,通过Pydantic schema从票据文本中提取JSON特征
- 在工程化的表格数据集上训练和评估一个scikit-learn分类器
事不宜迟,让我们开始吧。
引言
虽然大型语言模型(LLMs)通常用于会话目的,处理涉及自然语言交互的应用场景,但它们也能辅助处理复杂数据集上的特征工程等任务。具体来说,你可以利用来自Groq等提供商的预训练LLMs(例如,Llama系列模型),来执行数据转换和预处理任务,包括将非结构化数据(如文本)转化为可用于驱动预测性机器学习模型的、完全结构化的表格数据。
在本文中,我将指导你完成将结构化文本进行特征工程的完整流程,将其转化为适合机器学习模型的表格数据——即,一个利用LLM创建的特征进行训练的分类器。
设置和导入
首先,我们将为这个实践示例导入所有必要的库:
import pandas as pd
import json
from pydantic import BaseModel, Field
from openai import OpenAI
from google.colab import userdata
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.preprocessing import StandardScaler
请注意,除了scikit-learn等常用的机器学习和数据预处理库外,我们还导入了OpenAI类——并非因为我们将直接使用OpenAI的模型,而是因为许多LLM API(包括Groq的)已经采纳了与OpenAI相同的接口风格和规范。因此,这个类可以帮助你通过单一客户端与多种提供商进行交互,并访问各种LLMs,包括通过Groq访问Llama模型,正如我们稍后将看到的。
接下来,我们设置一个Groq客户端,以便在执行期间通过API调用预训练的LLM进行推理:
groq_api_key = userdata.get('GROQ_API_KEY')
client = OpenAI(
base_url="https://api.groq.com/openai/v1",
api_key=groq_api_key
)
重要提示:要使上述代码正常工作,你需要定义一个Groq的API密钥。在Google Colab中,可以通过左侧边栏的“Secrets”图标(该图标看起来像一把钥匙)来完成。在这里,将你的密钥命名为'GROQ_API_KEY',然后在Groq网站注册以获取实际密钥,并将其粘贴到值字段中。
创建玩具票据数据集
下一步是生成一个合成的、部分随机的玩具数据集以供说明。如果你有自己的文本数据集,可以随意修改代码并使用你自己的数据。
import random
import time
random.seed(42)
categories = ["access", "inquiry", "software", "billing", "hardware"]
templates = {
"access": [
"I've been locked out of my account for {days} days and need urgent help!",
"I can't log in, it keeps saying bad password.",
"Reset my access credentials immediately.",
"My 2FA isn't working, please help me get into my account."
],
"inquiry": [
"When will my new credit card arrive in the mail?",
"Just checking on the status of my recent order.",
"What are your business hours on weekends?",
"Can I upgrade my current plan to the premium tier?"
],
"software": [
"The app keeps crashing every time I try to view my transaction history.",
"Software bug: the submit button is greyed out.",
"Pages are loading incredibly slowly since the last update.",
"I'm getting a 500 Internal Server Error on the dashboard."
],
"billing": [
"I need a refund for the extra charges on my bill.",
"Why was I billed twice this month?",
"Please update my payment method, the old card expired.",
"I didn't authorize this $49.99 transaction."
],
"hardware": [
"My hardware token is broken, I can't log in.",
"The screen on my physical device is cracked.",
"The card reader isn't scanning properly anymore.",
"Battery drains in 10 minutes, I need a replacement unit."
]
}
data = []
for _ in range(100):
cat = random.choice(categories)
# Injecting a random number of days into specific templates to foster variety
text = random.choice(templates[cat]).format(days=random.randint(1, 14))
data.append({
"text": text,
"account_age_days": random.randint(1, 2000),
"prior_tickets": random.choices([0, 1, 2, 3, 4, 5], weights=[40, 30, 15, 10, 3, 2])[0],
"label": cat
})
df = pd.DataFrame(data)
生成的数据集包含客户支持票据,结合了文本描述以及账户年龄和先前票据数量等结构化数值特征,还有一个涵盖多个票据类别的类标签。这些标签稍后将用于在流程结束时训练和评估分类模型。
提取LLM特征
接下来,我们定义希望从文本中提取的所需表格特征。特征的选择是领域相关的且完全可定制的,但你稍后将使用LLM以一致、结构化的格式提取这些字段:
class TicketFeatures(BaseModel):
urgency_score: int = Field(description="Urgency of the ticket on a scale of 1 to 5")
is_frustrated: int = Field(description="1 if the user expresses frustration, 0 otherwise")
例如,紧急程度和沮丧程度通常与特定的票据类型相关(例如,账户锁定和中断通常比一般查询更紧急、情绪更激动),因此这些信号可以帮助下游分类器比仅使用原始文本更有效地分离类别。
下一个函数是流程的关键部分,因为它封装了将票据文本转换为符合我们模式的JSON对象所需的LLM集成。
def extract_features(text: str) -> dict:
# Sleep for 2.5 seconds for safer use under the constraints of the 30 RPM free-tier limit
time.sleep(2.5)
schema_instructions = json.dumps(TicketFeatures.model_json_schema())
response = client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[
{
"role": "system",
"content": f"You are an extraction assistant. Output ONLY valid JSON matching this schema: {schema_instructions}"
},
{"role": "user", "content": text}
],
response_format={"type": "json_object"},
temperature=0.0
)
return json.loads(response.choices[0].message.content)
为什么函数返回JSON对象?首先,JSON是要求LLM生成结构化输出的可靠方式。其次,JSON对象可以轻松地转换为Pandas Series对象,然后可以无缝地与其他列合并到现有的DataFrame中,成为新的列。以下指令可以完成此操作,并将提取的特征(存储在engineered_features中)附加到原始数据集的其余部分:
print("1. Extracting structured features from text using LLM...")
engineered_features = df["text"].apply(extract_features)
features_df = pd.DataFrame(engineered_features.tolist())
X_raw = pd.concat([df.drop(columns=["text", "label"]),
features_df], axis=1)
y = df["label"]
print("\n2. Final Engineered Tabular Dataset:")
print(X_raw)
这是最终表格数据的样子:
account_age_days prior_tickets urgency_score is_frustrated
0 564 0 5 1
1 1517 3 4 0
2 62 0 5 1
3 408 2 4 0
4 920 1 5 1
.. ... ... ... ...
95 91 2 4 1
96 884 0 4 1
97 1737 0 5 1
98 837 0 5 1
99 862 1 4 1
[100 rows x 4 columns]
训练和评估分类器
最后,我们准备好训练一个分类器。在这个示例中,我们将使用一个经典的RandomForestClassifier,但你可以根据需要使用其他模型。首先,我们需要将数据集拆分为训练集和测试集,并对数值特征进行缩放,以确保模型能够获得最佳性能。
# Split data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X_raw, y, test_size=0.2, random_state=42)
# Scale numerical features
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# Initialize and train the RandomForestClassifier
classifier = RandomForestClassifier(random_state=42)
classifier.fit(X_train_scaled, y_train)
# Make predictions on the test set
y_pred = classifier.predict(X_test_scaled)
# Print the classification report
print("\n3. Classification Report:")
print(classification_report(y_test, y_pred))
运行此代码将生成一个分类报告,其中包含针对每个类别的精确度、召回率、F1分数和支持度等指标。通过分析这些指标,你可以了解LLM提取的特征对模型性能的贡献程度。
结论
在这篇文章中,我们探讨了如何使用大型语言模型(LLMs)进行特征工程,将非结构化的文本数据转化为结构化的表格格式,从而增强机器学习模型的预测能力。通过一个实际的例子,我们演示了如何从客户支持票据中提取关键特征,如紧急程度和用户沮丧程度,并将这些新特征与现有的数值数据结合起来,最终训练了一个有效的分类器。
这种方法不仅能够处理传统方法难以应对的文本数据,还为特征工程开辟了新的可能性。通过精心设计的提示词和模式,LLMs可以成为强大的数据预处理工具,显著提高数据科学家和机器学习工程师在复杂数据集上构建更准确、更鲁棒模型的效率。
🚀 想要体验更好更全面的AI调用?
欢迎使用青云聚合API,约为官网价格的十分之一,支持300+全球最新模型,以及全球各种生图生视频模型,无需翻墙高速稳定,文档丰富,小白也可以简单操作。
评论区