🔍 一、TF-IDF的核心思想
TF-IDF(Term Frequency-Inverse Document Frequency)是一种评估词语在文档集合中重要性的统计方法
。其核心逻辑基于两点:
- 词频(TF):词在单篇文档中出现的频率越高,对该文档的代表性越强。
- 逆文档频率(IDF):词在整个语料库中出现的文档越少,其区分不同文档的能力越强。
💡 简单来说:高频且稀有的词是文档的“关键词”(如技术术语),而“的”、“是”等高频常见词因IDF值低被过滤。
📊 二、算法原理与公式拆解
1. 词频(TF)的计算
衡量词 t 在文档 d 中的局部重要性,通常进行归一化防止长文档主导结果
例如:文档 “苹果手机 苹果电脑” 中,“苹果”的TF = 2/3≈0.67。
2. 逆文档频率(IDF)的计算
评估词 t 的全局稀缺性,惩罚常见词(如停用词)
加1平滑:防止 nt=0 时分母为零。若“苹果”在1000篇文档中出现20次,则IDF = log(1000/21)≈1.67。
3. TF-IDF的合成
将TF与IDF相乘,得到词的最终权重
上例中,“苹果”的TF-IDF = 0.67×1.67≈1.12。
🛠️三、API接口参数
方法 | 作用 | 调用时机 |
---|---|---|
fit(raw_documents) | 学习词汇表和 IDF 值(不返回矩阵) | 仅需训练词汇表时使用 |
transform(raw_documents) | 将文本转换为 TF-IDF 矩阵(需先调用 fit ) | 处理测试集或新数据时使用 |
fit_transform(raw_documents) | 一步完成词汇表学习和矩阵生成 | 最常用,训练阶段直接使用 |
get_feature_names_out() | 获取有序特征词列表(按列索引排列) | 查看词汇表或分析特征时使用 |
get_params() | 获取当前参数配置 | 调试或保存配置时使用 |
💻 四、Python实现示例
使用sklearn
库快速计算TF-IDF矩阵:
from sklearn.feature_extraction.text import TfidfVectorizer
# 文档集示例
documents = [
"苹果手机 苹果电脑",
"华为手机 华为平板",
"小米手机 小米手环"
]
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(documents)
# 输出词表及TF-IDF矩阵
print("特征词列表:", vectorizer.get_feature_names_out())
print("TF-IDF矩阵:\n", tfidf_matrix.toarray())
输出说明:
- 每行对应一个文档的TF-IDF向量。(其中第几个表示特征表的第几个值)
- 每列对应一个特征词(如“华为”、“苹果”)。
- 值越高,表示该词对当前文档越重要 ✅。
💻 五、实战演练
下面我们来实现一个红楼梦书籍的重要词提取,这直接我们要进行数据处理。
初始我们的数据集就是一本数,全部内容在一个txt中。下面是步骤:
根据您提供的图片,我已准确识别并提取所有文字内容。以下是图片中的完整文字信息,严格按原始结构和步骤呈现:
步骤:
-
处理数据集成标准格式
a. 根据段落特征把文章进行分篇
b. 把每篇的内容变成一行,然后放在一个文件中 -
jjiaba分词
a 导入红楼们专属的jieba词库
b jieba分词,并且把早停词去除
3 进行模型训练
a. 训练模型
b. 展示参数
代码展示
文章分卷
import os.path
import time
wz=open('红楼梦.txt','r',encoding='utf-8')
file=open('.\红楼梦卷\开头.txt','w',encoding='utf-8')
i=10
for line in wz:
if '卷 第'in line:
file.close()
name=line.strip() + '.txt'
path=os.path.join('.\红楼梦卷',name)
file = open(path,'w',encoding='utf-8')
i=0
if i<=3:
i=i+1
continue
file.write(line)
file.close()
#把数据处理成,要求的样子
import os.path
jg=open("结果.txt","w",encoding="utf-8")
a=os.walk("红楼梦卷")
print(a)
for root,dirs,files in a:
for filename in files:
jg.write(filename)
path=os.path.join(root,filename)
# print(path)
file=open(path,encoding="utf-8")
for line in file.readlines():
line=line.strip()
jg.write(line)
jg.write("\n")
jg.close()
#jieba分词,并且去除
import pandas as pd
import jieba
stopwords=pd.read_table('StopwordsCN.txt',encoding='utf-8')
print(stopwords)
ck=open('红楼梦词库.txt',encoding='utf-8')
# print(ck.read())
jieba.load_userdict(ck)
file=open('结果.txt',encoding='utf-8')
a=jieba.lcut(file.read())
# print(a)
file1=open('结果1.txt','w',encoding='utf-8')
for i in a:
if i in stopwords.values or i==' ':
continue
content=i+' '
file1.write(content)
file1.close()
from sklearn.feature_extraction.text import TfidfVectorizer
model=TfidfVectorizer()
data=open('结果1.txt',encoding='utf-8')
jg=model.fit_transform(data)
# print(jg)
wordlist=model.get_feature_names_out()
print(wordlist)
import pandas as pd
df=pd.DataFrame(jg.T.todense(),index=wordlist)
print(df)
# featurelist = df.iloc[:,5].tolist()
# print(featurelist)
for i in range(120):
series = df.iloc[:,i]
sorted_series =series.sort_values(ascending=False)
gjc = sorted_series.head(10)
print('第{}回的核心关键词是:'.format(i+1),list(gjc.items()))
代码详解:
1 、分卷处理:按章节分割原始文本
import os.path
import time
wz = open('红楼梦.txt', 'r', encoding='utf-8') # 打开原始文本
file = open('.\红楼梦卷\开头.txt', 'w', encoding='utf-8') # 临时文件,后续被覆盖
i = 10 # 初始跳过行数计数器
for line in wz:
if '卷 第' in line: # 检测章节标题(如"卷 第一回")
file.close() # 关闭当前章节文件
name = line.strip() + '.txt' # 用章节标题命名新文件(如"卷 第一回.txt")
path = os.path.join('.\红楼梦卷', name) # 构建文件路径
file = open(path, 'w', encoding='utf-8') # 创建新章节文件
i = 0 # 重置行计数器,准备跳过卷头
if i <= 3: # 跳过卷头的前4行(标题行+3行冗余内容)
i = i + 1
continue
file.write(line) # 将有效内容写入当前章节文件
file.close() # 关闭最后一个章节文件
关键逻辑:
- 章节检测:通过关键词
卷 第
识别新章节起始位置。 - 文件管理:
- 每检测到新章节,关闭旧文件并创建以章节标题命名的新文件(如
卷 第一回.txt
)。 - 跳过章节头部的冗余行(通过
i<=3
控制跳过4行)。
- 每检测到新章节,关闭旧文件并创建以章节标题命名的新文件(如
- 目录结构:所有分卷文件保存在
红楼梦卷
文件夹中。
2、数据整合:合并分卷内容为单行格式
import os.path
jg = open("结果.txt", "w", encoding="utf-8")
a = os.walk("红楼梦卷") # 遍历分卷文件目录
for root, dirs, files in a:
for filename in files:
jg.write(filename) # 写入文件名(如"卷 第一回.txt")
path = os.path.join(root, filename)
file = open(path, encoding="utf-8")
for line in file.readlines():
line = line.strip() # 去除每行首尾空白符
jg.write(line) # 将每卷内容压缩为单行
jg.write("\n") # 卷间用换行分隔
jg.close()
关键逻辑:
- 文件遍历:
os.walk
获取红楼梦卷
下所有分卷文件。 - 单行压缩:
- 每卷内容去除换行符和首尾空格,合并为单行字符串。
- 各卷以文件名 + 压缩内容的形式写入
结果.txt
,卷间用换行符分隔。
- 输出格式示例:
卷 第一回.txt 甄士隐梦幻识通灵 贾雨村风尘怀闺秀... 卷 第二回.txt 贾夫人仙逝扬州城 冷子兴演说荣国府...
3、分词与停用词清洗
import pandas as pd
import jieba
# 加载停用词表(每行一个词)
stopwords = pd.read_table('StopwordsCN.txt', encoding='utf-8') # 格式:["的", "了", "是"]
# 加载自定义词库(如"林黛玉"、"荣国府"等专有名词)
ck = open('红楼梦词库.txt', encoding='utf-8')
jieba.load_userdict(ck) # 提升专有名词分词准确性
# 读取压缩后的文本并分词
file = open('结果.txt', encoding='utf-8')
a = jieba.lcut(file.read()) # 精确模式分词
# 清洗停用词和空格
file1 = open('结果1.txt', 'w', encoding='utf-8')
for i in a:
if i in stopwords.values or i == ' ': # 过滤停用词和空格
continue
content = i + ' ' # 用空格分隔有效词
file1.write(content)
file1.close()
关键逻辑:
- 停用词过滤:使用中文停用词表(如"的"、"了")移除无意义词。
- 自定义词典:通过
红楼梦词库.txt
添加专有名词,避免错误拆分(如"林黛玉"不被拆为"林"和"黛玉")。 - 分词策略:
jieba.lcut
采用精确模式,适合后续TF-IDF分析。 - 输出格式:清洗后的文本以空格分隔词语(如
甄士隐 通灵 贾雨村...
)。
4、TF-IDF关键词提取
from sklearn.feature_extraction.text import TfidfVectorizer
# 初始化TF-IDF模型
model = TfidfVectorizer()
data = open('结果1.txt', encoding='utf-8') # 注:此处需按行读取文档列表
#这里data已经转化为标准形式了,直接训练就行!
# 训练模型并转换数据
jg = model.fit_transform(data) # 生成稀疏矩阵(文档数×词汇数)
wordlist = model.get_feature_names_out() # 获取词汇表(如['甄士隐', '通灵', ...])
# 转换为DataFrame便于分析
import pandas as pd
df = pd.DataFrame(jg.T.todense(), index=wordlist) # 转置后:行=词汇,列=文档
# 提取每卷(文档)的Top10关键词
for i in range(120): # 假设共120卷
series = df.iloc[:, i] # 取第i卷的TF-IDF向量
sorted_series = series.sort_values(ascending=False) # 按权重降序排序
gjc = sorted_series.head(10) # 取权重最高的前10个词
print(f'第{i+1}回的核心关键词是:', list(gjc.items())) # 输出(词,权重)列表
- DataFrame设计:
- 常规用法:行=文档,列=词汇 → 直接对每行取Top10关键词。
- 修正:
df = pd.DataFrame(jg.todense(), columns=wordlist) # 行=文档,列=词汇 for i in range(df.shape[0]): series = df.iloc[i] # 取第i个文档 sorted_series = series.sort_values(ascending=False) gjc = sorted_series.head(10)
- TF-IDF参数优化:
- 可添加
stop_words
参数二次过滤停用词,或设置ngram_range=(1,2)
捕获词组(如"荣国府")。
- 可添加