Rust:使用结构向量的 polars 中的 DataFrame
Rust: DataFrame in polars using a vector of structs
问题
我想从 mysql
数据库中将数据读入 polars
数据框。我正在使用 sqlx
.
sqlx
生成结构向量 例如:Vec<Country>
下面:
来自 sqlx
Docs:
// no traits are needed
struct Country { country: String, count: i64 }
let countries = sqlx::query_as!(Country,
"
SELECT country, COUNT(*) as count
FROM users
GROUP BY country
WHERE organization = ?
",
organization
)
.fetch_all(&pool) // -> Vec<Country>
.await?;
// countries[0].country
// countries[0].count
我如何使用此 Vec<Country>
生成极坐标数据帧
来自 polars
Docs:
use polars_core::prelude::*;
let s0 = Series::new("a", &[1i64, 2, 3]);
let s1 = Series::new("b", &[1i64, 1, 1]);
let s2 = Series::new("c", &[2i64, 2, 2]);
let list = Series::new("foo", &[s0, s1, s2]);
let s0 = Series::new("B", [1, 2, 3]);
let s1 = Series::new("C", [1, 1, 1]);
let df = DataFrame::new(vec![list, s0, s1]).unwrap();
可能的解决方案
我能想到的唯一解决方案是,如果我可以为 Country
结构内的每个 column/Data 创建一个系列,并使用这些单独的系列创建数据框。
我不知道如何将 Vec<Country>
分解为 Vec<country>
和 Vec<count>
我不知道这些 DataFrame
或 Series
的结构,但是如果你想拆分一个结构向量,你可以编写一个小的 reducer 来迭代向量的内容并将它们推入多个新向量。
简化的 playground 片段:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f698866751214fc3f44c348b7c4f80c5
struct A(u8, i8);
fn main() {
let v = vec![A(1, 4), A(2, 6), A(3, 5)];
let result = v.into_iter()
.fold((vec![], vec![]), |(mut u, mut i), item| {
u.push(item.0);
i.push(item.1);
(u, i)
});
dbg!(result);
// `result` is just a tuple of vectors
// let (unsigneds, signeds): (Vec<u8>, Vec<i8>) = result;
}
你基本上采用结构向量,迭代它们并将它们一个接一个地折叠到提供的新(空)向量中。最后,返回结果(2 个向量的元组)。你现在可以用这些做你想做的事了。
您可以为此使用构建器或从迭代器中收集。从迭代器收集通常很快,但在这种情况下,它需要您循环 Vec<Country>
两次,因此您应该进行基准测试。
下面是显示的两种解决方案的示例函数。
use polars::prelude::*;
struct Country {
country: String,
count: i64,
}
fn example_1(values: &[Country]) -> (Series, Series) {
let ca_country: Utf8Chunked = values.iter().map(|v| &*v.country).collect();
let ca_count: NoNull<Int64Chunked> = values.iter().map(|v| v.count).collect();
let mut s_country: Series = ca_country.into();
let mut s_count: Series = ca_count.into_inner().into();
s_country.rename("country");
s_count.rename("country");
(s_count, s_country)
}
fn example_2(values: &[Country]) -> (Series, Series) {
let mut country_builder = Utf8ChunkedBuilder::new("country", values.len(), values.len() * 5);
let mut count_builder = PrimitiveChunkedBuilder::<Int64Type>::new("count", values.len());
values.iter().for_each(|v| {
country_builder.append_value(&v.country);
count_builder.append_value(v.count)
});
(
count_builder.finish().into(),
country_builder.finish().into(),
)
}
顺便说一句,如果你想要最高性能,我真的推荐 connector-x。它集成了极线和箭头,性能非常出色。
问题
我想从 mysql
数据库中将数据读入 polars
数据框。我正在使用 sqlx
.
sqlx
生成结构向量 例如:Vec<Country>
下面:
来自 sqlx
Docs:
// no traits are needed
struct Country { country: String, count: i64 }
let countries = sqlx::query_as!(Country,
"
SELECT country, COUNT(*) as count
FROM users
GROUP BY country
WHERE organization = ?
",
organization
)
.fetch_all(&pool) // -> Vec<Country>
.await?;
// countries[0].country
// countries[0].count
我如何使用此 Vec<Country>
生成极坐标数据帧
来自 polars
Docs:
use polars_core::prelude::*;
let s0 = Series::new("a", &[1i64, 2, 3]);
let s1 = Series::new("b", &[1i64, 1, 1]);
let s2 = Series::new("c", &[2i64, 2, 2]);
let list = Series::new("foo", &[s0, s1, s2]);
let s0 = Series::new("B", [1, 2, 3]);
let s1 = Series::new("C", [1, 1, 1]);
let df = DataFrame::new(vec![list, s0, s1]).unwrap();
可能的解决方案
我能想到的唯一解决方案是,如果我可以为 Country
结构内的每个 column/Data 创建一个系列,并使用这些单独的系列创建数据框。
我不知道如何将 Vec<Country>
分解为 Vec<country>
和 Vec<count>
我不知道这些 DataFrame
或 Series
的结构,但是如果你想拆分一个结构向量,你可以编写一个小的 reducer 来迭代向量的内容并将它们推入多个新向量。
简化的 playground 片段: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f698866751214fc3f44c348b7c4f80c5
struct A(u8, i8);
fn main() {
let v = vec![A(1, 4), A(2, 6), A(3, 5)];
let result = v.into_iter()
.fold((vec![], vec![]), |(mut u, mut i), item| {
u.push(item.0);
i.push(item.1);
(u, i)
});
dbg!(result);
// `result` is just a tuple of vectors
// let (unsigneds, signeds): (Vec<u8>, Vec<i8>) = result;
}
你基本上采用结构向量,迭代它们并将它们一个接一个地折叠到提供的新(空)向量中。最后,返回结果(2 个向量的元组)。你现在可以用这些做你想做的事了。
您可以为此使用构建器或从迭代器中收集。从迭代器收集通常很快,但在这种情况下,它需要您循环 Vec<Country>
两次,因此您应该进行基准测试。
下面是显示的两种解决方案的示例函数。
use polars::prelude::*;
struct Country {
country: String,
count: i64,
}
fn example_1(values: &[Country]) -> (Series, Series) {
let ca_country: Utf8Chunked = values.iter().map(|v| &*v.country).collect();
let ca_count: NoNull<Int64Chunked> = values.iter().map(|v| v.count).collect();
let mut s_country: Series = ca_country.into();
let mut s_count: Series = ca_count.into_inner().into();
s_country.rename("country");
s_count.rename("country");
(s_count, s_country)
}
fn example_2(values: &[Country]) -> (Series, Series) {
let mut country_builder = Utf8ChunkedBuilder::new("country", values.len(), values.len() * 5);
let mut count_builder = PrimitiveChunkedBuilder::<Int64Type>::new("count", values.len());
values.iter().for_each(|v| {
country_builder.append_value(&v.country);
count_builder.append_value(v.count)
});
(
count_builder.finish().into(),
country_builder.finish().into(),
)
}
顺便说一句,如果你想要最高性能,我真的推荐 connector-x。它集成了极线和箭头,性能非常出色。