You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Pydantic 2.11.7捕获Pandas 2.3.0中的缺失NaN值?

前置条件

  • Python 3.11.7
  • Pandas 2.3.0
  • Numpy 2.1.3
  • Pydantic 2.11.7

Pandas文档说明,数值类型的缺失值会用numpy.nan填充:

In [1]:
import pandas as pd
import numpy as np

In [2]:
s = pd.Series([1, 2], dtype=np.int64).reindex([0, 1, 2])

In [3]:
s
Out[3]: 
0    1.0
1    2.0
2    NaN
dtype: float64

理论上在Pydantic模型中,可以用Literal[numpy.nan]捕获numpy.nan,结合typing.Union就能创建支持复杂逻辑的模型,比如接受正整数或numpy.nan:

In [4]:
import numpy as np
import pydantic

from typing import Union, Literal

class Col(pydantic.BaseModel):
    precision: Union[
        pydantic.conint(ge=1),
        Literal[np.nan]
    ]

但在上述Pandas示例中,遍历Series的values遇到缺失值时,Pydantic验证失败:

In [5]:
for i in s.values:
    print(i)
    Col(precision=i)
Out[5]:
1.0
2.0
nan

---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
Cell In[5], line 3
      1 for i in s.values:
      2     print(i)
----> 3     Col(precision=i)

File ~/........./python3.11/site-packages/pydantic/main.py:253, in BaseModel.__init__(self, **data)
    251 # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    252 __tracebackhide__ = True
--> 253 validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
    254 if self is not validated_self:
    255     warnings.warn(
    256         'A custom validator is returning a value other than `self`.
'
    257         "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.
"
    258         'See the `model_validator` docs for more details.',
    259         stacklevel=2,
    260     )

ValidationError: 2 validation errors for Col
precision.constrained-int
  Input should be a finite number [type=finite_number, input_value=nan, input_type=float64]
precision.literal[nan]
  Input should be nan [type=literal_error, input_value=nan, input_type=float64]

但直接传入常规numpy.nan时,验证却能正常通过:

In [6]:
Col(precision=np.nan)
Out[6]:
Col(precision=nan)

这似乎说明Pandas填充的缺失值并非常规numpy.nan,请问该缺失值是什么类型?如何用Pydantic和类型注解优雅捕获它?


目前我有一个临时解决方案:用pydantic.confloat(allow_inf_nan=True)替代Literal[np.nan],再添加模型验证器确保非NaN值符合要求,但该方案不够优雅:

In [7]:
import math

class Col2(pydantic.BaseModel):
    precision: Union[
        pydantic.conint(ge=1),
        pydantic.confloat(allow_inf_nan=True)
    ]

    @pydantic.model_validator(mode="after")
    def validate_nans(self):
        if self.precision is not None and isinstance(self.precision, float):
            if self.precision.is_integer():
                assert self.precision >= 0
            else:
                assert math.isnan(self.precision)

该方案对多种NaN类型均有效:

In [8]:
import pytest

bad_nan = s.iloc[-1]

test_values = [
    (0, True), (-1, False), (-1.234, False), (1.234, False), (2, True),
    (3.0, True), (-3.0, False),
    (bad_nan, True), (np.nan, True), (float('nan'), True), (np.float64('nan'), True),
    (False, True), (True, True)  # Bool False is 0, True is 1. This is fine.
]

for val, should_pass in test_values:
    if should_pass:
        Col2(precision=val)
    else:
        with pytest.raises(pydantic.ValidationError):
            Col2(precision=val)
Out[8]:
============================== 1 passed in 0.05s ===============================

以下是我尝试过但无效的方案:

  • Annotated[pydantic.conint(ge=0), pydantic.AllowInfNan()]
    失败原因:无法在一个注解类型中混合int和NaN浮点类型。
  • pydantic.confloat(ge=0, multiple_of=1, allow_inf_nan=True)
    失败原因:无法同时指定ge参数与allow_inf_nan=True(NaN不满足大于等于0的条件)。

内容的提问来源于stack exchange,提问作者MikeFenton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 10:34:52