跳转到主要内容

Goodtables是一个用于检查表格数据的框架。

项目描述

goodtables-py

Travis Coveralls PyPi Github Gitter

Goodtables是一个用于验证表格数据的框架。它可以检查您数据的结构(例如,所有行都有相同数量的列),以及其内容(例如,所有日期都是有效的)。

[重要通知] goodtables从版本3开始更名为frictionless。该框架得到了各种改进,并扩展成为一个完整的数据解决方案。这种更改不会破坏现有的软件,因此无需采取任何行动。请阅读迁移指南,以开始使用Python的Frictionless。

  • 我们在此分支上继续修复goodtables@2.x的bug,同时在PyPi上也像之前一样提供
  • 请注意,我们目前正在工作的frictionless@3.x版本API尚不稳定
  • 我们将在2020年底发布frictionless@4.x,以成为第一个SemVer/stable版本

功能

  • 结构检查:确保没有空行,没有空白标题等。
  • 内容检查:确保值具有正确的类型(“字符串”、“数字”、“日期”等),它们的格式有效(“字符串必须是电子邮件”),并且它们遵守约束(“年龄必须是一个大于18的数字”)。
  • 支持多种表格格式:CSV、Excel文件、LibreOffice、数据包等。
  • 多表格数据集的并行验证
  • 命令行界面

内容

入门

为了更快地验证与goodtables兼容的Pandas数据帧,请参阅https://github.com/ezwelty/goodtables-pandas-py

安装

pip install goodtables
pip install goodtables[ods]  # If you need LibreOffice's ODS file support

在CLI上运行

goodtables data.csv

使用goodtables --help查看不同选项。

在Python上运行

from goodtables import validate

report = validate('invalid.csv')
report['valid'] # false
report['table-count'] # 1
report['error-count'] # 3
report['tables'][0]['valid'] # false
report['tables'][0]['source'] # 'invalid.csv'
report['tables'][0]['errors'][0]['code'] # 'blank-header'

您可以在开发者文档部分阅读有关使用Python与goodtables的更深入的解释。也可以查看示例文件夹中的其他示例。

文档

Goodtables验证您的表格数据集以查找结构和内容错误。假设您有一个名为invalid.csv的文件。让我们来验证它

report = validate('invalid.csv')

我们也可以传递远程URI而不是本地路径。它支持CSV、XLS、XLSX、ODS、JSON以及由tabulator库支持的所有其他格式。

报告

验证报告遵循在goodtables/schemas/report.json上定义的JSON Schema。

validate()方法输出是一个报告字典。它包括数据是否有效、错误计数、表报告列表、哪些单独的检查失败等信息。报告将如下所示

{
    "time": 0.009,
    "error-count": 1,
    "warnings": [
        "Table \"data/invalid.csv\" inspection has reached 1 error(s) limit"
    ],
    "preset": "table",
    "valid": false,
    "tables": [
        {
            "errors": [
                {
                    "row-number": null,
                    "message": "Header in column 3 is blank",
                    "row": null,
                    "column-number": 3,
                    "code": "blank-header"
                }
            ],
            "error-count": 1,
            "headers": [
                "id",
                "name",
                "",
                "name"
            ],
            "scheme": "file",
            "row-count": 2,
            "valid": false,
            "encoding": "utf-8",
            "time": 0.007,
            "schema": null,
            "format": "csv",
            "source": "data/invalid"
        }
    ],
    "table-count": 1
}

错误被分为以下类别之一

  • source - 数据无法加载或解析
  • structure - 一般表格错误,如重复标题
  • schema - 与Table Schema的检查错误
  • custom - 自定义检查错误

检查

检查是goodtables中的主要验证角色。可以使用checksskip_checks参数来更改启用的检查列表。让我们通过一个例子来探索选项。

report = validate('data.csv') # by default structure and schema (if available) checks
report = validate('data.csv', checks=['structure']) # only structure checks
report = validate('data.csv', checks=['schema']) # only schema (if available) checks
report = validate('data.csv', checks=['bad-headers']) # check only 'bad-headers'
report = validate('data.csv', skip_checks=['bad-headers']) # exclude 'bad-headers'

