本文正在参加【NLP】入门(四):TF-IDF(代码篇) 结尾处,博主曾留下疑问:除了搜索匹配之外,TF-IDF 还能干些什么有意思的事情呢?
不知道大家思考的如何,接下来且听博主分析;
拓展
TF−IDFTF-IDF 其实就是一种将 词语重要程度 转换成 向量 的文档展示方式,那么在这些向量中, 必定会有主导型元素,而这些元素其实就是这篇文档中很重要的关键词了。
下面的功能就是给前三篇文档挑两个关键词:
def get_keywords(n=2):
for c in range(3):
# 选取第 c 篇文章的 tf_idf 值
col = tf_idf[:, c]
# 返回 tf_idf 值最大的前 n 个索引
idx = np.argsort(col)[-n:]
print("doc{}, top{} keywords {}".format(c, n, [i2v[i] for i in idx]))
当然,我们也可以将矩阵可视化,便于给读者更加直观的感受:
另外,如果 IDFIDF 是所有文档的全局信息,那么带有不同属性的文档集群可能拥有不同性质的 IDFIDF 分布。 比如在混合了金融领域的文档和普通文档的数据量中, 这会是个大而全的 IDFIDF,任意一个金融的词都可能对金融类搜索很重要, 因为它可以将金融文档和其他类型的文档有效区分开。但是如果我数据库中只有金融的文档, 想要更精准的搜索,这个大而全的 IDFIDF 就不适合了,那么我需要一个带有金融属性的 IDFIDF 表来优化对金融子领域的搜索。 这也是 IDFIDF 比较重要的应用方式之一。
当然,一个完善的搜索引擎不仅仅只有类似 TF−IDFTF-IDF 的算法,还有很多其他环节。从一个 query(搜索问句)开始,包含了很多 query 预处理部分,比如分词,敏感词过滤,纠错,拼音识别,查询改写,查询补全等等。再通过各种的召回策略,比如 TF-IDF/ElasticSearch 召回,得到候选答案,最后再做一些业务层面的过滤处理,才能到达你的搜索结果展示框里。所以看似一个小小的搜索引擎,实际上要包含很多大的工程项目。
问题
用 TF−IDFTF-IDF 来表示文档,然后可以用来做搜索和提取关键词。 可是在代码中存在一个机制,会引发 内存占用大 的问题。
TF−IDFTF-IDF 是一张二维表,分别代表文章索引和单词索引。文章量是可以无限增大的,单词量的增长也是很恐怖的。那么随着这两个维度的增长, 我们的内存总有一天会扛不住。好在我们可以利用一个节约内存的技术,叫做 Sparse Matrix
,稀疏矩阵,它只会存储有内容的值,而忽略无内容的值。 在这张巨大的二维表中,肯定每篇文章不一定会提及到所有词汇,这些不提及的词汇,我们当然可以不用存储。
用 Skearn
模块的 Sparse Matrix
功能,能更快速,有效地计算和存储海量的数据。
导入 sklearn
包:
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
然后就能计算文档中的 TF−IDFTF-IDF 了,像上篇博文 【NLP】入门(四):TF-IDF(代码篇) 中 IDF 计算一样,也可以使用下面的 vectorizer._idf
来提取,用来给新的数据使用。
vectorizer = TfidfVectorizer()
tf_idf = vectorizer.fit_transform(docs)
print("idf: ", [(n, idf) for idf, n in zip(vectorizer.idf_, vectorizer.get_feature_names())])
print("v2i: ", vectorizer.vocabulary_)
得到 TF−IDFTF-IDF 矩阵结果:
这时,我们就可以利用 TF−IDFTF-IDF 进行查找匹配了:
q = "I get a coffee cup"
qtf_idf = vectorizer.transform([q])
res = cosine_similarity(tf_idf, qtf_idf)
res = res.ravel().argsort()[-3:]
print("ntop 3 docs for '{}':n{}".format(q, [docs[i] for i in res[::-1]]))
后记
以上就是 【NLP】入门(五):TF-IDF(拓展篇) 的全部内容了。
希望本篇博文对大家有所帮助!
📝 上篇精讲:【NLP】入门(四):TF-IDF(代码篇)
💖 我是 𝓼𝓲𝓭𝓲𝓸𝓽,期待你的关注;
👍 创作不易,请多多支持;