当前位置: 首页 > news >正文

特征工程 --- 特征提取

特征工程

一、特征工程逻辑思维导图

Untitled diagram _ Mermaid Chart-2025-08-01-102556

二、特征工程的概念

1.定义:

特征工程(Feature Engineering)是指在机器学习或深度学习项目中,为了更好地提高模型性能,通过构造、转换、选择特征的技术与过程。

2.目的:

目的说明
提高模型性能更有意义的特征 → 更好的模型拟合与预测能力
降低维度与计算复杂度去除冗余、无关特征,加快模型训练
提升泛化能力减少过拟合,提升对新数据的表现
增强可解释性构造更具现实意义的特征,方便模型解释

3.特征工程包括哪些步骤:

  • 特征提取
  • 特征选择
  • 特征处理
  • 特征降维

4. 举个简单例子

假设你要预测一个人的购车行为,原始数据有这些字段:

姓名年龄年收入(元)婚姻状态城市是否购车
张三25120000未婚北京
李四45300000已婚上海
王五35200000离异广州
赵六28180000未婚深圳

5.特征工程做了什么?

① 特征提取(Feature Extraction)
  • 通常直接使用结构化数据的字段
  • 或从原始字段中提取额外信息,如:
原始字段新提取特征
城市城市级别(如一线城市)
年龄年龄段(<30、30-50、>50)

② 特征处理(Feature Processing)
操作字段方法/说明
数值缩放年收入标准化(Z-score)或归一化(Min-Max)
分箱年龄分为年龄段(如 <30, 30-50, >50)
编码婚姻状态/城市独热编码 One-Hot 或 Label Encoding
缺失值处理若有缺失使用中位数/众数/插值填充

编码示例(婚姻状态)

婚姻状态婚姻_未婚婚姻_已婚婚姻_离异
未婚100
已婚010
离异001

③ 特征构造(Feature Construction)
构造目标构造方法
家庭稳定指数婚姻状态 × 年龄
收入等级年收入分箱(如高/中/低)
城市影响力评分自定义字典,如北京=3,广州=2

④ 特征选择(Feature Selection)
  • 目的:去除无用或冗余特征(如城市过多分散,且购车率差异小)
  • 可采用:
    • 相关系数法
    • 卡方检验
    • L1 正则化
    • 树模型的重要性评分(Feature Importance)

⑤ 特征降维(可选)

如果有维度灾难风险,比如城市编码后有 100 维,可以用:

方法适用场景
PCA连续变量、数值特征降维
LDA有监督、分类场景
AutoEncoder深度特征压缩

🔄 转换后数据示意
年龄年收入婚姻_未婚婚姻_已婚婚姻_离异城市_北京城市_上海城市_广州城市_深圳收入等级_高是否购车
250.2110010000
451.0001001001
350.6200100101
280.5410000010

6. 特征工程与建模的关系

原始数据
数据清洗
特征工程
模型训练
评估
  • 没有好的特征工程,再强的模型也很难表现好
  • 特征工程 ≈ 模型效果的地基

三、特征工程API

  • 实例化转换器对象,转换器类有很多,都是Transformer的子类, 常用的子类有:

    DictVectorizer  	字典特征提取
    CountVectorizer 	文本特征提取
    TfidfVectorizer 	TF-IDF文本特征词的重要程度特征提取 
    MinMaxScaler 		归一化
    StandardScaler 		标准化
    VarianceThreshold 	底方差过滤降维
    PCA  				主成分分析降维
    
  • 转换器对象调用fit_transform()进行转换, 其中fit用于计算数据,transform进行最终转换fit_transform()可以使用fit()和transform()代替

data_new = transfer.fit_transform(data)
可写成
transfer.fit(data)
data_new = transfer.transform(data)

在后面我们会讲解为什么会设计成这样。

四、DictVectorizer字典列表特征提取

from sklearn.feature_extraction import DictVectorizer

1. 什么是字典列表特征提取?

举个例子:你有一个这样的原始数据:

data = [{'age': 28, 'income': 50000, 'married': 'yes', 'city': 'Beijing'},{'age': 35, 'income': 80000, 'married': 'no',  'city': 'Shanghai'},{'age': 40, 'income': 90000, 'married': 'yes', 'city': 'Beijing'}
]
  • 每条数据是一个字典,整个数据是“字典的列表”。
  • DictVectorizer 会自动把分类变量做成 One-Hot,数值型保持原值。

2.代码演示(含稀疏矩阵和稠密矩阵)

