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

Polars转换JSON至DataFrame触发Panic问题求助

解决Polars JsonReader转换Vec为DataFrame时的Panic问题

核心问题分析

你遇到的panic本质是:Polars的JsonReader在解析由自定义结构体序列生成的JSON时,遇到了Arrow不支持的类型(大概率是嵌套结构体,或是decimal类型被序列化为结构体格式)。直接用JsonReader处理“反序列化后的Vec再转JSON”的流程冗余且容易触发类型兼容问题,更高效的方式是直接从Vec构造DataFrame。

解决方案1:直接从Vec构造DataFrame(推荐)

既然已经完成了JSON到Vec的反序列化,没必要再转成JSON让JsonReader重新解析,直接提取字段构建Series再组装DataFrame更可控。

示例代码(假设结构体无嵌套)

use polars::prelude::*;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct StockZhAHist {
    date: String,
    open: f64,
    close: f64,
    volume: u64,
}

fn main() {
    // 假设已经从服务器获取并反序列化得到data: Vec<StockZhAHist>
    let data = vec![
        StockZhAHist {
            date: "2024-01-01".to_string(),
            open: 10.5,
            close: 11.2,
            volume: 1000000,
        },
        // 更多数据...
    ];

    // 提取各字段为Vec
    let dates: Vec<&str> = data.iter().map(|item| item.date.as_str()).collect();
    let opens: Vec<f64> = data.iter().map(|item| item.open).collect();
    let closes: Vec<f64> = data.iter().map(|item| item.close).collect();
    let volumes: Vec<u64> = data.iter().map(|item| item.volume).collect();

    // 构造DataFrame
    let df = DataFrame::new(vec![
        Series::new("date", dates),
        Series::new("open", opens),
        Series::new("close", closes),
        Series::new("volume", volumes),
    ]).unwrap();

    println!("{}", df);
}

如果结构体包含嵌套字段

如果StockZhAHist里有嵌套结构体,需要先扁平化字段:

#[derive(Debug, Deserialize)]
struct PriceDetails {
    open: f64,
    close: f64,
}

#[derive(Debug, Deserialize)]
struct StockZhAHist {
    date: String,
    price: PriceDetails,
    volume: u64,
}

// 提取嵌套字段
let opens: Vec<f64> = data.iter().map(|item| item.price.open).collect();
let closes: Vec<f64> = data.iter().map(|item| item.price.close).collect();
// 构造Series时用明确的列名(如price_open、price_close)

解决方案2:处理Decimal类型导致的Struct问题

如果错误是由decimal类型被序列化为结构体(比如{"value": 123, "scale": 2})导致的,需要调整序列化方式,让decimal以字符串/数字形式输出:

  1. 在Cargo.toml添加依赖:
serde_with = "3.4.0"
rust_decimal = "1.35.0"
  1. 修改结构体的序列化配置:
use rust_decimal::Decimal;
use serde::Deserialize;
use serde_with::{serde_as, DisplayFromStr};

#[serde_as]
#[derive(Debug, Deserialize)]
struct StockZhAHist {
    date: String,
    #[serde_as(as = "DisplayFromStr")]
    open: Decimal,
    #[serde_as(as = "DisplayFromStr")]
    close: Decimal,
    volume: u64,
}
  1. 从Vec构造DataFrame时直接使用Decimal类型(需确保Polars开启dtype-decimal特性):
let opens: Vec<Decimal> = data.iter().map(|item| item.open).collect();
let open_series = Series::new("open", opens);
// 其他字段同理,组装DataFrame

解决方案3:手动指定Schema使用JsonReader

如果一定要用JsonReader,需要手动定义Schema告诉Polars如何识别结构体类型:

use polars::prelude::*;
use serde_json::to_string;
use std::io::Cursor;

// 假设data是已经反序列化的Vec<StockZhAHist>
let json_str = to_string(&data).unwrap();

// 定义与结构体匹配的Schema
let schema = Schema::new(vec![
    Field::new("date", DataType::Utf8),
    Field::new("open", DataType::Float64),
    Field::new("close", DataType::Float64),
    Field::new("volume", DataType::UInt64),
]);

let df = JsonReader::new(Cursor::new(json_str))
    .with_schema(&schema)
    .finish()
    .unwrap();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 22:17:01