AI 和错误分类的巴西联邦法律的故事
介绍
几周前,当我在寻找用于开发个人项目的数据集时,我偶然发现了巴西众议院开放数据门户,其中包含了大量数据,包括议员的费用、政党元数据等,所有这些都可以通过一个很好的 API 获得。
在搜索和检查了几个小时后,我注意到了一个非常有趣的事情:众议员提出的所有法案的编目,包括法案的“ementas”(简洁摘要)、作者、年份,更重要的是它们的主题(健康、安全、财政等…)-由众议院的文件和信息中心(Centro de Documentação e Informação da Câmara)进行分类。
我的脑海里闪过一道火花-“我将建立一个监督分类流程,使用法案摘要来预测法案的主题,探索机器学习的一些基础设施方面,如使用 DVC 进行数据版本控制等等。”我迅速编写了一个脚本,并收集了一个庞大的数据集,其中包括从1990年到2022年的超过60,000个法案。
我已经在司法和立法数据方面做过一些工作了,所以我有一种感觉,这个任务应该不难。但是,为了让事情变得更简单,我选择只对法案提案(LP)是否涉及“税收和纪念日”进行分类(二分类)。理论上来说,这应该很容易,因为这些文本非常简单:
![使用CleanLab自动检测数据集中的标签错误 四海 第2张-四海吧 ChatGPT提供的原始摘要和字面翻译- I. 作者提供的图像。](https://miro.medium.com/v2/resize:fit:640/format:webp/1*Xj6OGsOqdNmjgtRxFh_0wA.png)
但是,无论我尝试做什么,我的性能都无法超过F1得分的~0.80标记,而召回率(对于正类)相对较低,为0.5至0.7。
当然,我的数据集高度不平衡,这个类别只占数据集大小的不到5%,但还有更多的问题。
经过一些调查,通过基于正则表达式的查询来检查数据,并查看错误分类的记录,我发现了一些错误的标记示例。用我粗略的方法,我发现了大约200个假阴性,它们代表了“真正”阳性的~7.5%和我的数据集的0.33%,更不用提假阳性了。以下是其中的一些示例:
![使用CleanLab自动检测数据集中的标签错误 四海 第3张-四海吧 错误分类的例子。作者提供的图像。](https://miro.medium.com/v2/resize:fit:640/format:webp/1*0Lq8_BejP2a3zPxwAP_G6A.png)
这些例子破坏了我的验证指标-“它们可能有多少存在?我需要手动搜索错误吗?”
但是,随后,自信学习以“干净实验室”Python软件包的形式出现,拯救了我。
什么是自信学习?
正确标记数据是任何监督式机器学习项目中最耗时和昂贵的步骤之一。类似众包、半监督学习、微调和其他许多技术都试图降低收集标签的成本或在模型训练中需要这些标签的需求。
幸运的是,我们已经在这个问题上走在了前面。我们已经有了专业人士提供的标签,可能是具有适当专业知识的政府工作人员。但是,我的非专业眼睛和粗糙的正则表达式方法一旦打破了我的性能预期,就能发现错误。
问题是:数据中还有多少错误?
检查每一条法律是不合理的——需要一种自动的方式来检测错误标签,这就是自信学习。
总之,它利用从模型概率预测中收集的统计数据来估计数据集中的错误。它可以检测噪声、异常值,以及本文的主题——标签错误。
我不会详细介绍自信学习,但有一篇非常好的文章介绍了它的主要观点,还有一个由CleanLab的创始人讲解该领域研究的YouTube视频。
让我们看看它在实践中是如何工作的。
数据
数据是从巴西众议院开放数据门户收集的,包含了1990年至2022年的法律提案(LP)。最终数据集包含约60K个LP。
单个LP可以与多个主题相关联,例如健康和财政,这些信息也可以在开放数据门户上找到。为了更容易处理,我已经通过将每个独立主题二值化到单独的列中来对主题信息进行编码。
如前所述,本文使用的主题是“致敬和纪念日期”。我之所选择它,是因为它的摘要非常简短和简单,所以标签错误很容易被识别。
数据和代码都可以在项目的GitHub存储库中找到。
实现
我们的目标是自动修复“致敬和纪念日期”中的每一个标签错误,并用一个漂亮干净的数据集结束这篇文章,准备用于机器学习问题。
设置环境
只需要安装经典的ML/Data Science Python包(Pandas、Numpy和Scikit-Learn)+ CleanLab包即可运行此项目。
cleanlab==2.4.0scikit-learn==1.2.2pandas>=2.0.1numpy>=1.20.3
只需安装这些要求,我们就可以开始了。
使用CL检测标签错误
CleanLab包本身具备识别许多类型的数据集问题的能力,如异常值和重复/相似条目,但我们只对标签错误感兴趣。
CleanLab使用由代表其对某个标签的置信度的机器学习模型生成的概率。如果数据集有n个条目和m个类别,那么这将由一个n乘m的矩阵P表示,其中P[i, j]表示第i行属于类别j的概率。
这些概率和“真实”标签在CleanLab内部用于估计错误。
让我们练习一下:
导入包
import numpy as npimport pandas as pdfrom sklearn.feature_extraction.text import TfidfVectorizerfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.model_selection import train_test_split, cross_val_score, cross_val_predictfrom sklearn.model_selection import GridSearchCV, StratifiedKFoldfrom sklearn.pipeline import Pipelinefrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_scorefrom sklearn.metrics import confusion_matrix, classification_reportfrom cleanlab import DatalabRANDOM_SEED = 214np.random.seed(RANDOM_SEED)
加载数据…
df_pls_theme = pd.read_parquet( '../../data/proposicoes_temas_one_hot_encoding.parquet')# "Tributes and commemorative dates"BINARY_CLASS = "Homenagens e Datas Comemorativas"IN_BINARY_CLASS = "in_" + BINARY_CLASS.lower().replace(" ", "_")df_pls_theme = df_pls_theme.drop_duplicates(subset=["ementa"])df_pls_theme = df_pls_theme[["ementa", BINARY_CLASS]]df_pls_theme = df_pls_theme.rename( columns={BINARY_CLASS: IN_BINARY_CLASS})
首先,让我们生成概率。
如CleanLab文档中所述,为了达到更好的性能,关键是概率在“非训练”数据(即测试数据)上生成。这很重要,因为模型在预测训练数据的概率时往往过于自信。在数据集中生成测试数据的概率的最常见方法是使用K-Fold策略,如下所示:
y_proba = 交叉验证预测( 清洁管道, df_pls_theme['ementa'], df_pls_theme[IN_BINARY_CLASS], cv=分层KFold(n_splits=5, shuffle=True, random_state=RANDOM_SEED), method='predict_proba', verbose=2, n_jobs=-1)
注意:了解类分布非常重要,因此使用了StratifiedKFold对象。所选的类别在数据集中占比不到5%,使用天真的采样方法可能会导致模型在错误平衡的数据集上训练生成质量较差的概率。
CleanLab使用一个名为Datalab的类来处理错误检测任务。它接收包含数据的DataFrame和标签列的名称。
lab = Datalab( data=df_pls_theme, label_name=IN_BINARY_CLASS,)
现在,我们只需要将之前计算得到的概率传递给它…
lab.find_issues(pred_probs=y_proba)
…就可以开始查找问题了
lab.get_issue_summary("label")
就是这么简单。
get_issues(“label”)函数返回一个DataFrame,其中包含CleanLab为每个记录计算的指标和度量。最重要的列是’is_label_issue’和’predicted_label’,分别表示记录是否存在标签问题以及可能的正确标签。
lab.get_issues("label")
我们可以将这些信息合并到原始DataFrame中,以查看哪些示例存在问题。
# 获取预测的错误y_clean_labels = lab.get_issues("label")[['predicted_label', 'is_label_issue']]# 将它们添加到原始数据集df_ples_theme_clean = df_pls_theme.copy().reset_index(drop=True)df_ples_theme_clean['predicted_label'] = y_clean_labels['predicted_label']df_ples_theme_clean['is_label_issue'] = y_clean_labels['is_label_issue']
让我们检查一些示例:
对我来说,这些法律明显与致敬和纪念日期有关,然而它们并没有被适当地分类。
不错!CleanLab在我们的数据集中找到了312个标签错误,但现在该怎么办呢?
这些错误可以通过手动检查进行修正(以主动学习的方式),或者立即进行修正(假设CleanLab的工作正确)。前者更耗时,但可能会产生更好的结果,而后者更快,但可能会导致更多错误。
无论选择哪种方式,CleanLab将劳动量从6万个记录减少到几百个(最坏情况下)。
但是有一个问题。
我们如何确保CleanLab找到了数据集中的所有错误?
事实上,如果我们使用修复错误后的数据作为基本事实再次运行上述流程,CleanLab会找到更多的错误…
更多的错误,但希望比第一次运行时少。
我们可以重复这个逻辑多次:查找错误,修复错误,使用新的被假定为质量更高的标签重新训练模型,再次查找错误…
![使用CleanLab自动检测数据集中的标签错误 四海 第8张-四海吧 Fixing errors iteratively. Image by Author.](https://miro.medium.com/v2/resize:fit:640/format:webp/1*UfiNOQcY0bqkM7hajf9LjA.png)
希望在一些交互之后,错误的数量将变为零。
使用CleanLab迭代修复错误
要实现这个想法,我们只需要在一个循环中重复上述过程,下面的代码就是这样做的:
让我们来回顾一下。
在每次迭代中,使用StratifiedKFold和cross_val_predict方法生成OOS概率,每次迭代使用当前的概率来构建一个新的Datalab对象并找到新的标签问题。
找到的问题与当前数据集合并并修复。
我选择将修复后的标签附加为新列,而不是替换原始标签。
![使用CleanLab自动检测数据集中的标签错误 四海 第9张-四海吧 附加修复后的标签。作者提供的图片。](https://miro.medium.com/v2/resize:fit:640/format:webp/1*J-MlsqTq0iYlSRorLW2z8Q.png)
LABEL_COLUMN_0是原始标签,LABEL_COLUMN_1是修复了1次的标签列,LABEL_COLUMN_2是修复了2次的标签列,依此类推…
除了这个过程,还计算并存储了常规分类指标以供后续检查。
经过8次迭代(约16分钟),过程结束。
结果
下表显示了在过程中计算的性能指标。
在8次迭代中,数据集中找到了393个标签错误。如预期的那样,每次迭代中找到的错误数量都减少了。
有趣的是,这个过程只用了6次迭代就“收敛”到了一个“解”,在最后2次迭代中保持了0个错误。这表明在这种情况下,CleanLab的实现是稳健的,并且没有通过“偶然”找到可能导致震荡的更多错误。
虽然错误数量仅占数据集的0.6%,但F1得分从0.81提高到了0.90,增加了约11%。这可能是因为类别高度不平衡,新的322个正标签在原始正例数量中占比约12%。
但是,CleanLab真的能找到有意义的错误吗?让我们检查一些例子,看看它们是否合理。
修复的假阴性
![使用CleanLab自动检测数据集中的标签错误 四海 第11张-四海吧 ChatGPT生成的原始摘要和直译。作者提供的图片。](https://miro.medium.com/v2/resize:fit:640/format:webp/1*S6bvD2u1W0KqLAevzZEaeg.png)
上述文本确实类似于“致敬和纪念日期”,暗示它们应该被适当地分类为这样的内容 — CleanLab的优势
修复的假阳性
![使用CleanLab自动检测数据集中的标签错误 四海 第12张-四海吧 ChatGPT生成的原始摘要和直译。作者提供的图片。](https://miro.medium.com/v2/resize:fit:640/format:webp/1*mT1y2DI7vQ_O1-ABQiL_Vg.png)
在这种情况下,有一些错误,第2个和第4个法律并不是假阳性。不太好,但还可以接受。
我多次重复了这个检查,抽样了新的“修复”法律,总体上,CleanLab在检测假阴性方面表现几乎完美,但对于假阳性有些困惑。
现在,即使我们可能没有一个完全标记的数据集,我对在其中训练机器学习模型更加有信心了。
结论
长期以来,机器学习领域一直饱受模型质量差和计算能力不足的困扰,但这个时代已经过去。现在,大多数机器学习应用的真正瓶颈是数据。但不是原始数据,而是经过精炼的数据 —— 具有良好标签、格式良好、没有太多噪音或异常值的数据。
因为无论模型有多大、多强大,无论在流程中混入多少统计和数学,这些都无法使你摆脱计算机科学中最基本的法则:垃圾进,垃圾出。
而这个项目正是对这一原则的证明——我测试了几个模型、深度学习架构、采样技术和向量化方法,最后发现问题出在基础上:我的数据是错误的。
在这种情况下,投资于数据质量技术成为创建成功的机器学习项目的关键因素。
在这篇文章中,我们探讨了CleanLab,一个帮助我们检测和修复数据集中错误标签的包。它不仅使我们能够显著提高数据集的质量,而且还以自动化、可重复和廉价的方式实现了这一点——无需人工干预。
希望这个项目能帮助你更好地了解自信学习和CleanLab包。与往常一样,我对本文涉及的任何主题都不是专家,并强烈建议进一步阅读,以下是一些参考资料。
感谢阅读! 😉
参考资料
所有代码都可以在此GitHub存储库中找到。使用的数据——联邦议会开放数据门户。[开放数据 – 第12.527号法律]所有图片均由作者创建,除非另有说明。
[1] Cleanlab. (n.d.). GitHub — cleanlab/cleanlab: The standard data-centric AI package for data quality and machine learning with messy, real-world data and labels. GitHub. [2] Computing Out-of-Sample Predicted Probabilities with Cross-Validation — cleanlab. (n.d.). [3] Databricks. (2022, July 19). CleanLab: AI to find and fix errors in ML datasets [Video]. YouTube. [4] FAQ — cleanlab. (n.d.). [5] Mall, S. (2023, May 25). Are label errors imperative? Is confident learning useful? VoAGI. [6] Northcutt, C. G. (2021). Confident Learning: Estimating uncertainty in Dataset labels. arXiv.org.