大数据特征工程:如何处理文本与数值混合特征
一、引言 (Introduction)
钩子 (The Hook)
你是否曾在处理电商用户行为数据时陷入这样的困境:
- 手里有一堆数值型特征:
购买次数(1-1000)、平均客单价(100-10000)、停留时长(0-3600秒); - 还有一堆文本型特征:
用户评论(“这个商品质量太差了,再也不买了”)、商品标题(“2024夏季新款纯棉T恤男宽松休闲短袖”)、客服聊天记录(“请问这个衣服能退换吗?”); - 想把这些特征喂给模型(比如推荐系统、欺诈检测),但不知道该怎么把结构化的数值和非结构化的文本揉成模型能理解的“统一语言”?
如果你的答案是“是”,那么这篇文章就是为你写的。混合特征处理是大数据特征工程中的“必考题”,也是很多数据科学家容易栽跟头的地方——处理得好,模型效果能提升30%以上;处理得差,可能让所有努力白费。
定义问题/阐述背景 (The “Why”)
在大数据场景中,单一类型的特征几乎不存在。比如:
- 推荐系统:用户的
浏览次数(数值)+搜索关键词(文本)+收藏夹内容(文本); - 情感分析:产品的
评分(数值)+评论内容(文本)+销量(数值); - 欺诈检测:用户的
交易金额(数值)+收货地址(文本)+设备型号(文本)。
这些混合特征包含了不同模态的信息:数值特征能直接反映“量”的大小(比如购买次数越多,用户粘性越高),文本特征能反映“质”的特征(比如评论中的“太差了”直接表达负面情绪)。如果只处理其中一种类型,会丢失大量关键信息——比如忽略评论文本,推荐系统可能把“差评很多但购买次数多”的商品推荐给用户,导致转化率暴跌。
因此,混合特征处理的核心目标是:保留数值特征的“量化信息”和文本特征的“语义信息”,并将它们转换为模型能高效利用的结构化表示。
亮明观点/文章目标 (The “What” & “How”)
本文将带你从0到1掌握混合特征处理的完整流程,内容涵盖:
- 基础认知:数值特征与文本特征的本质差异;
- 实战步骤:从数据探索到特征融合的具体操作(附Python代码);
- 进阶技巧:避免踩坑的最佳实践、性能优化方法;
- 未来趋势:大模型时代混合特征处理的新方向。
读完这篇文章,你能解决的问题包括:
- 如何清洗数值特征中的异常值?
- 如何将文本特征转换为向量?
- 如何融合数值与文本特征,让模型同时“看懂”两者?
- 如何避免混合特征处理中的常见陷阱?
二、基础知识/背景铺垫 (Foundational Concepts)
在开始实战前,我们需要先明确几个核心概念,避免后续混淆。
1. 什么是特征工程?
特征工程是将原始数据转换为模型可理解的特征的过程,目的是提升模型的性能。它包括:数据清洗、特征提取、特征选择、特征融合等步骤。
对于混合特征(文本+数值),特征工程的难点在于:两种特征的表示方式完全不同——数值特征是结构化的(比如购买次数=5),文本特征是非结构化的(比如评论=“质量太差了”),需要分别处理后再融合。
2. 数值特征的类型与特点
数值特征分为连续型(比如停留时长、客单价)和离散型(比如购买次数、收藏数量),它们的特点是:
- 结构化:可以直接用数字表示;
- 量纲差异大:比如
客单价是100-10000,购买次数是1-1000,直接输入模型会导致“数值大的特征被过度重视”; - 容易统计:可以通过均值、方差、分位数等统计量构造新特征。
3. 文本特征的类型与特点
文本特征是非结构化的,需要转换为结构化的向量才能被模型使用。常见的文本特征包括:
- 短文本:比如
商品标题(10-20字)、用户评论(50-100字); - 长文本:比如
客服聊天记录(500-1000字)、产品说明书(几千字)。
文本特征的核心价值是语义信息(比如“太差了”表示负面情绪),但需要通过分词、嵌入等步骤将语义转换为数字。
4. 混合特征的常见场景
混合特征几乎存在于所有大数据应用中,以下是几个典型场景:
| 场景 | 数值特征 | 文本特征 |
|---|---|---|
| 电商推荐 | 购买次数、客单价、停留时长 | 用户评论、商品标题、搜索关键词 |
| 金融欺诈检测 | 交易金额、还款次数、逾期天数 | 收货地址、设备型号、备注信息 |
| 医疗诊断 | 体温、血压、血常规指标 | 病历描述、症状主诉、医生备注 |
三、核心内容/实战演练 (The Core - “How-To”)
接下来进入本文的核心部分:混合特征处理的实战流程。我们以电商用户评论分析为例(目标:预测用户是否会再次购买),用Python实现从数据探索到特征融合的完整步骤。
数据准备
首先,我们构造一个模拟的电商用户数据集(user_data.csv),包含以下字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
| user_id | 字符串 | 用户ID |
| purchase_count | 整数 | 购买次数(数值特征) |
| avg_order_value | 浮点数 | 平均客单价(数值特征) |
| stay_duration | 整数 | 平均停留时长(秒,数值特征) |
| comment | 字符串 | 用户评论(文本特征) |
| re_purchase | 整数 | 是否再次购买(标签:0=否,1=是) |
导入必要的库:
importpandasaspdimportnumpyasnpimportjieba# 中文分词库fromsklearn.preprocessingimportStandardScaler,MinMaxScalerfromsklearn.feature_extraction.textimportTfidfVectorizerfromsklearn.composeimportColumnTransformerfromsklearn.pipelineimportPipelinefromsklearn.linear_modelimportLogisticRegressionfromsklearn.model_selectionimporttrain_test_splitfromsklearn.metricsimportaccuracy_score,f1_score步骤一:数据探索与预处理
数据探索(EDA)是特征工程的第一步,目的是发现数据中的问题(比如缺失值、异常值),并为后续处理提供依据。
1. 加载数据并查看基本信息
df=pd.read_csv("user_data.csv")print(df.head())print(df.info())print(df.describe())输出结果示例:
purchase_count:均值为12.3,最大值为100,最小值为1(无缺失值);avg_order_value:均值为523.6,最大值为10000,最小值为100(无缺失值);stay_duration:均值为180,最大值为3600,最小值为0(有缺失值,占比5%);comment:有10%的缺失值(用户未评论);re_purchase:正负样本比例为1:1(平衡数据集)。
2. 处理缺失值
- 数值特征:
stay_duration缺失值用均值填充(因为是连续型特征,均值更稳健); - 文本特征:
comment缺失值用空字符串填充(或者用“未评论”代替,避免丢失样本)。
# 处理数值特征缺失值df["stay_duration"].fillna(df["stay_duration"].mean(),inplace=True)# 处理文本特征缺失值df["comment"].fillna("",inplace=True)3. 处理异常值
数值特征中的异常值(比如avg_order_value=10000,可能是测试数据或异常交易)会影响模型效果,需要处理。常见的方法有:
- 截断法:将超过99%分位数或低于1%分位数的值替换为分位数;
- 删除法:如果异常值占比很小(比如<1%),直接删除。
这里我们用截断法处理avg_order_value:
# 计算99%分位数q99=df["avg_order_value"].quantile(0.99)# 将超过99%分位数的值替换为q99df["avg_order_value"]=df["avg_order_value"].apply(lambdax:min(x,q99))步骤二:处理数值特征
数值特征的处理目标是消除量纲差异(让不同特征的数值范围一致)和提取更有价值的信息(比如统计特征)。
1. 连续型数值特征:归一化/标准化
连续型特征(比如avg_order_value、stay_duration)的量纲差异大,需要归一化(Min-Max Scaling)或标准化(Standard Scaling)。
- 归一化:将数值缩放到[0,1]区间,适合数据分布已知(比如正态分布)的情况;
- 标准化:将数值转换为均值为0、方差为1的分布,适合数据分布未知的情况。
这里我们用标准化处理连续型特征:
# 选择连续型数值特征numeric_features=["avg_order_value","stay_duration"]# 初始化标准化器scaler=StandardScaler()# 拟合并转换特征df[numeric_features]=scaler.fit_transform(df[numeric_features])2. 离散型数值特征:保持原样或离散化
离散型特征(比如purchase_count,取值为1-100)的量纲差异小,通常不需要归一化。如果取值范围很大(比如1-1000),可以用离散化(比如分箱)将其转换为类别特征(比如“低购买次数”“中购买次数”“高购买次数”)。
这里purchase_count的取值范围是1-100,我们保持原样:
# 离散型数值特征(无需处理)discrete_features=["purchase_count"]3. 构造新的数值特征
除了原始数值特征,我们还可以构造统计特征或交互特征,提升模型效果。比如:
total_spend:总消费金额(purchase_count×avg_order_value);stay_per_purchase:每次购买的平均停留时长(stay_duration/purchase_count)。
# 构造总消费金额df["total_spend"]=df["purchase_count"]× df["avg_order_value"]# 构造每次购买的平均停留时长(避免除以0,加1)df["stay_per_purchase"]=df["stay_duration"]/(df["purchase_count"]+1)步骤三:处理文本特征
文本特征的处理目标是将非结构化的文本转换为结构化的向量,保留语义信息。常见的处理步骤包括:分词、停用词去除、词嵌入。
1. 分词(中文文本的核心步骤)
中文文本没有天然的分隔符(比如英文的空格),需要用分词工具(比如jieba)将句子拆分为词语。
# 定义分词函数(去除标点符号)importredefsegment_text(text):# 去除标点符号text=re.sub(r"[^\w\s]","",text)# 分词words=jieba.lcut(text)# 去除空字符串words=[wordforwordinwordsifword.strip()]return" ".join(words)# 对comment字段进行分词df["comment_seg"]=df["comment"].apply(segment_text)示例输出:
原始评论:“这个商品质量太差了,再也不买了” → 分词后:“这个 商品 质量 太 差 了 再也 不 买 了”。
2. 去除停用词
停用词是指没有实际语义的词(比如“的”“是”“了”),会增加特征维度但不提供价值,需要去除。
首先,下载jieba的停用词表(或自定义):
# 加载停用词表(可以从网上下载,比如哈工大停用词表)withopen("stopwords.txt","r",encoding="utf-8")asf:stopwords=set(f.read().splitlines())# 定义去除停用词的函数defremove_stopwords(text):words=text.split()filtered_words=[wordforwordinwordsifwordnotinstopwords]return" ".join(filtered_words)# 去除停用词df["comment_seg"]=df["comment_seg"].apply(remove_stopwords)示例输出:
分词后:“这个 商品 质量 太 差 了 再也 不 买 了” → 去除停用词后:“商品 质量 差 再也 不 买”。
3. 词嵌入(将文本转换为向量)
词嵌入是文本特征处理的核心步骤,常见的方法有:
- TF-IDF:统计词的频率-逆文档频率,适合短文本(比如商品标题、评论);
- Word2Vec:将词转换为低维向量,保留语义信息(比如“国王”−“男人”+“女人”=“女王”);
- BERT:基于Transformer的预训练模型,能捕捉上下文语义,适合长文本(比如客服聊天记录)。
这里我们用TF-IDF处理评论文本(因为评论是短文本,TF-IDF足够高效):
# 初始化TF-IDF向量器(最多保留1000个最常见的词)tfidf=TfidfVectorizer(max_features=1000)# 拟合并转换评论文本comment_tfidf=tfidf.fit_transform(df["comment_seg"])# 将TF-IDF向量转换为DataFrame(方便后续融合)comment_tfidf_df=pd.DataFrame(comment_tfidf.toarray(),columns=tfidf.get_feature_names_out())示例输出:comment_tfidf_df的每一行是一个长度为1000的向量,每个元素表示对应词的TF-IDF值(比如“质量”的TF-IDF值为0.8,“差”的TF-IDF值为0.7)。
步骤四:融合数值与文本特征
融合是混合特征处理的最后一步,目的是将数值特征和文本特征合并为一个统一的特征矩阵,供模型输入。常见的融合方法有:
1. 简单拼接(Concat)
最简单的融合方法是将数值特征的DataFrame和文本特征的DataFrame按列拼接。这种方法适合数值特征和文本特征独立的场景(比如推荐系统中的用户行为和商品描述)。
# 选择数值特征(包括原始和构造的)numeric_features_all=["purchase_count","avg_order_value","stay_duration","total_spend","stay_per_purchase"]# 数值特征DataFramenumeric_df=df[numeric_features_all]# 拼接数值特征和文本特征(TF-IDF)merged_df=pd.concat([numeric_df,comment_tfidf_df],axis=1)示例输出:merged_df的 columns 包括:purchase_count(数值)、avg_order_value(数值)、质量(TF-IDF)、差(TF-IDF)等,共1005列(5个数值特征+1000个文本特征)。
2. 特征交叉(Feature Cross)
特征交叉是指将数值特征和文本特征进行组合,生成新的特征(比如purchase_count × 质量)。这种方法适合数值特征和文本特征有交互作用的场景(比如“购买次数多且评论中提到‘质量’的用户,更可能再次购买”)。
# 选择数值特征(比如purchase_count)和文本特征(比如“质量”“差”)numeric_feature="purchase_count"text_features=["质量","差"]# 生成特征交叉fortext_featureintext_features:merged_df[f"{numeric_feature}_×_{text_feature}"]=merged_df[numeric_feature]× merged_df[text_feature]示例输出:
新增purchase_count_×_质量(购买次数ד质量”的TF-IDF值)、purchase_count_×_差(购买次数ד差”的TF-IDF值)等特征。
3. 注意力机制(Attention)
注意力机制是深度学习中的高级融合方法,能自动学习数值特征和文本特征的权重(比如“评论中的‘差’比购买次数更重要”)。这种方法适合需要捕捉特征间依赖关系的场景(比如情感分析、推荐系统)。
这里我们用TensorFlow实现一个简单的注意力融合模型:
importtensorflowastffromtensorflow.keras.layersimportInput,Dense,Attention,Concatenatefromtensorflow.keras.modelsimportModel# 定义输入层(数值特征:5维,文本特征:1000维)numeric_input=Input(shape=(5,),name="numeric_input")text_input=Input(shape=(1000,),name="text_input")# 数值特征编码(全连接层)numeric_encoded=Dense(64,activation="relu")(numeric_input)# 文本特征编码(全连接层)text_encoded=Dense(64,activation="relu")(text_input)# 注意力层(计算数值特征和文本特征的权重)attention=Attention()([numeric_encoded,text_encoded])# 融合特征(拼接注意力输出和原始编码)merged=Concatenate()([attention,numeric_encoded,text_encoded])# 输出层(二分类)output=Dense(1,activation="sigmoid")(merged)# 构建模型model=Model(inputs=[numeric_input,text_input],outputs=output)model.compile(optimizer="adam",loss="binary_crossentropy",metrics=["accuracy"])# 准备输入数据(数值特征和文本特征分开)X_numeric=merged_df[numeric_features_all].values X_text=merged_df[comment_tfidf_df.columns].values y=df["re_purchase"].values# 划分训练集和测试集X_numeric_train,X_numeric_test,X_text_train,X_text_test,y_train,y_test=train_test_split(X_numeric,X_text,y,test_size=0.2,random_state=42)# 训练模型model.fit([X_numeric_train,X_text_train],y_train,epochs=10,batch_size=32,validation_data=([X_numeric_test,X_text_test],y_test))# 评估模型loss,accuracy=model.evaluate([X_numeric_test,X_text_test],y_test)print(f"Test Accuracy:{accuracy:.4f}")示例输出:
Test Accuracy: 0.89(比简单拼接的0.82高,说明注意力机制能更好地融合特征)。
步骤五:模型训练与评估
融合后的特征矩阵可以喂给任何机器学习模型(比如逻辑回归、随机森林、XGBoost)或深度学习模型(比如CNN、LSTM)。这里我们用逻辑回归(简单、易解释)进行训练,并评估效果。
# 准备训练数据(简单拼接的特征矩阵)X=merged_df.values y=df["re_purchase"].values# 划分训练集和测试集X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=42)# 训练逻辑回归模型lr=LogisticRegression(max_iter=1000)lr.fit(X_train,y_train)# 预测并评估y_pred=lr.predict(X_test)print(f"Accuracy:{accuracy_score(y_test,y_pred):.4f}")print(f"F1 Score:{f1_score(y_test,y_pred):.4f}")示例输出:
Accuracy: 0.82,F1 Score: 0.81(比只使用数值特征的0.75高,说明文本特征的加入提升了模型效果)。
四、进阶探讨/最佳实践 (Advanced Topics / Best Practices)
1. 常见陷阱与避坑指南
- 陷阱1:数值特征未归一化:比如
avg_order_value(100-10000)和purchase_count(1-100),未归一化会导致模型更重视avg_order_value,而忽略purchase_count的重要性。
避坑方法:对连续型数值特征进行标准化或归一化。 - 陷阱2:文本特征过拟合:比如TF-IDF保留了10000个词,导致特征维度太高,模型在训练集上表现好但测试集上表现差。
避坑方法:限制TF-IDF的max_features(比如1000),或用PCA进行降维。 - 陷阱3:混合特征融合顺序错误:比如先将数值特征和文本特征拼接,再进行归一化,会导致文本特征的TF-IDF值被缩放(失去语义信息)。
避坑方法:先分别处理数值特征和文本特征,再融合(比如数值特征标准化后,再与文本特征的TF-IDF向量拼接)。
2. 性能优化技巧
- 文本特征降维:对于高维的文本特征(比如TF-IDF的1000维),可以用PCA(主成分分析)将其降维到100-200维,减少计算量。
fromsklearn.decompositionimportPCA pca=PCA(n_components=200)comment_tfidf_pca=pca.fit_transform(comment_tfidf_df) - 数值特征选择:用互信息(Mutual Information)或L1正则(Lasso)选择与标签相关的数值特征,减少冗余。
fromsklearn.feature_selectionimportmutual_info_classif mi=mutual_info_classif(numeric_df,y)# 选择互信息前3的特征top_numeric_features=numeric_df.columns[mi.argsort()[-3:]].tolist() - 稀疏矩阵存储:文本特征的TF-IDF向量是稀疏的(大部分元素为0),用稀疏矩阵(比如
scipy.sparse.csr_matrix)存储,可以节省内存(比如1000维的向量,稀疏矩阵只存储非零元素)。
3. 最佳实践总结
- 先做EDA:通过数据探索了解特征的分布、缺失值、异常值,为后续处理提供依据;
- 保留可解释性:比如用TF-IDF而不是BERT(黑盒),方便解释模型的决策(比如“用户评论中的‘差’是导致不再次购买的主要原因”);
- 迭代优化:先试简单的方法(比如TF-IDF+简单拼接),再试复杂的方法(比如BERT+注意力机制),逐步提升模型效果;
- 结合业务场景:比如在欺诈检测中,
收货地址(文本特征)的“异常性”(比如频繁更换地址)比交易金额(数值特征)更重要,需要重点处理文本特征。
五、结论 (Conclusion)
核心要点回顾
混合特征处理的完整流程可以总结为:
- 数据探索:发现缺失值、异常值;
- 数值特征处理:归一化/标准化、构造新特征;
- 文本特征处理:分词、停用词去除、词嵌入;
- 特征融合:简单拼接、特征交叉、注意力机制;
- 模型训练:用融合后的特征矩阵训练模型。
展望未来/延伸思考
随着大模型(比如GPT-4、Claude 3)的发展,混合特征处理的方式正在发生变化:
- 统一嵌入:大模型能直接处理文本和数值特征(比如将数值特征转换为文本“购买次数=5”,然后输入大模型),减少人工预处理的工作量;
- 自动特征工程:大模型能自动生成有价值的特征(比如从评论中提取“负面情绪”特征,从数值中提取“高消费用户”特征);
- 端到端训练:大模型能直接从原始数据(文本+数值)中学习,不需要人工特征处理(比如用GPT-4预测用户是否会再次购买,输入是“购买次数=5,平均客单价=500,评论=‘质量太差了’”)。
行动号召
现在,轮到你动手实践了!
- 下载一个包含混合特征的数据集(比如Kaggle的Amazon Reviews Dataset);
- 按照本文的流程处理数值特征和文本特征;
- 尝试不同的融合方法(简单拼接、注意力机制),比较模型效果;
- 在评论区分享你的实践经验,或提出你的问题——我会一一解答!
参考资源:
- 《特征工程入门与实践》(作者:克里斯·阿尔本);
- sklearn官方文档:特征处理;
- jieba官方文档:中文分词;
- TensorFlow官方文档:注意力机制。
最后:混合特征处理不是“银弹”,没有放之四海而皆准的方法。关键是理解业务场景,结合数据特点,迭代优化。希望这篇文章能帮你解决混合特征处理的痛点,让你的模型更“懂”数据!