Goodtables是一个用于检查表格数据的框架。
项目描述
goodtables-py
Goodtables是一个用于验证表格数据的框架。它可以检查您数据的结构(例如,所有行都有相同数量的列),以及其内容(例如,所有日期都是有效的)。
[重要通知]
goodtables
从版本3开始更名为frictionless
。该框架得到了各种改进,并扩展成为一个完整的数据解决方案。这种更改不会破坏现有的软件,因此无需采取任何行动。请阅读迁移指南,以开始使用Python的Frictionless。
功能
- 结构检查:确保没有空行,没有空白标题等。
- 内容检查:确保值具有正确的类型(“字符串”、“数字”、“日期”等),它们的格式有效(“字符串必须是电子邮件”),并且它们遵守约束(“年龄必须是一个大于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中的主要验证角色。可以使用checks
和skip_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支持表格数据集的不同格式。它们被称为预设。表格数据集是一些可以分割成数据表列表的数据,如下所示:
我们可以使用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
列是否包含 bug
或 bad
的行
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
)或添加对自定义错误的检查(使用type
、context
和position
参数)。
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'])
推荐步骤
- 让我们先在评论中讨论一下提议的检查
- 为新检查选择名称,例如
possible-noise-text
- 将https://github.com/frictionlessdata/goodtables-py/blob/master/goodtables/contrib/checks/blacklisted_value.py复制到新检查模块
- 将新检查模块添加到配置中 - https://github.com/frictionlessdata/goodtables-py/blob/master/goodtables/config.py
- 编写新检查的实际代码
- 为新检查编写测试和readme
如何添加对新的表格文件类型的支持?
要创建自定义预设,用户可以使用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
(默认)、datapackage
、nested
或自定义。通常,预设可以从源推断,因此您不需要定义它。 -
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):必须是
head
或body
- 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
贡献
建议的入门方法是创建并激活项目虚拟环境。要将包和开发依赖项安装到活动环境中
$ make install
运行具有lint和覆盖率测试
$ make test
变更日志
以下仅描述了破坏性变更和最重要的变更。所有发布版本的完整变更日志和文档可以在格式良好的提交历史记录中找到。
v2.5
- 添加了
check.check_headers_hook
以支持对body上下文检查的标题检查(有关原生支持,请参阅https://github.com/frictionlessdata/goodtables-py/tree/v3)
v2.4
- 添加了对数据包的完整性检查。如果提供了
resource.bytes
或resource.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
的第一个版本。
项目详细信息
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。
源代码分发
构建分发
goodtables-2.5.4.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 67c51ac98967684763adb6406f92a683571d144b3a80095b0351a65f49848027 |
|
MD5 | 89d708f61494bcb50b05d096ec6b0774 |
|
BLAKE2b-256 | 9325c691e85a93d0411ef50903a56ff26ffcc784f392e2765d2555548a0dd1a0 |
goodtables-2.5.4-py2.py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 6175806b5aa1879e6eeb6899df69edd6ba22ef5e99b23f6a35b55f49b7800076 |
|
MD5 | 58ade63dbcb908ede947c50109661b7a |
|
BLAKE2b-256 | 9cead0015027c1cd008cc4da48829747f3f9e585ed541349ca66d0e4ee0c2cab |