从 Vec 创建 Polars 数据框<Struct>

问题描述 投票:0回答:3

假设我有一个像这样的结构向量:


struct Test {
    id:u32,
    amount:u32
 }
 
 fn main() {
    let test_vec:Vec<Test> = vec![Test{id:1,amount:3}, Test{id:3,amount:4}];
 }

有没有办法将其放入极坐标数据框中,其中列名称为结构字段?

希望得到如下输出:

   id  amount
0   1       3
1   3       4
dataframe rust struct rust-polars
3个回答
6
投票

经过一番苦思冥想,我找到了以下解决方案。

如果您有自定义结构的向量,要将其放入 Polars 数据框中,您可以执行以下操作:

// 1. Derive serde::Serialize for your struct

#[derive(Serialize)]
struct Test {
    id:u32,
    amount:u32
}

// (Adding new method here for quality of life).

impl Test {
    fn new(id:u32, amount:u32) -> Self{
        Test{id,amount}
    }
}


// 2. Jsonify your struct Vec
let test_vec:Vec<Test> = vec![Test::new(1,3), Test::new(3,4)];
let json = serde_json::to_string(&test_vec).unwrap();

// 3. Create cursor from json 
let cursor = Cursor::new(json);

// 4. Create polars DataFrame from reading cursor as json
let df = JsonReader::new(cursor)
            .finish()
            .unwrap();
    

5
投票

出于几个原因,我不喜欢接受的答案

  1. 它是类型不安全的,事实上,如果您转换例如
    chrono::NaiveDate
    字段,您就会丢失类型信息 - 它将作为
    str
    返回到您的
    DataFrame
    中。
  2. 效率低下,因为您需要序列化和反序列化数据。

我认为更好的解决方案是宏:

macro_rules! struct_to_dataframe {
    ($input:expr, [$($field:ident),+]) => {
        {
            // Extract the field values into separate vectors
            $(let mut $field = Vec::new();)*

            for e in $input.into_iter() {
                $($field.push(e.$field);)*
            }
            df! {
                $(stringify!($field) => $field,)*
            }
        }
    };
}

你应该可以这样称呼它:

struct Test {
    id:u32,
    amount:u32
}

impl Test {
    fn new(id:u32, amount:u32) -> Self{
        Test{id,amount}
    }
}
let test_vec:Vec<Test> = vec![Test::new(1,3), Test::new(3,4)];
let df = struct_to_dataframe!(test_vec, [id, amount]).unwrap();

0
投票

让测试给出:

struct Test {
   id: u32, 
   amount: u32, 
   field3: String, 
   field4: Option<f64>,
}

impl Test {
    fn new(id:u32, amount:u32, field3: String, field4: Option<f64>) -> Self {
        Test { id, amount, field3, field4 }
    }
}

let test_vec:Vec<Test> = vec![
    Test::new(1, 3, "foo".to_string, Some(6.43)), 
    Test::new(3, 4, "bar".to_string, Some(8.0)), 
];

是否可以通过结构名称显式更改字段

[id, amount, field3, field4]

即通过Test改变

[id, amount, field3, field4]

let df = struct_to_dataframe!(test_vec, Test).unwrap(); 

这些改变之后

struct_to_dataframe
会是什么样子?

© www.soinside.com 2019 - 2024. All rights reserved.