数据类型验证

pandera 的核心功能是它允许您验证传入原始数据的类型,以便您的数据管道可以提前失败,而不是将数据损坏传播到下游的关键应用程序。这些应用程序可能包括依赖于干净数据进行有效分析的分析、统计和机器学习用例。

我怎样指定数据类型?

使用pandera模式,有多种方式来指定列、索引或整个数据框的数据类型。

import pandera as pa
import pandas as pd

# schema with datatypes at the column and index level
schema_field_dtypes = pa.DataFrameSchema(
    {
        "column1": pa.Column(int),
        "column2": pa.Column(float),
        "column3": pa.Column(str),
    },
    index = pa.Index(int),
)

# schema with datatypes at the dataframe level, if all columns are the
# same data type
schema_df_dtypes = pa.DataFrameSchema(dtype=int)

等效的 DataFrameModel 将是:

from pandera.typing import Series, Index

class ModelFieldDtypes(pa.DataFrameModel):
    column1: Series[int]
    column2: Series[float]
    column3: Series[str]
    index: Index[int]

class ModelDFDtypes(pa.DataFrameModel):
    class Config:
        dtype = int

支持的pandas数据类型

默认情况下,pandera 支持验证 pandas 数据帧,因此 pandera 模式支持 pandas 支持的任何 数据类型

  • 内置的python类型,例如 intfloatstrbool 等。

  • Numpy 数据类型,例如 numpy.int_numpy.bool__ 等。

  • Pandas原生数据类型,例如 pd.StringDtype, pd.BooleanDtype, pd.DatetimeTZDtype 等。

  • 任何由 pandas 支持的 字符串别名

我们推荐使用内置的python数据类型来处理常见的数据类型,但最终由您决定如何表示这些类型。此外,如果您愿意,也可以使用pandera定义的数据类型

例如,以下模式以六种不同的方式表示等效的整数类型:

import numpy as np

integer_schema = pa.DataFrameSchema(
    {
        "builtin_python": pa.Column(int),
        "builtin_python": pa.Column("int"),
        "string_alias": pa.Column("int64"),
        "numpy_dtype": pa.Column(np.int64),
        "pandera_dtype_1": pa.Column(pa.Int),
        "pandera_dtype_2": pa.Column(pa.Int64),
    },
)

注意

Windows的默认 int 类型是32位整数 int32

参数化数据类型

需要注意的一点是,将纯Python类型(即类)声明为列的数据类型与参数化类型之间的区别,在pandas的情况下,实际上是pandas定义的特殊类的实例。例如,使用基于对象的API,我们可以轻松地将列定义为时区感知数据类型:

datetimeschema = pa.DataFrameSchema({
    "dt": pa.Column(pd.DatetimeTZDtype(unit="ns", tz="UTC"))
})

然而,由于 python 的类型注解需要类型而不是对象,要通过基于类的 API 表达相同的类型,我们需要使用一个 Annotated 类型:

try:
    from typing import Annotated  # python 3.9+
except ImportError:
    from typing_extensions import Annotated

class DateTimeModel(pa.DataFrameModel):
    dt: Series[Annotated[pd.DatetimeTZDtype, "ns", "UTC"]]

或者,您可以将 dtype_kwargs 传递给 Field()

class DateTimeModel(pa.DataFrameModel):
    dt: Series[pd.DatetimeTZDtype] = pa.Field(dtype_kwargs={"unit": "ns", "tz": "UTC"})

您可以在 这里阅读更多关于支持的参数化数据类型的信息。

数据类型强制转换

Pandera主要是一个验证库:它仅检查数据框架的架构元数据或数据值,而不更改数据框架本身的任何内容。

然而,在许多情况下,将数据值 解析,即转换为 pandera 模式中指定的数据合约是有用的。目前,pandera 唯一的转换是类型强制转换,这可以通过将 coerce=True 参数传递给模式或模式组件对象来完成:

如果提供了这个参数,调用 schema.validate 将尝试将输入的数据框值转换为指定的数据类型,而不是简单地检查列/索引的正确类型。