from sklearn.feature_extraction import DictVectorizerdata = [{'age': 28, 'income': 50000, 'married': 'yes', 'city': 'Beijing'},{'age': 35, 'income': 80000, 'married': 'no',  'city': 'Shanghai'},{'age': 40, 'income': 90000, 'married': 'yes', 'city': 'Beijing'}
]# 1. 创建向量器
vec = DictVectorizer(sparse=True)  # 默认为 True,返回稀疏矩阵# 2. 进行转换
X_sparse = vec.fit_transform(data)# 3. 查看稀疏结果(CSR格式)
print(X_sparse)# 4. 转成稠密矩阵
X_dense = X_sparse.toarray()# 5. 获取特征名
print(vec.get_feature_names_out())
print(X_dense)

3.返回值的不同(稀疏 VS 稠密)

参数作用返回类型优点
sparse=True返回稀疏矩阵(默认)scipy.sparse 三元组表形式(CSR)节省内存
sparse=False返回稠密 numpy.ndarray直接是 array便于查看与调试

4. 稀疏矩阵转换成稠密矩阵

X_dense = X_sparse.toarray()

5. 示例输出

稀疏矩阵:(行索引,列索引) 数据

<Compressed Sparse Row sparse matrix of dtype 'float64'with 12 stored elements and shape (3, 6)>Coords	Values(0, 0)	28.0(0, 1)	1.0(0, 3)	50000.0(0, 5)	1.0(1, 0)	35.0(1, 2)	1.0(1, 3)	80000.0(1, 4)	1.0(2, 0)	40.0(2, 1)	1.0(2, 3)	90000.0(2, 5)	1.0
  • 内存中:是 CSR 格式Compressed Sparse Row),存储的是:

    • .data: 非零元素值列表
    • .indices: 非零元素所在的列索引
    • .indptr: 每行非零元素的起始位置索引
  • 打印时显示出来的 (row, col) \t value 只是为了可读性 —— 这叫做:

    “伪三元组表输出”(Human-readable triplet-like format)

它让我们看到非零值在矩阵中的具体位置和数值,但这不是它真实的底层结构。

特征名(vec.get_feature_names_out()):

['age' 'city=Beijing' 'city=Shanghai' 'income' 'married=no' 'married=yes']

稠密矩阵:

[[2.8e+01 1.0e+00 0.0e+00 5.0e+04 0.0e+00 1.0e+00][3.5e+01 0.0e+00 1.0e+00 8.0e+04 1.0e+00 0.0e+00][4.0e+01 1.0e+00 0.0e+00 9.0e+04 0.0e+00 1.0e+00]]

6. 特点总结

优点缺点
自动处理分类变量(One-Hot)特征维度可能膨胀,尤其是高基类分类变量
数值变量保持原样不支持嵌套结构(如 list、dict 中嵌 dict)
输出与 OneHotEncoder + ColumnTransformer 类似只适用于结构化数据(非嵌套 JSON)

7.使用场景建议

  • 小规模分类变量编码:如城市、性别等,用 DictVectorizer 非常便捷。
  • 大规模/高基类分类变量:建议使用 OneHotEncoder(handle_unknown='ignore') 结合 ColumnTransformer 管理更灵活。

五、CountVectorizer 文本特征提取

from sklearn.feature_extraction.text import CountVectorizer

1.基本原理

CountVectorizer 是最基础的文本向量化工具,它将文本中的词语转换为词频(Bag-of-Words,简称 BOW)特征矩阵。

功能:将一组文本(corpus)转换成词频矩阵(bag-of-words)

  • 每一行代表一条文本
  • 每一列代表一个词(特征)
  • 每个单元格表示该词在该文本中出现的次数

默认行为是:

  • 按英文空格和标点分词
  • 自动转小写
  • 只能处理英文,处理中文会把整句话当成一个词

2.案例解释

①简洁版

from sklearn.feature_extraction.text import CountVectorizer
import jiebacorpus = ["我爱北京天安门","天安门上太阳升","The sun rises in the east","I love Beijing Tiananmen"
]def mixed_tokenizer(text):if any( '\u4e00' <= chinese <='\u9fff' for chinese in text):return " ".join(jieba.cut(text))else:return text.lower()counter = CountVectorizer()
data2 = [mixed_tokenizer(word) for word in corpus]
data = counter.fit_transform(data2)
print(data.toarray())
print(counter.get_feature_names_out())

输出结果如下:

[[0 0 0 0 0 0 0 0 1 1 0][0 0 0 0 0 0 0 0 0 1 1][0 1 1 0 1 1 2 0 0 0 0][1 0 0 1 0 0 0 1 0 0 0]]
['beijing' 'east' 'in' 'love' 'rises' 'sun' 'the' 'tiananmen' '北京' '天安门''太阳升']

DataFrame构建词汇表