默认情况下,数据集将针对所有可用的数据质量规范错误进行验证。某些检查可能不可用于验证。例如,如果没有提供架构,则只执行structure检查。

预设

goodtables支持表格数据集的不同格式。它们被称为预设。表格数据集是一些可以分割成数据表列表的数据,如下所示:

Dataset

我们可以使用validate()函数的preset参数来更改预设。默认情况下,它将从源自动推断,如果源不可用,将回退到table。要验证数据包,我们可以这样做:

report = validate('datapackage.json') # implicit preset
report = validate('datapackage.json', preset='datapackage') # explicit preset

这将验证数据包中的所有表格资源。

还有可能使用“嵌套”预设来验证文件列表。要做到这一点,validate()的第一个参数应该是字典列表,其中每个字典的键都是validate()参数的名称。例如:

report = validate([{'source': 'data1.csv'}, {'source': 'data2.csv'}]) # implicit preset
report = validate([{'source': 'data1.csv'}, {'source': 'data2.csv'}], preset='nested') # explicit preset

类似于

report_data1 = validate('data1.csv')
report_data2 = validate('data2.csv')

区别在于goodtables可以并行验证多个表格,因此使用“嵌套”预设应该运行得更快。

数据质量错误

基本报告错误是标准化的,并在数据质量规范中描述。

源错误

基本检查不能被禁用,因为它们涉及到goodtables能否读取文件。

check 描述
io-error 由于IO错误导致的数据读取错误。
http-error 由于HTTP错误导致的数据读取错误。
source-error 由于不支持或不一致的内容导致的数据读取错误。
scheme-error 由于不正确的架构导致的数据读取错误。
format-error 由于不正确的格式导致的数据读取错误。
encoding-error 由于编码问题导致的数据读取错误。

结构错误

这些检查验证文件的结构是否有效。

check 描述
blank-header 存在空白标题名称。标题行中的所有单元格都必须有值。
duplicate-header 存在多个具有相同名称的列。所有列名都必须是唯一的。
blank-row 行必须至少有一个非空白单元格。
duplicate-row 行不能重复。
extra-value 行比标题有更多的列。
missing-value 行比标题少的列。

Schema errors

这些检查验证文件的内容。要使用它们,您需要传递一个表架构。如果您没有架构,并且使用infer_schema选项,goodtables可以推断它。

如果您的架构只覆盖部分数据,您可以使用infer_fields来推断剩余的字段。

最后,如果数据中字段的顺序与架构中的顺序不同,请启用order_fields选项。

check 描述
schema-error 架构无效。
non-matching-header 架构中的标题名称与数据中的名称不同。
extra-header 数据包含架构中未定义的标题。
missing-header 数据不包含架构中定义的标题。
type-or-format-error 无法根据该字段的架构类型和格式将值转换为类型。
required-constraint 该字段是必填字段,但没有任何值。
pattern-constraint 该字段值应符合定义的模式。
unique-constraint 该字段是唯一的字段,但它包含了一个在另一行已使用的值。
可枚举约束 该字段值应等于可枚举约束中的其中一个值。
最小约束 该字段值应大于或等于约束值。
最大约束 该字段值应小于或等于约束值。
最小长度约束 该字段值的长度应大于或等于架构约束值。
最大长度约束 该字段值的长度应小于或等于架构约束值。

自定义错误

check 描述
黑名单值 确保没有包含黑名单值的单元格。
偏差值 确保数字在平均值附近的若干个标准差范围内。
外键 确保数据包内的外键有效。
顺序值 确保数字是连续的。
截断值 检测可能被截断的值。
自定义约束 基于其他列的值定义约束(例如 value * quantity == total)。
黑名单值

有时我们必须检查我们不想在我们的数据集中出现的值。它接受以下选项

选项 类型 描述
int/str 列号或名称
黑名单 str 列表 黑名单值列表

考虑以下 CSV 文件

id,name
1,John
2,bug
3,bad
5,Alex

让我们检查 name 列是否包含 bugbad 的行

