You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
llm/05-Embedding/04-美食评论小案例.py

96 lines
4.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import ast
import pandas as pd
import numpy as np
from langchain_huggingface import HuggingFaceEmbeddings
model_name = "BAAI/bge-small-zh-v1.5"
model_kwargs = {'device': 'cpu'}
encode_kwargs = {'normalize_embeddings': True} # set True to compute cosine similarity
bge_hf_embedding = HuggingFaceEmbeddings(
model_name=model_name,
model_kwargs=model_kwargs,
encode_kwargs=encode_kwargs
)
# 【2】该函数就是把数据变为向量的函数
def text_2_embedding(text):
resp = bge_hf_embedding.embed_documents(
[text]
)
return resp[0]
# 【1】读取原始文件中的美食评论数据通过调用Embedding模型得到对应的向量并保持到新文件中
def embedding_2_file(source_file, output_file):
"""读取原始的美食评论数据通过调用Embedding模型得到向量并保持到新文件中"""
# 步骤1、准备数据并读取从第index_col个字段读取
# pandas 是 Python 中用于数据处理和分析的核心工具,专门解决表格类数据的各类操作需求。
# pandas 支持读取几乎所有常见的结构化数据格式Excel、CSV、SQL、JSON 等),并能将处理后的数据便捷地保存为这些格式,解决了数据导入导出的基础问题。
df = pd.read_csv(source_file, index_col=0)
# 读取后提取所需要的字段
df = df[['Time', 'ProductId', 'UserId', 'Score', 'Summary', 'Text']]
print(df.head(2)) # 打印前两行看看
# 步骤2 清洗数据 和 合并数据
df = df.dropna() # 如果有空数据,就删掉
# 把评论的摘要 和 内容字段 合并成 一个字段方便后续处理放入新字段text_content
df['text_content'] = 'Summary: ' + df.Summary.str.strip() + "; Text: " + df.Text.str.strip()
print(df.head(2)) # 打印前两行看看 发现确实增加一个字段text_content
# 步骤3: 对text_content向量化存到一个新的文件中向量单独存入embedding字段
df['embedding'] = df.text_content.apply(lambda x: text_2_embedding(x))
# 保存到新文件
df.to_csv(output_file)
def cosine_distance(a, b):
"""计算余弦距离"""
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
# 【3】input用户输入的问题 embedding_file 要检索的文件, top_n 按照相似性最多检索3个
def search_text(input, embedding_file, top_n=3):
"""
根据用户输入的问题进行语义检索返回最相似的前top_n个结果
:param input:
:param top_n:
:return:
"""
# 读取新文件
df_data = pd.read_csv(embedding_file)
# 取文件中df_data['embedding']字段,该字段在文件中是以字符串存储的
# 所以你从文件读取出来这个字段也是字符串类型的啊
# 要把这个字符串变成向量进行后续的数学计算保持到新字段embedding_vector
# 目前这个新字段是在内存中的,没有在文件里
df_data['embedding_vector'] = df_data['embedding'].apply(ast.literal_eval)
# 把输入问题转化为向量
input_vector = text_2_embedding(input)
# 内存中embedding_vector字段和input_vector进行相似度比较
# 按照余弦相似度比较,余弦相似度单独封装到函数 cosine_distance中
# 产生一个新字段 similarity
df_data['similarity'] = df_data.embedding_vector.apply(lambda x: cosine_distance(x, input_vector))
res = (
# 对similarity字段排序降序排
df_data.sort_values('similarity', ascending=False)
# 返回topn,此案例是返回3个
.head(top_n)
# 把text_content字段的Summary: 替换为"",把; Text: 替换为""
.text_content.str.replace('Summary: ', "") # text_content是字段名
.str.replace('; Text: ', ';')
)
# 把topn的结果打印每打印一行画个虚线
for r in res:
print(r)
print('-' * 30)
if __name__ == '__main__':
# 可以先单独测试函数embedding_2_file('../datas/fine_food_reviews_1k.csv', '../datas/output_embedding.csv')
search_text('delicious beans', './output_embedding.csv')