import jieba
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd# 自定义中文 + 英文分词函数
def mixed_tokenizer(text):if any('\u4e00' <= ch <= '\u9fff' for ch in text):  # 中文检测return list(jieba.cut(text))else:return text.lower().split()  # 英文按空格并小写处理# 用 CountVectorizer 进行词频统计
vectorizer = CountVectorizer(tokenizer=mixed_tokenizer,token_pattern=None)X = vectorizer.fit_transform(corpus)# 输出特征名(词汇表)
print("词汇表:")
print(vectorizer.get_feature_names_out())# 转成 DataFrame 展示词频矩阵
df = pd.DataFrame(X.toarray(), columns=vectorizer.get_feature_names_out())
print("\n词频矩阵:")
df.head()

输出如下所示:

词汇表:

['beijing' 'east' 'i' 'in' 'love' 'rises' 'sun' 'the' 'tiananmen' '上' '北京''天安门' '太阳升' '我' '爱']

词频矩阵:

beijingeastiinloverisessunthetiananmen北京天安门太阳升
0000000000011011
1000000000101100
2010101120000000
3101010001000000

3.参数解释

参数名作用示例
lowercase是否转小写(默认True)'NLP''nlp'
stop_words停用词(如 ‘the’, ‘is’)stop_words='english'
max_features限制输出特征数量max_features=1000
ngram_range支持 n-gram 模型(1,2) → 1-gram + 2-gram
token_pattern正则表达式控制分词方式默认只保留词长 ≥2 的单词
binary是否将词频转为二值(出现为1)binary=True

六、TfidfVectorizer TF-IDF文本特征词的重要程度特征提取

from sklearn.feature_extraction.text import TfidfVectorizer

TfidfVectorizer 是 sklearn 中用于将文本数据转换为基于 TF-IDF(词频 - 逆文档频率) 权重的特征向量的工具,核心作用是量化词语在文本中的重要程度,是文本分类、聚类等任务中常用的特征提取方法。

1. TF-IDF 核心原理

TF-IDF 由两部分组成:词频(TF)逆文档频率(IDF),最终通过两者的乘积衡量词语的重要性。

image-20250801194848790

  1. 词频(Term Frequency, TF) 表示一个词在单篇文档中出现的频率,反映该词在当前文档中的重要性。

    • 计算公式(sklearn 默认):直接使用词语在文档中出现的原始次数(与 CountVectorizer 的结果一致)。
    • 示例:若 “教育” 在文档 1 中出现 2 次,则该文档中 “教育” 的 TF 为 2。
  2. 逆文档频率(Inverse Document Frequency, IDF) 反映一个词在整个文档集合中的稀有程度:若一个词在多数文档中都出现(如 “的”“是”),则其重要性低;若仅在少数文档中出现,则重要性高。

    • sklearn 中的计算公式(带平滑处理):

      IDF(t)=log⁡(总文档数+1包含词t的文档数+1)+1 \text{IDF}(t) = \log\left(\frac{\text{总文档数} + 1}{\text{包含词}t\text{的文档数} + 1}\right) + 1 IDF(t)=log(包含词t的文档数+1总文档数+1)+1

      • 平滑目的:避免分母为 0(当某词未出现在任何文档中时)。
    • 示例:若 “民办” 在 3 篇文档中出现 2 次,总文档数为 3,则其 IDF 为 log⁡(3+12+1)+1≈0.2877+1=1.2877\log\left(\frac{3+1}{2+1}\right) + 1 \approx 0.2877 + 1 = 1.2877log(2+13+1)+10.2877+1=1.2877

  3. TF-IDF 最终值 词语的 TF-IDF 权重 = 该词的 TF × 该词的 IDF。

    • 含义:同时考虑词语在当前文档中的频率和在整体文档中的稀有性,权重越高则该词对当前文档的 “代表性” 越强。
  4. L2 归一化(sklearn 默认) 为了避免长文档的向量权重普遍高于短文档,TfidfVectorizer 会对每个文档的 TF-IDF 向量进行 L2 归一化:

归一化后的值=xix12+x22+...+xn2 \text{归一化后的值} = \frac{x_i}{\sqrt{x_1^2 + x_2^2 + ... + x_n^2}} 归一化后的值=x12+x22+...+xn2xi

其中 $x_i $是向量中的每个元素(即某词的 TF-IDF 权重)。

2. ✅ 各部分 “+1” 的意义详解:
部分数学目的原因解释
分子 N+1平衡缩放如果没有这个,极端情况下 IDF 可能会小于 1(造成结果偏小),这个 +1 有助于提高稀有词的重要性。
分母 +1防止除零避免某个词没有出现在任何文档中(即 df=0),否则会导致除以 0。
整体 +1平移,避免 0让所有 IDF 都大于 0,防止乘上 IDF 后造成词权重为 0,特别是在只有一个文档时。

在 sklearn 的 TfidfVectorizer 中,输出的 TF-IDF 向量默认经过了 L2 正则化,目的如下:

  • 保证每个文档的特征向量是单位长度,避免长文本向量绝对值过大
  • 更好地支持 余弦相似度计算(常用于文本匹配)
  • 提高模型对文本长度不一致的鲁棒性