from goodtables import validate

report = validate('data.csv', checks=[
    {'blacklisted-value': {'column': 'name', 'blacklist': ['bug', 'bad']}},
])
# error on row 3 with code "blacklisted-value"
# error on row 4 with code "blacklisted-value"
偏差值

此检查有助于在包含正数的列中查找异常值。它接受以下选项

选项 类型 描述
int/str 列号或名称
平均值 str 平均值类型,可以是 "mean"、"median" 或 "mode"
区间 int 值必须在 average ± standard deviation * interval 范围内

考虑以下 CSV 文件

temperature
1
-2
7
0
1
2
5
-4
100
8
3

我们使用 median 来获取列值的平均值,并允许 3 个标准差的区间。在我们的例子中,中位数是 2.0,标准差是 29.73,因此所有有效值都必须在 [-87.19, 91.19] 区间内。

report = validate('data.csv', checks=[
    {'deviated-value': {'column': 'temperature', 'average': 'median', 'interval': 3}},
])
# error on row 10 with code "deviated-value"
外键

我们支持相对路径。它必须仅用于受信任的数据源。

此检查验证数据包内的外键。考虑以下数据包定义

DESCRIPTOR = {
  'resources': [
    {
      'name': 'cities',
      'data': [
        ['id', 'name', 'next_id'],
        [1, 'london', 2],
        [2, 'paris', 3],
        [3, 'rome', 4],
        # [4, 'rio', None],
      ],
      'schema': {
        'fields': [
          {'name': 'id', 'type': 'integer'},
          {'name': 'name', 'type': 'string'},
          {'name': 'next_id', 'type': 'integer'},
        ],
        'foreignKeys': [
          {
            'fields': 'next_id',
            'reference': {'resource': '', 'fields': 'id'},
          },
          {
            'fields': 'id',
            'reference': {'resource': 'people', 'fields': 'label'},
          },
        ],
      },
    }, {
      'name': 'people',
      'data': [
        ['label', 'population'],
        [1, 8],
        [2, 2],
        # [3, 3],
        # [4, 6],
      ],
    },
  ],
}

在它上运行 goodtables 将会引发一些 foreign-key 错误,因为我们已经注释了数据包中的某些行

report = validate(DESCRIPTOR, checks=['structure', 'schema', 'foreign-key'])
print(report)
{'error-count': 2,
 'preset': 'datapackage',
 'table-count': 2,
 'tables': [{'datapackage': '...',
             'error-count': 2,
             'errors': [{'code': 'foreign-key',
                         'message': 'Foreign key "[\'next_id\']" violation in '
                                    'row 4',
                         'message-data': {'fields': ['next_id']},
                         'row-number': 4},
                        {'code': 'foreign-key',
                         'message': 'Foreign key "[\'id\']" violation in row 4',
                         'message-data': {'fields': ['id']},
                         'row-number': 4}],
             'format': 'inline',
             'headers': ['id', 'name', 'next_id'],
             'resource-name': 'cities',
             'row-count': 4,
             'schema': 'table-schema',
             'source': 'inline',
             'time': 0.031,
             'valid': False},
            {'datapackage': '...',
             'error-count': 0,
             'errors': [],
             'format': 'inline',
             'headers': ['label', 'population'],
             'resource-name': 'people',
             'row-count': 3,
             'source': 'inline',
             'time': 0.038,
             'valid': True}],
 'time': 0.117,
 'valid': False,
 'warnings': []}

它实验性地支持外部资源检查,例如,对于以下 foreignKey 定义

{"package": "../people/datapackage.json", "resource": "people", "fields": "label"}
{"package": "http:/example.com/datapackage.json", "resource": "people", "fields": "label"}
顺序值

这是一个非常常见的检查情况,当一列应该有顺序递增的整数时。它接受以下选项

选项 类型 描述
int/str 列号或名称

考虑以下 CSV 文件

id,name
1,one
2,two
3,three
5,five

让我们检查 id 列是否包含顺序整数

from goodtables import validate

