如何不通过List直接构造Array Series?附Polars相关技术疑问
关于Polars中FixedSizeList构建及相关API的疑问
我目前通过以下方式实现创建固定长度数组列的需求:
let mut col1: ListPrimitiveChunkedBuilder<Float64Type> = ListPrimitiveChunkedBuilder::new( "array", 1, 2, DataType::Float64); col1.append_slice(&[1.1,2.2]); col1.append_slice(&[2.1,2.2]); col1.append_slice(&[3.1,2.2]); let s = col1.finish().into_series(); let sa = s.cast(&DataType::Array(Box::new(DataType::Float64), 2)).unwrap(); let df = DataFrame::new(vec![sa]); println!("{:?}",df)
输出结果:
shape: (3, 1) ┌───────────────┐ │ array │ │ --- │ │ array[f64, 2] │ ╞═══════════════╡ │ [1.1, 2.2] │ │ [2.1, 2.2] │ │ [3.1, 2.2] │ └───────────────┘
但先创建List再转换为FixedSize Array的方式显得冗余。我在polars-core/src/chunked_array_builder/fixed_size_list.rs中找到了FixedSizeListNumericBuilder,但不知道如何使用。
另外还有两个附加问题:
- 在
ListPrimitiveChunkedBuilder中,capacity和values_capacity的作用是什么?它们似乎没有约束力(即我可以指定更多的横向和纵向值)。 - 为什么必须用
Box::new()包裹DataType::Float64?
解答
1. 直接使用FixedSizeListNumericBuilder构建固定长度数组列
不需要先创建List再转换,直接用FixedSizeListNumericBuilder可以一步到位生成FixedSize List类型的列,示例代码如下:
use polars::prelude::*; fn main() { // 初始化构建器:参数依次为列名、每个数组的固定长度、预分配的行容量(可选,优化内存) let mut builder = FixedSizeListNumericBuilder::<Float64Type>::new( "array", 2, // 固定每个数组元素长度为2 3, // 预分配3行的空间,可根据实际情况调整 ); // 追加元素组,每组长度必须等于设定的固定长度 builder.append_slice(&[1.1, 2.2]).unwrap(); builder.append_slice(&[2.1, 2.2]).unwrap(); builder.append_slice(&[3.1, 2.2]).unwrap(); // 完成构建并转为Series,直接就是array[f64,2]类型 let sa = builder.finish().into_series(); let df = DataFrame::new(vec![sa]).unwrap(); println!("{:?}", df); }
执行后会直接得到和之前一致的DataFrame,省去了类型转换的步骤。
2. capacity和values_capacity的作用
这两个参数都是内存预分配优化参数,而非硬性限制:
capacity:预分配的行数量(即最终生成的List列有多少行),提前分配对应空间可以避免后续频繁扩容带来的性能开销。Polars的Builder支持动态扩容,所以即使你添加的行数超过这个值,它也会自动调整内存,不会报错。values_capacity:预分配的所有List元素的总数量(比如3行×2个元素=6个总元素),同样是为了减少内存扩容次数。当实际元素总数超过这个值时,Builder会自动扩容,因此看起来没有约束力。
3. 为什么要用Box::new()包裹DataType
DataType是一个递归枚举类型,比如DataType::Array内部需要包含另一个DataType(元素类型),而这个内部的DataType又可能是Array、Struct等递归结构。
在Rust中,编译器需要在编译时确定每个类型的大小,如果枚举变体包含递归的自身类型,会导致大小无限递归无法确定。使用Box::new()将内部的DataType包装成一个指针,指针的大小是固定的(在64位系统是8字节),这样就能解决递归类型的大小计算问题,让DataType枚举可以正常定义和使用。
内容的提问来源于stack exchange,提问作者Dean MacGregor
相关产品推荐
相关产品推荐

