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
示例代码(假设结构体无嵌套)
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以字符串/数字形式输出:
- 在Cargo.toml添加依赖:
serde_with = "3.4.0" rust_decimal = "1.35.0"
- 修改结构体的序列化配置:
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, }
- 从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
相关产品推荐
相关产品推荐

