解决系统准确性问题的策略
在处理系统性能问题时,我们常常会遇到准确性不足的情况。本文将探讨如何通过改变数据和重构应用这两种策略来解决系统准确性问题。
1. 系统性能评估
在解决系统准确性问题之前,我们需要对系统的性能进行评估。通过观察混淆矩阵的主对角线,我们可以看到正确的预测结果。例如,ABBR 被正确预测为 ABBR 达 137 次。同时,我们也能发现每个类别的预测错误情况,其中最常见的错误是将 ENTY 错误分类为 ABBR,出现了 11 次。
此外,我们还可以查看分类报告,以了解每个类别的精确率、召回率和 F1 分数,以及整个测试集的总体平均值。以下是分类报告的示例:
['ABBR', 'DESC', 'ENTY', 'HUM', 'LOC', 'NUM']
precision recall f1-score support
ABBR 0.90 0.99 0.94 138
DESC 1.00 0.78 0.88 9
ENTY 0.97 0.80 0.88 94
HUM 0.97 0.97 0.97 65
LOC 0.96 0.98 0.97 113
NUM 0.94 0.96 0.95 81
accuracy 0.94 500
macro avg 0.96 0.91 0.93 500
weighted avg 0.94 0.94 0.94 500
从报告中可以看出,DESC 和 ENTY 的召回率相对较低,这反映出这些类别的部分项目被错误地识别为 ABBR。
需要指出的是,系统是否足够好的判断实际上取决于应用场景和开发者的决策。在某些应用中,即使结果可能有误,给用户提供一些结果也是更好的选择;而在其他应用中,确保每个结果都正确至关重要,即使系统几乎总是不得不说“我不知道”。这也意味着在某些应用中,召回率更为重要,而在其他情况下,精确率更为重要。
2. 解决准确性问题的策略
解决系统性能问题主要有两种策略:改变数据和重构应用。一般来说,改变数据相对容易,并且在需要保持应用结构不变的情况下,是更好的策略。
2.1 改变数据
改变数据可以显著提高系统的性能,但并非总是可行。如果你使用的是标准数据集,并且希望与其他研究人员的工作进行比较,那么你可能无法控制数据集。在这种情况下,改变数据会使你的系统性能与其他研究人员的结果不可比。如果系统性能不理想但无法改变数据,那么唯一的选择是使用不同的模型或调整超参数来改进算法。
然而,如果你对数据集有控制权,改变数据可以是一种非常有效的方法。许多性能问题是由于数据不足,无论是总体数据量不足还是特定类别的数据不足。此外,标注错误也可能导致性能问题。
- 标注错误 :监督学习应用中系统性能不佳可能是由于标注错误。标注错误可能是由于标注者不小心将某些数据分配到了错误的类别。如果是训练数据,错误类别的数据会使模型的准确性降低;如果是测试数据,由于模型错误,项目的得分也会不正确。
检查偶尔的标注错误可能非常耗时,并且对系统的改进可能不大。但如果你怀疑标注错误导致了问题,可以通过检查低置信度项目来提供帮助,而无需检查每个标注。可以使用以下代码来检查低置信度项目:
# 假设这里是检查弱类别的代码示例,需要根据实际情况修改
# 预测每个项目的类别并记录概率
# 然后在最终列表中查找低概率项目
此外,数据中可能不仅存在偶尔的错误,还存在系统性的标注错误。系统性错误可能是由于标注者对类别的含义理解不同,导致不同的标注者将相似的项目分配到不同的类别。为了避免或减少这类错误,可以在标注过程开始前为标注者准备清晰的标注指南,甚至为他们提供培训课程。
- 添加和删除现有数据 :不同类别中数据量的不平衡是导致模型性能不佳的常见情况。例如,检测在线仇恨言论的应用可能会遇到更多非仇恨言论的例子,而仇恨言论的例子相对较少。为了使类别的大小更加均衡,可以采用两种常见的方法:过采样和欠采样。
过采样是指复制小类别的数据,而欠采样是指从大类别的数据中删除一些数据。简单的过采样方法是随机复制一些数据实例并添加到训练数据中,欠采样则是随机删除大类别的实例。需要注意的是,过采样和欠采样需要谨慎使用,因为它们可能会导致过拟合或丢失重要信息。
以下是过采样和欠采样的优缺点对比表格:
| 方法 | 优点 | 缺点 |
| ---- | ---- | ---- |
| 过采样 | 增加小类别的数据量,提高模型对小类别的识别能力 | 可能导致过拟合,模型难以泛化到新的测试数据 |
| 欠采样 | 减少大类别的数据量,使数据更加平衡 | 可能会丢失重要信息 |
- 生成新数据 :如果数据集存在代表性不足的类别或总体数据量太小,可以通过以下三种方法生成新数据:
- 从规则生成新数据 :可以使用自然语言工具包(NLTK)编写规则来生成新的数据示例。例如,假设你正在开发一个本地商业搜索聊天机器人,需要更多餐厅搜索类别的数据,可以使用以下代码:
from nltk.parse.generate import generate
from nltk import CFG
grammar = CFG.fromstring("""
S -> SNP VP
SNP -> Pro
VP -> V NP PP
Pro -> 'I'
NP -> Det Adj N
Det -> 'a'
N -> 'restaurant' | 'place'
V -> 'am looking for' | 'would like to find'
PP -> P Adv
P -> 'near'| 'around'
Adv -> 'here'
Adj -> 'Japanese' | 'Chinese' | 'Middle Eastern' | 'Mexican'
""")
for sentence in generate(grammar, n = 10):
print(" ".join(sentence))
这段代码将生成 10 个符合语法规则的句子,例如:
I am looking for a Japanese restaurant near here
I am looking for a Japanese restaurant around here
...
需要注意的是,NLTK CFG 中的规则可以是任何上下文无关规则,规则名称和规则本身并不重要,重要的是语法符合 NLTK CFG 包的要求。
- 从大语言模型(LLMs)生成新数据 :在线大语言模型如 ChatGPT 是获取更多训练数据的好方法。你可以直接要求它们生成适当的训练数据。例如,给 ChatGPT 以下提示:
generate 20 requests to find local restaurants of different cuisines and price ranges
ChatGPT 会生成相应的结果。与 NLTK 的生成方法相比,ChatGPT 生成的句子重复性较低。你还可以通过改变温度参数来控制响应的变化程度,温度设置在 0 到 2 之间,较低的温度意味着响应的变化较小,较高的温度意味着响应的变化较大。
以下是设置温度参数的代码示例:
import openai
# 设置 OpenAI API 密钥
openai.api_key = "your_api_key"
# 设置温度参数和模型参数
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "generate 20 requests to find local restaurants of different cuisines and price ranges"}
],
temperature=1.5
)
print(response.choices[0].message.content)
使用 LLMs 生成数据时,需要检查结果,确保响应代表了用户真正会说的例子,并决定是否将其包含在训练数据中。
- 使用众包工人获取新数据 :从众包工人那里获取更多数据可能非常耗时且昂贵,具体取决于所需数据的数量和复杂程度。但如果其他方法无法获得足够的数据,这也是一种选择。
可以使用以下 mermaid 流程图来总结改变数据的策略:
graph LR
A[改变数据] --> B{是否有数据控制权}
B -- 是 --> C[解决数据问题]
B -- 否 --> D[改进算法]
C --> E[检查标注错误]
C --> F[平衡数据量]
C --> G[生成新数据]
F --> H[过采样]
F --> I[欠采样]
G --> J[从规则生成]
G --> K[从 LLMs 生成]
G --> L[使用众包工人]
综上所述,改变数据是提高系统性能的重要策略,但需要根据具体情况选择合适的方法。在接下来的下半部分,我们将探讨重构应用的策略。
解决系统准确性问题的策略
3. 重构应用
在某些情况下,解决类别预测不佳的最佳方法是重构应用。但如果使用的是研究社区用于不同实验室间比较工作的标准数据集,可能无法进行重构,因为为了使结果具有可比性,应用必须与其他研究人员使用的结构相同。若对应用结构有控制权,可通过添加、删除或合并表现不佳的类别来显著提高应用的整体性能。
3.1 可视化类别重构需求
可视化数据集通常能直接洞察潜在的性能问题,有以下两种方式可可视化数据集中类别之间的相似性:
-
混淆矩阵
:如之前提到的混淆矩阵能提供关于哪些类别彼此相似并因此容易相互混淆的信息。例如,从特定的混淆矩阵中可看出 ENTY 和 DESC 常与 ABBR 混淆。针对这种情况,可考虑添加数据到这些类别(如前文所述),也可考虑重构应用。
-
主题建模技术
:利用主题建模技术能发现应用结构问题。例如,对一个人工构建的包含四个类别的数据集,基于相关工具进行聚类后,可直观看到数据集中类别的问题。
以下是一个人工数据集聚类后的情况分析:
| 类别 | 表示图形 | 问题描述 | 建议操作 |
| ---- | ---- | ---- | ---- |
| 类别 1 | 圆形 | 实例似乎聚成两个不同的类别,分别围绕点 (0.5, 0.5) 和 (0.5, 1.75),不太可能属于同一类别 | 拆分该类别,将当前分配到类别 1 的实例至少分配到两个,可能是三个新类别 |
| 类别 2 | 正方形 | 与类别 3 有一定重叠 | 若含义相似可考虑合并,若不相似可考虑添加更多数据 |
| 类别 3 | 三角形 | 与类别 2 有一定重叠 | 若含义相似可考虑合并,若不相似可考虑添加更多数据 |
| 类别 4 | 星形 | 紧凑且不与其他类别重叠 | 无需调整 |
3.2 重构应用的具体策略
- 合并类别 :比其他类别小很多的类别可与语义相似的类别合并,特别是当它们经常与这些类别混淆时。这在多类问题中可行,因为在二分类问题中合并类别会使所有数据归为一类,无法进行分类。
例如,在一个通用个人助理应用中,有“播放音乐”“查找餐厅”“获取天气预报”“查找书店”和“查找银行”等类别。若“查找书店”的数据远少于“查找餐厅”,且“查找书店”常与“查找餐厅”混淆,可考虑将所有“查找”类合并为一个更大的类别,如“本地商业搜索”,将书店、餐厅和银行视为插槽。
-
划分类别 :当一个大类别中两个或多个组之间存在系统差异时,将其划分为单独的小类别是有意义的。如 BERTopic 等工具可在新类别名称不明显时帮助建议新名称。但将一个类别划分为新类别不像合并类别那么容易,因为新类别中的示例需要用新名称进行标注。尽管重新标注工作量更大,但如果必须将大类别划分为更有意义的新类别,这是必要的。
-
引入“其他”类别 :引入“其他”类别是合并类别的一种变体。如果有几个小类别没有足够的训练数据来可靠分类,将它们组合成一个“其他”类别有时是有用的。例如在电话自助服务应用的呼叫路由中,这种方法就很实用。
可以使用以下 mermaid 流程图来总结重构应用的策略:
graph LR
A[重构应用] --> B{是否能控制应用结构}
B -- 是 --> C[进行类别调整]
B -- 否 --> D[维持现状]
C --> E[合并类别]
C --> F[划分类别]
C --> G[引入其他类别]
总结
解决系统准确性问题可通过改变数据和重构应用两种主要策略。改变数据时,若有数据控制权,可通过检查标注错误、平衡数据量和生成新数据等方法提高系统性能;若没有数据控制权,则需改进算法。重构应用时,若能控制应用结构,可通过合并、划分类别或引入“其他”类别来解决类别预测不佳的问题。在实际应用中,应根据具体情况综合使用这些策略,以达到提高系统准确性的目的。
超级会员免费看

被折叠的 条评论
为什么被折叠?



