使用嵌入进行零样本分类

在本笔记本中,我们将使用嵌入和零标记数据对评论的情感进行分类!数据集在 Get_embeddings_from_dataset Notebook 中创建。

我们将积极情感定义为 4 星和 5 星评论,将消极情感定义为 1 星和 2 星评论。3 星评论被视为中性,我们在此示例中不使用它们。

我们将通过嵌入每个类的描述,然后比较样本和类嵌入之间的余弦距离来执行零样本分类。

import pandas as pd
import numpy as np
from ast import literal_eval

from sklearn.metrics import classification_report

EMBEDDING_MODEL = "text-embedding-3-small"

datafile_path = "data/fine_food_reviews_with_embeddings_1k.csv"

df = pd.read_csv(datafile_path)
df["embedding"] = df.embedding.apply(literal_eval).apply(np.array)

# convert 5-star rating to binary sentiment
df = df[df.Score != 3]
df["sentiment"] = df.Score.replace({1: "negative", 2: "negative", 4: "positive", 5: "positive"})

零样本分类

为了执行零样本分类,我们希望在没有任何训练的情况下预测样本的标签。为此,我们可以简单地嵌入每个类的简短描述,例如积极和消极,然后比较样本嵌入和标签嵌入之间的余弦距离。

与样本输入最相似的标签是预测的标签。我们还可以将预测分数定义为与积极标签的余弦距离与与消极标签的余弦距离之差。此分数可用于绘制精确率-召回率曲线,通过选择不同的阈值,可用于选择不同的精确率-召回率权衡。

from utils.embeddings_utils import cosine_similarity, get_embedding
from sklearn.metrics import PrecisionRecallDisplay

def evaluate_embeddings_approach(
    labels = ['negative', 'positive'],
    model = EMBEDDING_MODEL,
):
    label_embeddings = [get_embedding(label, model=model) for label in labels]

    def label_score(review_embedding, label_embeddings):
        return cosine_similarity(review_embedding, label_embeddings[1]) - cosine_similarity(review_embedding, label_embeddings[0])

    probas = df["embedding"].apply(lambda x: label_score(x, label_embeddings))
    preds = probas.apply(lambda x: 'positive' if x>0 else 'negative')

    report = classification_report(df.sentiment, preds)
    print(report)

    display = PrecisionRecallDisplay.from_predictions(df.sentiment, probas, pos_label='positive')
    _ = display.ax_.set_title("2-class Precision-Recall curve")

evaluate_embeddings_approach(labels=['negative', 'positive'], model=EMBEDDING_MODEL)
              精确率    召回率  f1-score   支持


    negative       0.54      0.92      0.68       136
    positive       0.98      0.87      0.92       789

    准确率                           0.87       925
   宏观平均       0.76      0.89      0.80       925
加权平均       0.92      0.87      0.89       925

png

我们可以看到,这个分类器已经表现得非常出色。我们使用了相似性嵌入和最简单的标签名称。让我们尝试使用更具描述性的标签名称和搜索嵌入来改进这一点。

evaluate_embeddings_approach(labels=['An Amazon review with a negative sentiment.', 'An Amazon review with a positive sentiment.'])
              精确率    召回率  f1-score   支持


    negative       0.76      0.96      0.85       136
    positive       0.99      0.95      0.97       789

    准确率                           0.95       925
   宏观平均       0.88      0.96      0.91       925
加权平均       0.96      0.95      0.95       925

png

使用搜索嵌入和描述性名称可带来性能的进一步提升。

evaluate_embeddings_approach(labels=['An Amazon review with a negative sentiment.', 'An Amazon review with a positive sentiment.'])
              精确率    召回率  f1-score   支持


    negative       0.76      0.96      0.85       136
    positive       0.99      0.95      0.97       789

    准确率                           0.95       925
   宏观平均       0.88      0.96      0.91       925
加权平均       0.96      0.95      0.95       925

png

如上所示,使用嵌入进行零样本分类可以带来出色的结果,特别是当标签比简单单词更具描述性时。