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

Polars长结构体列表解析异常:仅前25项字段可正常解析

Polars嵌套结构体列表的类型解析问题

我遇到了一个疑似类型推断的问题:当处理包含4种不同数据类型字段的结构体列表时,Polars仅解析列表前25项中出现过值的字段。

我先通过json.loads将JSON数据转换为字典后加载到DataFrame,数据存在大量嵌套结构。问题出在一个结构体列表类型的列上,加载时已传入预定义Schema,该字段的Schema定义如下:

{
"attributes": pl.List(pl.Struct({
  "stringValue": pl.String,
  "boolValue": pl.Boolean,
  "intValue": pl.Int64,
  "doubleValue": pl.Float64
}))}

列表中的每个条目仅包含一种类型的值。例如,若字符串和布尔类型的值出现在前25项中,后续条目里的这两类值能被正确解析;但如果整数类型的值出现在第25项之后,会被解析为None。

请问这是预期行为吗?是否可以配置类型推断的样本数量?有没有解决方案?

我尝试过多种Schema定义、调整infer_schema_length参数、切换使用read_json和pl.DataFrame加载方式。调整测试数据中列表项的顺序可以解决问题,但我无法控制原数据中列表项的顺序。

更新:示例代码

import polars as pl

data_schema = {
    "attributes": pl.List(pl.Struct({
        "key": pl.String,
        "value": pl.Struct({
            "stringValue": pl.String,
            "doubleValue": pl.Float64,
            "boolValue": pl.Boolean,
            "intValue": pl.Int64,
        }),
    })),
}

data = [
    {
        "attributes": [
            {"key": "string1", "value": {"stringValue": "sv1"}},
            {"key": "string2", "value": {"stringValue": "sv2"}},
            {"key": "string3", "value": {"stringValue": "sv3"}},
            {"key": "string4", "value": {"stringValue": "sv4"}},
            {"key": "string5", "value": {"stringValue": "sv5"}},
            {"key": "string6", "value": {"stringValue": "sv6"}},
            {"key": "string7", "value": {"stringValue": "sv7"}},
            {"key": "string8", "value": {"stringValue": "sv8"}},
            {"key": "string9", "value": {"stringValue": "sv9"}},
            {"key": "int1", "value": {"intValue": 1}},
            {"key": "int2", "value": {"intValue": 2}},
            {"key": "int3", "value": {"intValue": 3}},
            {"key": "string10", "value": {"stringValue": "sv10"}},
            {"key": "string11", "value": {"stringValue": "sv11"}},
            {"key": "string12", "value": {"stringValue": "sv12"}},
            {"key": "string13", "value": {"stringValue": "sv13"}},
            {"key": "string14", "value": {"stringValue": "sv14"}},
            {"key": "string15", "value": {"stringValue": "sv15"}},
            {"key": "string16", "value": {"stringValue": "sv16"}},
            {"key": "string17", "value": {"stringValue": "sv17"}},
            {"key": "string18", "value": {"stringValue": "sv18"}},
            {"key": "string19", "value": {"stringValue": "sv19"}},
            {"key": "string20", "value": {"stringValue": "sv20"}},
            {"key": "string21", "value": {"stringValue": "sv21"}},
            {"key": "string22", "value": {"stringValue": "sv22"}},
            {"key": "string23", "value": {"stringValue": "sv23"}},
            {"key": "string24", "value": {"stringValue": "sv24"}},
            {"key": "string25", "value": {"stringValue": "sv25"}},
            {"key": "int4", "value": {"intValue": 4}},
            {"key": "int5", "value": {"intValue": 5}},
            {"key": "bool1", "value": {"boolValue": True}},
            {"key": "bool2", "value": {"boolValue": False}},
            {"key": "bool3", "value": {"boolValue": True}},
            {"key": "double1", "value": {"doubleValue": 0.1}},
            {"key": "double2", "value": {"doubleValue": 2.3}},
        ]
    }
]

df = pl.DataFrame(data, schema=data_schema)

df.rows()

输出结果

