信息检索系统TFIDF得分计算效率低及运行报错问题咨询
信息检索TF-IDF系统问题修复与优化方案
1 现有bug修复
1.1 数组长度不匹配问题
该错误由两个低级错误共同触发:
- 计算查询词IDF时传参错误:原代码中
inverse_document_frequency(word, new_list)的第二个参数传入了当前查询的切词列表,而非全量摘要列表,部分不存在于全量摘要的词会触发逻辑异常 - 查询词未做去重处理:过滤后的
new_list保留了重复词,但vector_dict的key会自动去重,导致查询向量长度和字典key长度不一致,到第6个查询刚好触发长度校验失败
修复代码:
for query in query_array: query_words = query.split(" ") # 先对查询词去重+过滤停用词和非字母字符 new_list = list({word for word in query_words if word not in closed_class_stop_words and word.isalpha()}) vector = [] vector_dict = {} for word in new_list: tf = term_frequency(word, Counter(new_list)) # 计算IDF传入全量摘要列表 idf = inverse_document_frequency(word, abstract_word_list) tfidf = tf * idf vector.append(tfidf) vector_dict[word] = tfidf query_vectors.append(vector) query_dict.append(vector_dict)
1.2 排序结果异常问题
该问题完全由余弦相似度公式写错导致:
原代码cos = dot(query_vector, abstract_vector) / (np.sqrt(dot(query_vector, abstract_vector)) * np.sqrt(dot(query_vector, abstract_vector)))的分母两次使用了两个向量的点积,计算结果恒等于1,排序时只能默认按第二个字段(摘要索引)升序排列,所以呈现为原有数字顺序。
同时默认升序排序会把相关性最低的结果放在前面,需要改为降序。
修复代码:
for i in range(len(query_vectors)): rank = [] query_vector = query_vectors[i] # 提前计算查询向量模长,避免重复计算 q_norm = np.linalg.norm(query_vector) for j in range(len(all_vector_list[i])): abstract_vector = all_vector_list[i][j] a_norm = np.linalg.norm(abstract_vector) # 分母为0的边界处理 if q_norm == 0 or a_norm ==0: cos = 0 else: cos = np.dot(query_vector, abstract_vector) / (q_norm * a_norm) rank.append((cos, j)) # 改为降序排序,相关性高的在前 rank.sort(reverse=True) for k in range(len(rank)): print(i, rank[k][1])
2 运行效率优化方案
原有算法时间复杂度为O(查询数*查询词数*摘要总数),优化后可降至O(查询数*平均查询词数*平均词出现次数):
- 提前构建倒排索引:存储每个词对应的摘要索引和该词在摘要中的TF-IDF值,不需要每次遍历全量摘要匹配查询词
- 提前预计算所有摘要的向量模长,不需要每次查询重复计算
优化核心逻辑示例:
# 提前构建倒排索引 inverted_index = {} abs_norm_list = [] for abs_idx, tf_dict in enumerate(abstract_tf_dict): abs_vec = [] for word, tf in tf_dict.items(): tfidf = tf * abstract_idf_dict[word] abs_vec.append(tfidf) if word not in inverted_index: inverted_index[word] = [] inverted_index[word].append((abs_idx, tfidf)) # 预存摘要模长 abs_norm_list.append(np.linalg.norm(abs_vec)) # 直接用倒排索引计算相似度,不需要生成全量摘要向量 for q_idx, q_dict in enumerate(query_dict): dot_product = np.zeros(len(abstract_word_list)) q_vec = list(q_dict.values()) q_norm = np.linalg.norm(q_vec) for word, q_tfidf in q_dict.items(): if word in inverted_index: for abs_idx, a_tfidf in inverted_index[word]: dot_product[abs_idx] += q_tfidf * a_tfidf # 计算相似度并排序 cos_sim = dot_product / (q_norm * np.array(abs_norm_list) + 1e-8) # 加极小值避免分母为0 rank = sorted([(cos_sim[j], j) for j in range(len(abstract_word_list))], reverse=True) for k in range(len(rank)): print(q_idx, rank[k][1])
内容的提问来源于stack exchange,提问作者bloomsdayforever
相关产品推荐
相关产品推荐

