一、关键词提取:从“词频”到“语义”的进化
做材料筛选,最基础的一步是什么?
我个人觉得,是关键词提取。你想想看,一堆文档摆在你面前,你要快速知道每篇在讲什么,靠肉眼扫读?不现实。靠AI帮你提炼出几个核心词,这才是效率的起点。
但关键词提取这事儿,没那么简单。我刚开始做的时候,以为就是数数哪个词出现得多。后来发现,嗯,太天真了。
1.1 TF-IDF:别被名字吓到,其实就是“找重点”
TF-IDF,全称 Term Frequency-Inverse Document Frequency。说白了,就是“这个词在本文里出现得多,但在其他文章里出现得少,那它很可能就是本文的关键词”。
我在项目中遇到过这样一个场景:一堆技术文档里,“算法”这个词几乎每篇都有,但“贝叶斯”只在某几篇出现。那“贝叶斯”的IDF值就高,TF-IDF总分就高,它就更可能是那几篇文档的关键词。
核心公式(理解即可,不用背):
- TF(词频)= 某个词在文档中出现的次数 / 文档总词数
- IDF(逆文档频率)= log(总文档数 / 包含该词的文档数 + 1)
- TF-IDF = TF × IDF
代码实现其实很简单,我习惯用 sklearn 的 TfidfVectorizer。给你看个例子:
from sklearn.feature_extraction.text import TfidfVectorizer
docs = [
"AI辅助材料筛选与验证实战课程",
"关键词提取基于TF-IDF和TextRank",
"语义相似度计算在材料匹配中的应用"
]
vectorizer = TfidfVectorizer(max_features=10)
tfidf_matrix = vectorizer.fit_transform(docs)
# 提取第一篇文章的关键词
feature_names = vectorizer.get_feature_names_out()
first_doc_scores = tfidf_matrix[0].toarray().flatten()
top_indices = first_doc_scores.argsort()[-3:][::-1]
print("第一篇文章的关键词:")
for idx in top_indices:
print(f"{feature_names[idx]}: {first_doc_scores[idx]:.4f}")
避坑指南:我曾经在项目里直接用原始词频,结果“的”、“是”、“在”这些停用词全排前面去了。记得一定要先做分词 + 去停用词,不然TF-IDF会给你一堆没用的结果。
1.2 TextRank:让词与词之间“投票”
TF-IDF有个问题——它只看统计,不看词与词之间的关系。比如“人工智能”和“AI”明明是同一个意思,但TF-IDF会当成两个词处理。
TextRank 的思路就不一样了。它借鉴了 Google PageRank 的思想:一个词的重要性,取决于它周围有哪些词。如果“深度学习”经常和“神经网络”一起出现,那这两个词就会互相“投票”,提升对方的权重。
具体怎么做?三步走:
- 构建共现图:把文档分词后,设定一个窗口大小(比如5个词),窗口内的词两两之间建立边。
- 迭代计算权重:每个词的初始权重相同,然后不断迭代,直到收敛。
- 排序取Top N:权重最高的几个词,就是关键词。
我用 jieba 的 TextRank 接口比较多,因为它内置了分词和词性过滤:
import jieba.analyse
text = "AI辅助材料筛选与验证实战课程,重点讲解关键词提取与语义理解"
keywords = jieba.analyse.textrank(
text,
topK=5,
withWeight=True,
allowPOS=('n', 'v', 'a') # 只保留名词、动词、形容词
)
for word, weight in keywords:
print(f"{word}: {weight:.4f}")
注意:TextRank 对短文本效果一般。如果文档只有一两句话,共现图太稀疏,结果可能不如 TF-IDF。我建议长文档用 TextRank,短文本用 TF-IDF,或者两者结合。
二、语义相似度:让机器“理解”意思
关键词提取只是第一步。真正让材料筛选变得智能的,是语义相似度计算。
你想想看,用户搜“机器学习”,你只匹配到“机器学习”这个词的文档,但漏掉了“深度学习”、“神经网络”这些相关的,那这个筛选系统就太死板了。
2.1 从词袋到词向量
传统方法用词袋模型(Bag of Words),把文档变成一个稀疏向量。但“苹果”和“香蕉”在词袋里是完全不同的维度,相似度为0。这显然不合理。
后来有了词向量(Word Embedding),比如 Word2Vec、GloVe。每个词被映射到一个稠密向量里,语义相近的词在向量空间里距离也近。比如“苹果”和“香蕉”的向量夹角,会比“苹果”和“汽车”小得多。
| 方法 | 维度 | 语义理解 | 计算成本 |
|---|---|---|---|
| 词袋模型 | 高(词汇表大小) | 无 | 低 |
| TF-IDF | 高(词汇表大小) | 弱(仅统计) | 低 |
| Word2Vec | 低(100-300) | 强 | 中 |
| BERT | 低(768) | 极强 | 高 |
2.2 计算相似度的两种常用方式
有了向量之后,怎么算相似度?我常用两种:
- 余弦相似度:计算两个向量夹角的余弦值。值越接近1,越相似。这是最常用的方法。
- 欧氏距离:计算向量在空间中的直线距离。距离越小,越相似。但要注意,它对向量长度敏感。
给你看个实际例子,用 sentence-transformers 库计算句子相似度:
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
sentences = [
"AI辅助材料筛选",
"人工智能辅助材料验证",
"今天天气不错"
]
embeddings = model.encode(sentences)
# 计算第一句和第二句的相似度
sim_1_2 = util.cos_sim(embeddings[0], embeddings[1])
sim_1_3 = util.cos_sim(embeddings[0], embeddings[2])
print(f"第一句 vs 第二句: {sim_1_2.item():.4f}") # 应该很高
print(f"第一句 vs 第三句: {sim_1_3.item():.4f}") # 应该很低
关键点:语义相似度不是万能的。如果两个文档用词完全不同但意思相近(比如“买电脑”和“采购笔记本”),BERT这类模型能搞定。但如果文档是专业术语和日常用语混搭,效果可能会打折扣。我建议先用关键词粗筛,再用语义相似度精排,效率最高。
三、知识体系总览
说了这么多,我把本章的核心逻辑画成了一张图。你一看就明白:
我的建议:实际项目中,别只依赖一种方法。我通常的做法是:先用 TF-IDF 快速过滤掉明显不相关的文档,再用 TextRank 提取核心关键词,最后用 BERT 做语义匹配。三层过滤下来,准确率能到 90% 以上。
好了,这一章就到这里。关键词提取和语义相似度,是AI辅助材料筛选的两大基石。你先把这两个概念吃透,后面讲实战的时候,你会发现它们无处不在。