[([{'key': 'string1',
    'value': {'stringValue': 'sv1',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string2',
    'value': {'stringValue': 'sv2',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string3',
    'value': {'stringValue': 'sv3',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string4',
    'value': {'stringValue': 'sv4',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string5',
    'value': {'stringValue': 'sv5',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string6',
    'value': {'stringValue': 'sv6',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string7',
    'value': {'stringValue': 'sv7',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string8',
    'value': {'stringValue': 'sv8',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string9',
    'value': {'stringValue': 'sv9',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'int1',
    'value': {'stringValue': None,
     'doubleValue': None,
     'boolValue': None,
     'intValue': 1}},
   {'key': 'int2',
    'value': {'stringValue': None,
     'doubleValue': None,
     'boolValue': None,
     'intValue': 2}},
   {'key': 'int3',
    'value': {'stringValue': None,
     'doubleValue': None,
     'boolValue': None,
     'intValue': 3}},
   {'key': 'string10',
    'value': {'stringValue': 'sv10',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string11',
    'value': {'stringValue': 'sv11',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string12',
    'value': {'stringValue': 'sv12',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string13',
    'value': {'stringValue': 'sv13',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string14',
    'value': {'stringValue': 'sv14',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string15',
    'value': {'stringValue': 'sv15',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string16',
    'value': {'stringValue': 'sv16',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string17',
    'value': {'stringValue': 'sv17',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string18',
    'value': {'stringValue': 'sv18',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string19',
    'value': {'stringValue': 'sv19',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string20',
    'value': {'stringValue': 'sv20',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string21',
    'value': {'stringValue': 'sv21',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string22',
    'value': {'stringValue': 'sv22',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string23',
    'value': {'stringValue': 'sv23',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string24',
    'value': {'stringValue': 'sv24',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'string25',
    'value': {'stringValue': 'sv25',
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'int4',
    'value': {'stringValue': None,
     'doubleValue': None,
     'boolValue': None,
     'intValue': 4}},
   {'key': 'int5',
    'value': {'stringValue': None,
     'doubleValue': None,
     'boolValue': None,
     'intValue': 5}},
   {'key': 'bool1',
    'value': {'stringValue': None,
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'bool2',
    'value': {'stringValue': None,
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'bool3',
    'value': {'stringValue': None,
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'double1',
    'value': {'stringValue': None,
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}},
   {'key': 'double2',
    'value': {'stringValue': None,
     'doubleValue': None,
     'boolValue': None,
     'intValue': None}}],)]

解决方案

这个问题是Polars在处理嵌套结构体列表时的隐性类型推断逻辑导致的:即使传入了顶层Schema,Polars在解析列表内的结构体时,仍会默认采样前25个元素来推断结构体的实际字段存在性,忽略Schema中定义的后续字段。

解决方法:

  • 使用pl.Struct的strict=True参数
    在定义结构体Schema时,添加strict=True强制Polars严格遵循Schema中的所有字段定义,不再进行采样推断:

    data_schema = {
        "attributes": pl.List(pl.Struct({
            "key": pl.String,
            "value": pl.Struct({
                "stringValue": pl.String,
                "doubleValue": pl.Float64,
                "boolValue": pl.Boolean,
                "intValue": pl.Int64,
            }, strict=True),  # 启用严格模式
        })),
    }
    

    这样Polars会严格按照Schema解析所有字段,无论它们出现在列表的哪个位置。

  • 直接使用read_json并指定Schema
    跳过json.loads转字典的步骤,直接用pl.read_json加载原始JSON文件,并传入带strict=True的Schema:

    df = pl.read_json("your_data.json", schema=data_schema)
    

    这种方式能避免字典转译过程中的信息丢失,同时严格遵循Schema定义。

  • 调整全局采样长度(不推荐)
    可以通过设置环境变量POLARS_INFER_SCHEMA_LENGTH来修改默认采样数量,比如设置为-1表示采样全部数据:

    import os
    os.environ["POLARS_INFER_SCHEMA_LENGTH"] = "-1"
    

    但这种方法会影响所有Polars操作的性能,尤其是大数据量时,因此优先推荐前两种方法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:27:02