3.案例演示:

①使用官方API:

from sklearn.feature_extraction.text import TfidfVectorizer
import jiebacorpus = ["我爱北京天安门","天安门上太阳升","The sun rises in the east","I love Beijing Tiananmen"
]def mixed_tokenizer(text):if any( '\u4e00' <= chinese <='\u9fff' for chinese in text):return " ".join(jieba.cut(text))else:return text.lower()transfer = TfidfVectorizer()
data = [mixed_tokenizer(word) for word in corpus]
data = transfer.fit_transform(data)
print(data.toarray())
print(transfer.get_feature_names_out())

结果输出:

[[0.         0.         0.         0.         0.         0.0.         0.         0.78528828 0.6191303  0.        ][0.         0.         0.         0.         0.         0.0.         0.         0.         0.6191303  0.78528828][0.         0.35355339 0.35355339 0.         0.35355339 0.353553390.70710678 0.         0.         0.         0.        ][0.57735027 0.         0.         0.57735027 0.         0.0.         0.57735027 0.         0.         0.        ]]
['beijing' 'east' 'in' 'love' 'rises' 'sun' 'the' 'tiananmen' '北京' '天安门''太阳升']

②利用公式自定义函数:

from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
from sklearn.preprocessing import normalizedef myTfidVectorizer(data):counter = CountVectorizer()TF = counter.fit_transform(data).toarray()  # 词频矩阵(TF)IDF = np.log((len(TF) + 1) / ((TF != 0).sum(axis=0) + 1)) + 1  # IDF 计算TF_IDF = TF * IDF  # 每个位置乘以对应的 IDFTF_IDF = normalize(TF_IDF, norm="l2")  # L2归一化return TF_IDF,counter.get_feature_names_out()def default_tokenizer(text):if any("\u4e00" <= ch <= "\u9fff" for ch in text):  # 判断是否含有中文字符return " ".join(jieba.cut(text))else:return text.lower()import jiebacorpus = ["我爱北京天安门","天安门上太阳升","The sun rises in the east","I love Beijing Tiananmen"
]data = [default_tokenizer(word) for word in corpus]
transfer,feature = myTfidVectorizer(data)
print(transfer,feature)

结果输出:

[[0.         0.         0.         0.         0.         0.0.         0.         0.78528828 0.6191303  0.        ][0.         0.         0.         0.         0.         0.0.         0.         0.         0.6191303  0.78528828][0.         0.35355339 0.35355339 0.         0.35355339 0.353553390.70710678 0.         0.         0.         0.        ][0.57735027 0.         0.         0.57735027 0.         0.0.         0.57735027 0.         0.         0.        ]] ['beijing' 'east' 'in' 'love' 'rises' 'sun' 'the' 'tiananmen' '北京' '天安门''太阳升']
http://www.dtcms.com/a/310746.html

相关文章:

  • <1> ES内存泄漏问题深度解析:从Scroll查询到Mapped Buffer异常
  • WAIC 2025 聚焦“智能时代”,AI在内容、硬件与交互上的多线突破
  • IFC 转换为 UG 的技术指南及迪威模型网在线转换推荐
  • 签名分发平台怎么看我的订单
  • 从零到一:Linux内核MMU启动与虚拟内存体系建立全流程详解
  • 代码随想录算法训练营三十三天|动态规划part06
  • [Linux入门] Linux 防火墙技术入门:从 iptables 到 nftables
  • 一文了解 `package.json` 和 `package-lock.json`文件
  • Mysql group by
  • 查看主板信息的3种方法
  • 修改DeepSeek翻译得不对的V语言字符串文本排序程序
  • 【ESP32 IDF】LVGL驱动触摸屏
  • AI Agent 视角:可执行程序的二进制格式,是一场「结构化语言」与「智能解析」的双向奔赴
  • 知识图谱的学习
  • 脚本统计MongoDB集合表数据量
  • 思途JSP学习 0801
  • 函数 dirfd 详解
  • 26考研|高等代数:欧几里得空间
  • TwinCAT3示例项目1
  • Redis学习18-分布式锁
  • 深拷贝与浅拷贝的定义
  • 机器学习特征工程----常见的特征构建与转换方法
  • dify 升级1.7.1 插件无法下载依赖
  • 分区管控与高效协同:EtherCAT转EtherCAT网关赋能纺织生产
  • c++-reverse_iterator
  • 什么是 Redis?从基础概念到技术本质的全面解析
  • 微信小程序页面间通信的实现方式
  • 升级的MS1836C HD转CVBS/S-Video转换器
  • WooCommerce 与 ERP 系统集成解决方案
  • Agents-SDK智能体开发[1]之入门