如何在Rust中将二维ndarray转换为Polars的List<f64> Series?
从ndarray::Array2高效转换为Polars List[f64]类型Series
原方法性能瓶颈分析
你当前实现的方法速度慢,核心原因是逐行创建小Series带来的额外开销:每个Series::from_vec都会初始化元数据、单独分配内存,频繁的小对象操作和内存拷贝会大幅降低效率。下面提供两种更高效的实现路径:
方法一:用ListChunkedBuilder直接构建(通用高效)
利用Polars的ListChunkedBuilder低阶API,直接写入行数据的切片,避免中间Series的创建,同时减少不必要的内存拷贝。
use ndarray::prelude::*; use polars::prelude::*; use polars::chunked_array::builder::ListChunkedBuilder; fn array2_to_list_series(array: Array2<f64>) -> PolarsResult<Series> { let n_rows = array.nrows(); let row_len = array.ncols(); // 初始化ListChunked构建器,预分配总数据量的内存 let mut builder = ListChunkedBuilder::new("", n_rows, row_len * n_rows); // 遍历每一行,直接写入原始数据切片 for row in array.axis_iter(Axis(0)) { // 若ndarray行是连续内存布局,as_slice()可直接获取原始数据,无需to_vec()拷贝 builder.append_slice(row.as_slice().unwrap())?; } Ok(builder.finish().into_series()) } fn main() -> PolarsResult<()> { let array: Array2<f64> = array![[1., 2.], [3., 4.], [5., 6.]]; let series = array2_to_list_series(array)?; println!("{}", series); Ok(()) }
方法二:基于连续内存的批量构建(最优性能)
如果你的ndarray是连续内存布局(比如C/F顺序的标准布局),可以一次性将整个数组展平,再通过偏移量构建ListArray,完全避免逐行处理的开销。
use ndarray::prelude::*; use polars::prelude::*; use polars::array::ListArray; fn array2_to_list_series_contiguous(array: Array2<f64>) -> PolarsResult<Series> { // 确保数组为标准连续布局(非连续时自动转换) let contiguous_array = array.as_standard_layout(); let raw_data = contiguous_array.as_slice().unwrap(); let n_rows = contiguous_array.nrows(); let row_len = contiguous_array.ncols(); // 批量创建基础Float64ChunkedArray let values = Float64Chunked::new("", raw_data.to_vec()); // 计算每个列表的起始偏移量和固定长度 let offsets = (0..=n_rows).map(|i| (i * row_len) as i64).collect::<Vec<_>>(); let lengths = vec![row_len as i64; n_rows]; // 直接构建ListArray let list_array = ListArray::new( DataType::List(Box::new(DataType::Float64)), offsets.into(), values.into(), None, ); Ok(list_array.into_series()) } fn main() -> PolarsResult<()> { let array: Array2<f64> = array![[1., 2.], [3., 4.], [5., 6.]]; let series = array2_to_list_series_contiguous(array)?; println!("{}", series); Ok(()) }
内容的提问来源于stack exchange,提问作者Azmy Rajab
相关产品推荐
相关产品推荐

