3、示例选择策略:随机选择、基于相似度选择、多样性选择、代表性选择

少样本提示,说白了就是给模型「打样」。但问题来了——你手头可能有几百条数据,到底挑哪几条给模型看?

我见过不少新手,直接随机抽几条就往上怼。结果呢?模型输出忽好忽坏,跟开盲盒似的。今天咱们就把这四种策略掰开揉碎了讲清楚。

3.1 随机选择——最省事,也最不靠谱

随机选择,就是闭着眼睛从数据池里抓几条。代码写起来最简单:

import random

examples = all_data[:100]  # 假设有100条数据
selected = random.sample(examples, 5)  # 随机挑5条

嗯,这里要注意——随机选择有个致命问题:稳定性差。你这次抽到的样本可能刚好覆盖了关键模式,下次抽到的全是边缘案例。

我曾经踩过的坑:有一次做情感分类,随机抽了3条样本,结果全是「正面」评价。模型直接学歪了,输出清一色好评。后来我改成固定种子(random.seed(42))才勉强稳住。

什么时候用随机?我个人习惯在快速原型验证阶段用。数据量特别大(比如上万条)且分布均匀时,随机也能凑合。但正式项目?我劝你别偷懒。

3.2 基于相似度选择——让模型「抄近道」

这个策略的核心思想:找跟当前输入最像的样本做示例。你想想看,模型看到相似的例子,是不是更容易理解你的意图?

具体做法分三步:

  1. 把每条数据转成向量(用BERT或Sentence-BERT都行)
  2. 计算当前输入与所有候选样本的余弦相似度
  3. 挑相似度最高的K条

代码长这样:

from sklearn.metrics.pairwise import cosine_similarity

# 假设已有向量矩阵
query_vec = get_embedding("今天天气真好")  # 当前输入
candidate_vecs = get_embeddings(all_examples)  # 候选池

# 算相似度
scores = cosine_similarity([query_vec], candidate_vecs)[0]
# 挑Top-3
top_indices = scores.argsort()[-3:][::-1]

我的实战经验:在客服问答系统里,用相似度选择比随机选择准确率提升了12%。但有个坑——如果候选池里全是相似样本,模型容易「过拟合」到局部模式。说白了就是,它只学会了处理类似问题,遇到新花样就懵了。

3.3 多样性选择——避免「一叶障目」

多样性选择,就是让选出来的样本覆盖尽可能多的类型。为什么要这么做?

举个例子:你要教模型识别动物。如果示例全是猫,模型看到狗也会说成猫。多样性选择就是要避免这种「偏科」现象。

实现方法有很多,我常用的是聚类+采样

from sklearn.cluster import KMeans

# 先聚类
kmeans = KMeans(n_clusters=5, random_state=42)
clusters = kmeans.fit_predict(all_vectors)

# 每个簇里挑一条
selected = []
for i in range(5):
    cluster_indices = np.where(clusters == i)[0]
    selected.append(random.choice(cluster_indices))

还有一种更直接的方法——最大边际相关性(MMR)。它同时考虑「跟查询的相似度」和「样本间的差异性」:

def mmr_selection(query_vec, candidate_vecs, k=3, lambda_param=0.5):
    selected = []
    remaining = list(range(len(candidate_vecs)))
    
    for _ in range(k):
        scores = []
        for idx in remaining:
            sim_to_query = cosine_similarity([query_vec], [candidate_vecs[idx]])[0][0]
            sim_to_selected = max([cosine_similarity([candidate_vecs[idx]], [candidate_vecs[s]])[0][0] for s in selected]) if selected else 0
            mmr_score = lambda_param * sim_to_query - (1 - lambda_param) * sim_to_selected
            scores.append(mmr_score)
        best_idx = remaining[np.argmax(scores)]
        selected.append(best_idx)
        remaining.remove(best_idx)
    return selected

关键点:lambda_param控制「相似度」和「多样性」的权重。lambda越大,越偏向相似度;lambda越小,越偏向多样性。我一般从0.5开始调。

3.4 代表性选择——找「课代表」

代表性选择,就是挑出最能代表整体数据分布的样本。说白了,就是找「课代表」——它一个人就能反映全班的大致水平。

怎么做?我推荐两种方法:

方法 原理 适用场景
K-Centroid 找离聚类中心最近的样本 数据有明显簇结构
核心集选择 用贪心算法覆盖整个空间 数据分布均匀

K-Centroid的实现很简单:

# 先找聚类中心
centroids = kmeans.cluster_centers_

# 每个簇里找离中心最近的样本
representatives = []
for centroid in centroids:
    distances = np.linalg.norm(all_vectors - centroid, axis=1)
    rep_idx = np.argmin(distances)
    representatives.append(rep_idx)

注意:代表性选择有个隐含假设——你的数据分布能代表真实场景。如果数据本身就有偏差,选出来的「代表」也会带偏模型。我曾经在一个不平衡数据集上用过,结果选出来的全是多数类样本,少数类直接被忽略了。

3.5 四种策略怎么选?

我把这四种策略的优缺点整理成了一张表,方便你对照:

策略 优点 缺点 推荐场景
随机选择 简单、快 不稳定、质量不可控 快速原型、数据量大且均匀
相似度选择 针对性强、准确率高 容易过拟合、计算成本高 问答系统、分类任务
多样性选择 覆盖广、泛化好 可能包含低质量样本 开放域生成、多类别任务
代表性选择 全局视角、稳定 依赖数据质量、计算复杂 数据分布已知、需要稳定输出

我个人习惯的决策流程是这样的:

  • 时间紧、任务轻 → 随机选择(但记得固定种子)
  • 任务对准确性要求高 → 相似度选择
  • 需要模型有创造力 → 多样性选择
  • 追求稳定、可复现 → 代表性选择

进阶技巧:别死磕一种策略。我经常把相似度和多样性结合起来——先用相似度筛出Top-20,再用MMR从里面挑Top-3。这样既保证了相关性,又避免了样本扎堆。

最后说一句:示例选择没有银弹。你最好在自己的数据上跑几轮对比实验,看看哪种策略最适合你的场景。毕竟,实践出真知嘛。