# 使用 Cleanlab 检测文本数据集中的问题



作者: [Aravind Putrevu](https://huggingface.co/aravindputrevu)

在这个 5 分钟的快速入门教程中，我们将使用 Cleanlab 检测一个由在线银行（文本）客户服务请求组成的意图分类数据集中的各种问题。我们考虑的是 [Banking77-OOS数据集](https://arxiv.org/abs/2106.04564) 的一个子集，包含 1,000 个客户服务请求，根据它们的意图被分类为 10 个类别（你可以在任何文本分类数据集上运行相同的代码）。[Cleanlab](https://github.com/cleanlab/cleanlab)自动识别我们数据集中的坏例子，包括错误标记的数据、范围外的示例（离群值）或其他模糊不清的示例。在深入建模你的数据之前，请考虑过滤或更正这样的坏例子！

**本教程我们将要做的事情概述：**

- 使用预训练的 transformer 模型从客户服务请求中提取文本嵌入

- 在文本嵌入上训练一个简单的逻辑回归模型，以计算样本外的预测概率

- 使用这些预测和嵌入运行 Cleanlab 的 `Datalab` 审核，以识别数据集中的问题，如：标签问题、离群值和近重复项。

## 快速入门

已经有一个模型在现有标签集上训练得到的（样本外）`pred_probs` 了吗？也许你还有一些数值`特征`？运行下面的代码来查找数据集中的任何潜在标签错误。

**注意：** 如果在 Colab 上运行，可能需要使用 GPU（选择：Runtime > Change runtime type > Hardware accelerator > GPU）



```python
from cleanlab import Datalab

lab = Datalab(data=your_dataset, label_name="column_name_of_labels")
lab.find_issues(pred_probs=your_pred_probs, features=your_features)

lab.report()
lab.get_issues()
```

## 安装需要的依赖


你可以使用 `pip` 按照以下方式安装本教程所需的所有包：


```python
!pip install -U scikit-learn sentence-transformers datasets
!pip install -U "cleanlab[datalab]"
```

```python
import re
import string
import pandas as pd
from sklearn.metrics import accuracy_score, log_loss
from sklearn.model_selection import cross_val_predict
from sklearn.linear_model import LogisticRegression
from sentence_transformers import SentenceTransformer

from cleanlab import Datalab
```

```python
import random
import numpy as np

pd.set_option("display.max_colwidth", None)

SEED = 123456  # for reproducibility
np.random.seed(SEED)
random.seed(SEED)
```

## 加载和格式化文本数据集

```python
from datasets import load_dataset

dataset = load_dataset("PolyAI/banking77", split="train")
data = pd.DataFrame(dataset[:1000])
data.head()
```

```python
>>> raw_texts, labels = data["text"].values, data["label"].values
>>> num_classes = len(set(labels))

>>> print(f"This dataset has {num_classes} classes.")
>>> print(f"Classes: {set(labels)}")
```

<pre>
This dataset has 7 classes.
Classes: {32, 34, 36, 11, 13, 46, 17}
</pre>

让我们查看数据集中的第 i 个示例：

```python
>>> i = 1  # change this to view other examples from the dataset
>>> print(f"Example Label: {labels[i]}")
>>> print(f"Example Text: {raw_texts[i]}")
```

<pre>
Example Label: 11
Example Text: What can I do if my card still hasn't arrived after 2 weeks?
</pre>

数据以两个 numpy 数组的形式存储：
1. `raw_texts` 以文本格式存储客户服务请求的话语
2. `labels` 存储每个示例的意图类别（标签）

<div class="alert alert-info">

自有数据？

你可以轻松地将上述内容替换为你自己的文本数据集，并继续进行教程的其余部分。


</div>

接下来，我们将文本字符串转换为更适合作为机器学习模型输入的向量。

我们将使用预训练的 Transformer 模型提供的数值表示作为我们文本的嵌入。[Sentence Transformers](https://huggingface.co/docs/hub/sentence-transformers) 库提供了计算文本数据嵌入的简单方法。在这里，我们加载了预训练的 `electra-small-discriminator` 模型，然后通过网络运行我们的数据，以提取每个示例的向量嵌入。


```python
transformer = SentenceTransformer('google/electra-small-discriminator')
text_embeddings = transformer.encode(raw_texts)
```

我们后续的机器学习模型将直接在 `text_embeddings` 的元素上操作，以便对客户服务请求进行分类。

## 定义一个分类模型并计算样本外的预测概率

   为了利用预训练网络进行特定的分类任务，一种典型的方法是添加一个线性输出层，并在新数据上微调网络参数。然而，这可能需要大量的计算资源。另一种方法是冻结网络的预训练权重，只训练输出层，而不依赖于 GPU。在这里，我们通过在提取的嵌入顶部拟合一个 scikit-learn 线性模型来方便地实现这一点。

   为了识别标签问题，cleanlab 需要你的模型为每个数据点提供概率预测。然而，对于模型之前训练过的数据点，这些预测将是过拟合的（因此不可靠）。cleanlab 旨在仅与**样本外**的预测类概率一起使用，即在模型训练期间保持不变的数据点。

   在这里，我们使用带有交叉验证的逻辑回归模型来获得数据集中每个示例的样本外预测类概率。
   确保你的 `pred_probs` 列根据类的排序正确排序，对于 Datalab 来说，是：按类名字典顺序排序。

```python
model = LogisticRegression(max_iter=400)

pred_probs = cross_val_predict(model, text_embeddings, labels, method="predict_proba")
```

## 使用 Cleanlab 查找数据集中的问题

在给定来自你拥有的任何模型的特征嵌入和（样本外）预测类概率的情况下，cleanlab 可以帮助你快速识别数据中的低质量示例。

在这里，我们使用 Cleanlab 的 `Datalab` 来查找数据中的问题。Datalab 提供了几种加载数据的方式；我们将简单地在字典中包装训练特征和噪声标签。

```python
data_dict = {"texts": raw_texts, "labels": labels}
```

审核你的数据所需的全部操作就是调用 `find_issues()`。我们传入上面获得的预测概率和特征嵌入，但你不一定需要提供所有这些信息，具体取决于你对哪些类型的问题感兴趣。你提供的输入越多，`Datalab` 就能在你的数据中检测到更多类型的问题。使用更好的模型来生成这些输入将确保 cleanlab 更准确地估计问题。


```python
lab = Datalab(data_dict, label_name="labels")
lab.find_issues(pred_probs=pred_probs, features=text_embeddings)
```

输出看起来如下：

```bash
Finding null issues ...
Finding label issues ...
Finding outlier issues ...
Fitting OOD estimator based on provided features ...
Finding near_duplicate issues ...
Finding non_iid issues ...
Finding class_imbalance issues ...
Finding underperforming_group issues ...

Audit complete. 62 issues found in the dataset.
```

审计完成后，使用 `report` 方法来查看审计结果。

```python
>>> lab.report()
```

<pre>
Here is a summary of the different kinds of issues found in the data:

    issue_type  num_issues
       outlier          37
near_duplicate          14
         label          10
       non_iid           1

Dataset Information: num_examples: 1000, num_classes: 7


---------------------- outlier issues ----------------------

About this issue:
	Examples that are very different from the rest of the dataset 
    (i.e. potentially out-of-distribution or rare/anomalous instances).
    

Number of examples with this issue: 37
Overall dataset quality in terms of this issue: 0.3671

Examples representing most severe instances of this issue:
     is_outlier_issue  outlier_score
791              True       0.024866
601              True       0.031162
863              True       0.060738
355              True       0.064199
157              True       0.065075


------------------ near_duplicate issues -------------------

About this issue:
	A (near) duplicate issue refers to two or more examples in
    a dataset that are extremely similar to each other, relative
    to the rest of the dataset.  The examples flagged with this issue
    may be exactly duplicated, or lie atypically close together when
    represented as vectors (i.e. feature embeddings).
    

Number of examples with this issue: 14
Overall dataset quality in terms of this issue: 0.5961

Examples representing most severe instances of this issue:
     is_near_duplicate_issue  near_duplicate_score near_duplicate_sets  distance_to_nearest_neighbor
459                     True              0.009544               [429]                      0.000566
429                     True              0.009544               [459]                      0.000566
501                     True              0.046044          [412, 517]                      0.002781
412                     True              0.046044               [501]                      0.002781
698                     True              0.054626               [607]                      0.003314


----------------------- label issues -----------------------

About this issue:
	Examples whose given label is estimated to be potentially incorrect
    (e.g. due to annotation error) are flagged as having label issues.
    

Number of examples with this issue: 10
Overall dataset quality in terms of this issue: 0.9930

Examples representing most severe instances of this issue:
     is_label_issue  label_score  given_label  predicted_label
379           False     0.025486           32               11
100           False     0.032102           11               36
300           False     0.037742           32               46
485            True     0.057666           17               34
159            True     0.059408           13               11


---------------------- non_iid issues ----------------------

About this issue:
	Whether the dataset exhibits statistically significant
    violations of the IID assumption like:
    changepoints or shift, drift, autocorrelation, etc.
    The specific violation considered is whether the
    examples are ordered such that almost adjacent examples
    tend to have more similar feature values.
    

Number of examples with this issue: 1
Overall dataset quality in terms of this issue: 0.0000

Examples representing most severe instances of this issue:
     is_non_iid_issue  non_iid_score
988              True       0.563774
975             False       0.570179
997             False       0.571891
967             False       0.572357
956             False       0.577413

Additional Information: 
p-value: 0.0
</pre>

### 标签问题

报告显示 cleanlab 在我们的数据集中识别出了许多标签问题。我们可以使用 `get_issues` 方法来查看哪些示例被标记为可能标签错误，以及每个示例的标签质量分数，通过指定 `label` 作为参数来关注数据中的标签问题。

```python
label_issues = lab.get_issues("label")
label_issues.head()
```

| | is_label_issue | label_score | given_label | predicted_label |
|----------------|-------------|-------------|-----------------|-----------------|
| 0              | False       | 0.903926    | 11              | 11 |
| 1              | False       | 0.860544    | 11              | 11 |
| 2              | False       | 0.658309    | 11              | 11 |
| 3              | False       | 0.697085    | 11              | 11 |
| 4              | False       | 0.434934    | 11              | 11 |


此方法返回一个包含每个示例的标签质量分数的数据框。这些数值分数介于 0 和 1 之间，其中较低的分数表示更可能是错误标记的示例。数据框还包含一个布尔列，指定是否将每个示例识别为具有标签问题（表明它可能是错误标记的）。

我们可以获取标记有标签问题的示例的子集，并且还可以按标签质量分数排序，以找到数据集中最可能错误标记的 5 个示例的索引。

```python
>>> identified_label_issues = label_issues[label_issues["is_label_issue"] == True]
>>> lowest_quality_labels = label_issues["label_score"].argsort()[:5].to_numpy()

>>> print(
...     f"cleanlab found {len(identified_label_issues)} potential label errors in the dataset.\n"
...     f"Here are indices of the top 5 most likely errors: \n {lowest_quality_labels}"
... )
```

<pre>
cleanlab found 10 potential label errors in the dataset.
Here are indices of the top 5 most likely errors: 
 [379 100 300 485 159]
</pre>

让我们查看一些最可能的标签错误。

这里我们展示了数据集中被识别为最可能的标签错误的前 5 个示例，以及它们的给定（原始）标签和 cleanlab 提供的建议替代标签。




```python
data_with_suggested_labels = pd.DataFrame(
    {"text": raw_texts, "given_label": labels, "suggested_label": label_issues["predicted_label"]}
)
data_with_suggested_labels.iloc[lowest_quality_labels]
```

上面命令的输出如下所示：
  
|      | text                                                                                                      | given_label    | suggested_label |
|------|-----------------------------------------------------------------------------------------------------------|----------------|-----------------|
| 379  | Is there a specific source that the exchange rate for the transfer I'm planning on making is pulled from? | 32             | 11              |
| 100  | can you share card tracking number?                                                                       | 11             | 36              |
| 300  | If I need to cash foreign transfers, how does that work?                                                  | 32             | 46              |
| 485  | Was I charged more than I should of been for a currency exchange?                                         | 17             | 34              |
| 159  | Is there any way to see my card in the app?                                                               | 13             | 11              |


这些是 cleanlab 在此数据中识别的非常清晰的标签错误！请注意，`given_label` 并没有正确反映这些请求的意图，无论谁制作了这个数据集，在建模数据之前都需要解决许多错误。


### 离群值问题

根据报告，我们的数据集中包含一些离群值。

我们可以通过 `get_issues` 查看哪些示例是离群值（以及一个数值质量分数，量化每个示例看起来有多么典型）。我们将结果数据框按照 cleanlab 的离群值质量分数排序，以查看数据集中最严重的离群值。


```python
outlier_issues = lab.get_issues("outlier")
outlier_issues.sort_values("outlier_score").head()
```

输出如下所示：

|   | is_outlier_issue | outlier_score |
|---| ----------------|---------------|
| 791 | True             | 0.024866      |
| 601 | True             | 0.031162      |
| 863 | True             | 0.060738      |
| 355 | True             | 0.064199      |
| 157 | True             | 0.065075      |

```python
lowest_quality_outliers = outlier_issues["outlier_score"].argsort()[:5]

data.iloc[lowest_quality_outliers]
```

对于质量最低的离群值，样本输出将如下所示：

|index|text|label|
|---|---|---|
|791|withdrawal pending meaning?|46|
|601|$1 charge in transaction\.|34|
|863|My atm withdraw is stillpending|46|
|355|explain the interbank exchange rate|32|
|157|lost card found, want to put it back in app|13|


我们看到 cleanlab 已经识别出这个数据集中的条目，这些条目看起来并不是正确的客户请求。此数据集中的离群值似乎是不在范围内的客户请求和其他对意图分类没有意义的非语义文本。仔细考虑这些离群值是否可能对你的数据建模产生不利影响，如果有可能的话，考虑从数据集中移除它们。


### 近重复问题

根据报告，我们的数据集中包含一些几乎重复的示例集。
我们可以通过 `get_issues` 查看哪些示例是（几乎）重复的（以及一个数值质量分数，量化每个示例与数据集中最近邻的相似程度）。我们将结果数据框按照 cleanlab 的近重复质量分数排序，以查看数据集中最接近重复的文本示例。

```python
duplicate_issues = lab.get_issues("near_duplicate")
duplicate_issues.sort_values("near_duplicate_score").head()
```

上面的结果显示了 cleanlab 认为哪些示例是近重复的（`is_near_duplicate_issue == True` 的行）。在这里，我们看到示例 459 和 429 是近重复的，示例 501 和 412 也是近重复的。

让我们查看这些示例，看看它们有多么相似。


```python
data.iloc[[459, 429]]
```

样本输出：

|index|text|label|
|---|---|---|
|459|I purchased something abroad and the incorrect exchange rate was applied\.|17|
|429|I purchased something overseas and the incorrect exchange rate was applied\.|17|

```python
data.iloc[[501, 412]]
```

样本输出：

|index|text|label|
|---|---|---|
|501|The exchange rate you are using is really bad\.This can't be the official interbank exchange rate\.|17|
|412|The exchange rate you are using is bad\.This can't be the official interbank exchange rate\.|17|

我们看到这两组请求确实非常相似！在数据集中包含近重复项可能会对模型产生意想不到的影响，并且要小心不要将它们分割到训练/测试集中。从[常见问题解答](../faq.html#How-to-handle-near-duplicate-data-identified-by-cleanlab?)中了解更多关于处理数据集中的近重复数据的信息。

### 非独立同分布问题（数据漂移）
根据报告，我们的数据集似乎不是独立同分布的（IID）。数据集的整体非 IID 分数（如下所示）对应于一个统计测试的 `p 值`，该测试用于判断数据集中样本的排序是否与它们特征值之间的相似性有关。一个低的 `p 值`强烈表明数据集违反了 IID 假设，这是从数据集产生的结论（模型）推广到更大总体所需的关键假设。

```python
p_value = lab.get_info('non_iid')['p-value']
p_value
```

在这里，我们的数据集被标记为非 IID，因为原始数据中的行恰好是按类别标签排序的。如果我们记得在模型训练和数据拆分之前打乱行，这可能是不重要的。但是，如果你不知道为什么你的数据被标记为非IID，那么你应该担心可能的数据漂移或数据点之间的意外交互（它们的价值可能不是统计独立的）。仔细考虑未来的测试数据可能看起来如何（以及你的数据是否代表你关心的人群）。在非 IID 测试运行之前，你不应该打乱数据（这将使结论无效）。


    如上所示，cleanlab 可以自动筛选出数据集中最可能的问题，帮助你更好地为后续建模整理数据集。有了这个短名单，你可以选择修复这些标签问题，或者从数据集中移除非语义或重复的示例，以获得更高质量的数据集来训练你的下一个机器学习模型。cleanlab 的问题检测可以与你最初训练的*任何*类型的模型的输出一起运行。



### Cleanlab 开源项目

[Cleanlab](https://github.com/cleanlab/cleanlab) 是一个标准的以数据为中心的人工智能包，旨在解决混乱的现实世界数据的质量问题。

请考虑给 Cleanlab Github 仓库一个星标，如果你有兴趣，也可以参与到这个[项目](https://github.com/cleanlab/cleanlab/issues?q=is:issue+is:open+label:%22good+first+issue%22)中来，比如帮助解决一些简单的问题。。


<EditOnGithub source="https://github.com/huggingface/cookbook/blob/main/notebooks/zh-CN/issues_in_text_dataset.md" />