一、关键词提取:从“词频”到“语义”的进化

做材料筛选,最基础的一步是什么?

我个人觉得,是关键词提取。你想想看,一堆文档摆在你面前,你要快速知道每篇在讲什么,靠肉眼扫读?不现实。靠AI帮你提炼出几个核心词,这才是效率的起点。

但关键词提取这事儿,没那么简单。我刚开始做的时候,以为就是数数哪个词出现得多。后来发现,嗯,太天真了。

1.1 TF-IDF:别被名字吓到,其实就是“找重点”

TF-IDF,全称 Term Frequency-Inverse Document Frequency。说白了,就是“这个词在本文里出现得多,但在其他文章里出现得少,那它很可能就是本文的关键词”

我在项目中遇到过这样一个场景:一堆技术文档里,“算法”这个词几乎每篇都有,但“贝叶斯”只在某几篇出现。那“贝叶斯”的IDF值就高,TF-IDF总分就高,它就更可能是那几篇文档的关键词。

核心公式(理解即可,不用背):

  • TF(词频)= 某个词在文档中出现的次数 / 文档总词数
  • IDF(逆文档频率)= log(总文档数 / 包含该词的文档数 + 1)
  • TF-IDF = TF × IDF

代码实现其实很简单,我习惯用 sklearnTfidfVectorizer。给你看个例子:

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 的思想:一个词的重要性,取决于它周围有哪些词。如果“深度学习”经常和“神经网络”一起出现,那这两个词就会互相“投票”,提升对方的权重。

具体怎么做?三步走:

  1. 构建共现图:把文档分词后,设定一个窗口大小(比如5个词),窗口内的词两两之间建立边。
  2. 迭代计算权重:每个词的初始权重相同,然后不断迭代,直到收敛。
  3. 排序取Top N:权重最高的几个词,就是关键词。

我用 jiebaTextRank 接口比较多,因为它内置了分词和词性过滤:

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 筛选结果

我的建议:实际项目中,别只依赖一种方法。我通常的做法是:先用 TF-IDF 快速过滤掉明显不相关的文档,再用 TextRank 提取核心关键词,最后用 BERT 做语义匹配。三层过滤下来,准确率能到 90% 以上。

好了,这一章就到这里。关键词提取和语义相似度,是AI辅助材料筛选的两大基石。你先把这两个概念吃透,后面讲实战的时候,你会发现它们无处不在。


专注资料整理