report = validate('data.csv', checks=[
    {'sequential-value': {'column': 'id'}},
])
# error on row 5 with code "sequential-value"
截断值

某些数据库或电子表格软件(如 MySQL 或 Excel)在保存时可能会截断值。有一些已知的方法可以找到这些不良值。有关更详细的信息,请参阅 https://github.com/propublica/guides/blob/master/data-bulletproofing.md

考虑以下 CSV 文件

id,amount,comment
1,14000000,good
2,2147483647,bad
3,32767,bad
4,234234234,bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbad

要检测所有可能被截断的值,我们可以使用 truncated-value 检查

report = validate('data.csv', checks=[
    'truncated-value',
])
# error on row 3 with code "truncated-value"
# error on row 4 with code "truncated-value"
# error on row 5 with code "truncated-value"
自定义约束

使用表架构,我们可以为单个字段创建约束,但有时这还不够。使用自定义约束检查,可以针对每行与给定的有限 Python 表达式进行比较,其中变量名解析为列值。请参阅 可用运算符列表。它接受以下选项

约束 (str)
约束定义(例如 col1 + col2 == col3

考虑以下 CSV 文件

id,name,salary,bonus
1,Alex,1000,200
2,Sam,2500,500
3,Ray,1350,500
4,John,5000,1000

假设我们的业务规则是对奖金持谨慎态度

report = validate('data.csv', checks=[
    {'custom-constraint': {'constraint': 'salary > bonus * 4'}},
])
# error on row 4 with code "custom-constraint"

常见问题解答

如何添加新的自定义检查?

要创建自定义检查,用户可以使用check装饰器。这样就可以覆盖内置检查(使用规范错误代码如duplicate-row)或添加对自定义错误的检查(使用typecontextposition参数)。

from goodtables import validate, check, Error

@check('custom-check', type='custom', context='body')
def custom_check(cells):
    errors = []
    for cell in cells:
        message = 'Custom error on column {column_number} and row {row_number}'
        error = Error(
            'custom-error',
            cell,
            message
        )
        errors.append(error)
    return errors

report = validate('data.csv', checks=['custom-check'])

推荐步骤

如何添加对新的表格文件类型的支持?

要创建自定义预设,用户可以使用preset装饰器。这样就可以覆盖内置预设或添加自定义预设。

from tabulator import Stream
from tableschema import Schema
from goodtables import validate

@preset('custom-preset')
def custom_preset(source, **options):
    warnings = []
    tables = []
    for table in source:
        try:
            tables.append({
                'source':  str(source),
                'stream':  Stream(...),
                'schema': Schema(...),
                'extra': {...},
            })
        except Exception:
            warnings.append('Warning message')
    return warnings, tables

report = validate(source, preset='custom-preset')

目前,本节文档不完整。请参阅内置预设,了解有关数据集提取协议的更多信息。

API参考

cli

cli()

命令行界面

Usage: cli.py [OPTIONS] COMMAND [ARGS]...

Options:
  --version  Show the version and exit.
  --help     Show this message and exit.

Commands:
  validate*  Validate tabular files (default).
  init       Init data package from list of files.

validate

validate(source, **options)

验证源文件并返回报告。

参数

  • source (Union[str, Dict, List[Dict], IO]):要验证的源。可以是本地文件路径、URL、字典、字典列表或文件-like对象。如果是字典列表且预设为“嵌套”,则每个字典键都将用作此方法的键参数。

      The file can be a CSV, XLS, JSON, and any other format supported by
      `tabulator`_.
    
  • checks (List[str]):要启用的检查名称列表。可以是单个检查名称(例如blank-headers),也可以是检查类型(例如structure)。

  • skip_checks (List[str]):要跳过的检查名称列表。可以是单个检查名称(例如blank-headers),也可以是检查类型(例如structure)。

  • infer_schema (bool):如果没有传递参数,则推断模式。

  • infer_fields (bool):推断未在收到的模式中出现的列的模式。

  • order_fields (bool):根据模式字段顺序对源列进行排序。这在您不想验证数据列的顺序与模式相同时很有用。

  • error_limit (int):如果每张表中错误数超过此值,则停止验证。

  • table_limit (int):最大验证表数。

  • row_limit (int):最大验证行数。

  • preset (str):数据集类型可以是table(默认)、datapackagenested或自定义。通常,预设可以从源推断,因此您不需要定义它。

  • Any (Any):此处未定义的任何附加参数将根据所选的preset传递。如果预设为table,则额外参数将传递给tabulator;如果预设为datapackage,则将传递给datapackage构造函数。

引发

  • GoodtablesException:在发生任何非表格错误时引发。

返回

dict:验证报告。

preset

preset(name)

注册自定义预设(装饰器)

示例

@preset('custom-preset')
def custom_preset(source, **options):
    # ...

参数

  • name (str):预设名称

check

check(name, type=None, context=None, position=None)

注册自定义检查(装饰器)

示例

@check('custom-check', type='custom', context='body')
def custom_check(cells):
    # ...

参数

  • name (str):预设名称
  • type (str):必须是custom
  • context (str):必须是headbody
  • position (str):必须是before:<check-name>after:<check-name>

Error

Error(self, code, cell=None, row_number=None, message=None, message_substitutions=None)

描述验证检查错误

参数

  • code (str):错误代码。必须是规范中的一个。
  • cell (dict, optional):发生错误的单元格。
  • row_number (int, optional):发生错误的行号。
  • message (str, optional):错误消息。默认为数据质量规范中的消息。
  • message_substitutions (dict, optional):用于生成错误消息和描述的替换字典。

引发

  • KeyError:如果错误代码未知,将引发此错误。

spec

dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. 例如:dict(one=1, two=2)

GoodtablesException

GoodtablesException(self, /, *args, **kwargs)

Base goodtables exception

贡献

该项目遵循Open Knowledge International编码标准

建议的入门方法是创建并激活项目虚拟环境。要将包和开发依赖项安装到活动环境中

$ make install

运行具有lint和覆盖率测试

$ make test

变更日志

以下仅描述了破坏性变更和最重要的变更。所有发布版本的完整变更日志和文档可以在格式良好的提交历史记录中找到。

v2.5
v2.4
  • 添加了对数据包的完整性检查。如果提供了resource.bytesresource.hash(sha256),则将对其进行验证,以与实际值进行核对
v2.3
  • 添加了对外键的检查
v2.2
  • 改进了缺失/不匹配标题的检测(#298
v2.1
  • error.to_dict返回中添加了一个新的键:message-data
v2.0

破坏性变更

  • 现在,检查方法签名仅接收当前行的cells列表
  • 通过返回Error对象数组来引发错误
  • 单元格在row-number键中具有行号
  • 扩展名为ZIP的文件假定是数据包,因此goodtables mydatapackage.zip有效
  • 改进了goodtables CLI(#233
  • 添加了新的goodtables init <data paths>命令,用于使用传递的文件及其推断的模式创建新的datapackage.json

错误修复

  • 修复了日期字段上truncated-values检查的bug(#250
v1.5

添加了新API

  • 现在,验证source可以是pathlib.Path
v1.4

改进了行为

  • 基于Data Quality Spec v1进行重基
  • 基于Data Package Spec v1进行重基
  • 基于Table Schema Spec v1进行重基
  • 将主键视为必需/唯一字段
v1.3

添加了新的高级检查

  • 黑名单值
  • 自定义约束
  • 偏差值
  • 顺序值
  • 截断值
v1.2

添加了新API

  • report.preset
  • report.tables[].schema
v1.1

添加了新API

  • report.tables[].scheme
  • report.tables[].format
  • report.tables[].encoding
v1.0

本版本包含各种重大变更。迁移指南正在开发中,并将在此发布。

v0.6

goodtables的第一个版本。

项目详细信息


发布历史 发布通知 | RSS源

下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源代码分发

goodtables-2.5.4.tar.gz (66.4 kB 查看哈希值)

上传时间 源代码

构建分发

goodtables-2.5.4-py2.py3-none-any.whl (58.0 kB 查看哈希值)

上传时间 Python 2 Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面