然后将对数据应用数据框、列和索引级别的检查,所有这些都是纯粹的 验证器

数据类型如何与 nullable 交互

参数 nullable 可以在列、索引或 SeriesSchema 级别指定,实质上是一个核心的 pandera 检查。因此,它是在前一部分描述的数据类型检查/强制转换步骤之后应用的。因此,本身不允许为 null 的数据类型即使你指定了 nullable=True 也会失败,因为 pandera 将类型检查视为一个一流的检查,这与你可能想应用于数据的任何后续检查是不同的。

对python typing模块的支持

0.15.0中新功能

Pandera还支持typing模块中一组有限的通用和特殊类型,以便您验证包含object值的列:

  • typing.Dict[K, V]

  • typing.List[T]

  • typing.Tuple[T, ...]

  • typing.TypedDict

  • typing.NamedTuple

重要

在底层, pandera 使用 typeguard 来验证这些泛型类型。如果您安装了 typeguard >= 3.0.0pandera 将使用 typeguard.CollectionCheckStrategy 来验证数据值中的所有项,否则它将仅检查第一个项。

例如:

import sys
from typing import Dict, List, Tuple, NamedTuple

if sys.version_info >= (3, 12):
    from typing import TypedDict
    # use typing_extensions.TypedDict for python < 3.9 in order to support
    # run-time availability of optional/required fields
else:
    from typing_extensions import TypedDict


class PointDict(TypedDict):
    x: float
    y: float

class PointTuple(NamedTuple):
    x: float
    y: float

schema = pa.DataFrameSchema(
    {
        "dict_column": pa.Column(Dict[str, int]),
        "list_column": pa.Column(List[float]),
        "tuple_column": pa.Column(Tuple[int, str, float]),
        "typeddict_column": pa.Column(PointDict),
        "namedtuple_column": pa.Column(PointTuple),
    },
)

data = pd.DataFrame({
    "dict_column": [{"foo": 1, "bar": 2}],
    "list_column": [[1.0]],
    "tuple_column": [(1, "bar", 1.0)],
    "typeddict_column": [PointDict(x=2.1, y=4.8)],
    "namedtuple_column": [PointTuple(x=9.2, y=1.6)],
})

schema.validate(data)
字典列 列表列 元组列 类型字典列 命名元组列
0 {'foo': 1, 'bar': 2} [1.0] (1, bar, 1.0) {'x': 2.1, 'y': 4.8} (9.2, 1.6)

Pandera使用typeguard进行数据类型验证,使用pydantic进行数据值强制转换,前提是您在列级、索引级或数据框级指定了coerce=True

注意

对于某些类型,比如 List[T]typeguard 只会检查第一个值的类型,例如,如果你指定 List[int],数据值 [1, "foo", 1.0] 仍然会通过。检查所有值将在未来版本的 pandera 中可配置,当 typeguard > 4.*.* 被支持时。

Pyarrow 数据类型

pandas 验证引擎现在支持 pyarrow 数据类型。您可以传递 pyarrow-native 数据类型,pandas 字符串别名或 pandas ArrowDtype 类,例如:

import pyarrow

pyarrow_schema = pa.DataFrameSchema({
    "pyarrow_dtype": pa.Column(pyarrow.float64()),
    "pandas_str_alias": pa.Column("float64[pyarrow]"),
    "pandas_dtype": pa.Column(pd.ArrowDtype(pyarrow.float64())),
})

并且在使用基于类的API时,您必须指定实际类型(不支持字符串别名):

try:
    from typing import Annotated  # python 3.9+
except ImportError:
    from typing_extensions import Annotated


class PyarrowModel(pa.DataFrameModel):
    pyarrow_dtype: pyarrow.float64
    pandas_dtype: Annotated[pd.ArrowDtype, pyarrow.float64()]
    pandas_dtype_kwargs: pd.ArrowDtype = pa.Field(dtype_kwargs={"pyarrow_dtype": pyarrow.float64()})