```
// src/data_deal.rs
use polars::prelude::*;
use std::path::Path;
use chrono::prelude::*;
use std::collections::HashMap;
/// 数据处理结构体,封装常用的 Polars 操作
pub struct DataDeal {
df: Option<DataFrame>,
lazy_df: Option<LazyFrame>,
}
impl DataDeal {
/// 创建新的空 DataDeal 实例
pub fn new() -> Self {
Self {
df: None,
lazy_df: None,
}
}
/// 从 DataFrame 创建实例
pub fn from_dataframe(df: DataFrame) -> Self {
Self {
df: Some(df),
lazy_df: None,
}
}
/// 从惰性 DataFrame 创建实例
pub fn from_lazyframe(lazy_df: LazyFrame) -> Self {
Self {
df: None,
lazy_df: Some(lazy_df),
}
}
// ==================== 数据创建方法 ====================
/// 创建示例 DataFrame
pub fn create_sample_data(&mut self) -> PolarsResult<&mut Self> {
self.df = Some(df! [
"id" => [1, 2, 3, 4, 5],
"name" => ["Alice", "Bob", "Charlie", "David", "Eve"],
"age" => [25, 30, 35, 40, 28],
"department" => ["IT", "HR", "IT", "Finance", "HR"],
"salary" => [50000.0, 45000.0, 60000.0, 55000.0, 48000.0],
"join_date" => [
NaiveDate::from_ymd_opt(2020, 1, 15).unwrap(),
NaiveDate::from_ymd_opt(2019, 3, 20).unwrap(),
NaiveDate::from_ymd_opt(2021, 6, 10).unwrap(),
NaiveDate::from_ymd_opt(2018, 11, 5).unwrap(),
NaiveDate::from_ymd_opt(2022, 2, 28).unwrap(),
],
]?);
Ok(self)
}
/// 从 Vec 创建 DataFrame
pub fn create_from_vectors(
&mut self,
columns: HashMap<&str, Vec<Series>>,
) -> PolarsResult<&mut Self> {
let mut series_vec = Vec::new();
for (name, series) in columns {
for s in series {
series_vec.push((name, s));
}
}
self.df = Some(DataFrame::new(series_vec)?);
Ok(self)
}
// ==================== 数据读取方法 ====================
/// 读取 CSV 文件
pub fn read_csv<P: AsRef<Path>>(&mut self, path: P) -> PolarsResult<&mut Self> {
self.df = Some(LazyFrame::scan_csv(path, Default::default())?.collect()?);
Ok(self)
}
/// 惰性读取 CSV 文件
pub fn read_csv_lazy<P: AsRef<Path>>(&mut self, path: P) -> PolarsResult<&mut Self> {
self.lazy_df = Some(LazyFrame::scan_csv(path, Default::default())?);
Ok(self)
}
/// 读取 Parquet 文件
pub fn read_parquet<P: AsRef<Path>>(&mut self, path: P) -> PolarsResult<&mut Self> {
self.df = Some(LazyFrame::scan_parquet(path, Default::default())?.collect()?);
Ok(self)
}
// ==================== 数据写入方法 ====================
/// 写入 CSV 文件
pub fn write_csv<P: AsRef<Path>>(&self, path: P) -> PolarsResult<()> {
if let Some(ref df) = self.df {
let mut file = std::fs::File::create(path)?;
CsvWriter::new(&mut file).finish(df)?;
} else if let Some(ref lazy_df) = self.lazy_df {
let df = lazy_df.clone().collect()?;
let mut file = std::fs::File::create(path)?;
CsvWriter::new(&mut file).finish(&df)?;
}
Ok(())
}
/// 写入 Parquet 文件
pub fn write_parquet<P: AsRef<Path>>(&self, path: P) -> PolarsResult<()> {
if let Some(ref df) = self.df {
let mut file = std::fs::File::create(path)?;
ParquetWriter::new(&mut file).finish(df)?;
} else if let Some(ref lazy_df) = self.lazy_df {
let df = lazy_df.clone().collect()?;
let mut file = std::fs::File::create(path)?;
ParquetWriter::new(&mut file).finish(&df)?;
}
Ok(())
}
// ==================== 数据筛选和选择方法 ====================
/// 筛选行
pub fn filter(&mut self, condition: Expr) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
self.lazy_df = Some(lazy_df.clone().filter(condition));
}
Ok(self)
}
/// 选择列
pub fn select(&mut self, columns: Vec<Expr>) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
self.lazy_df = Some(lazy_df.clone().select(&columns));
}
Ok(self)
}
/// 选择列名
pub fn select_columns(&mut self, column_names: Vec<&str>) -> PolarsResult<&mut Self> {
let exprs: Vec<Expr> = column_names.into_iter().map(|name| col(name)).collect();
self.select(exprs)
}
// ==================== 数据转换方法 ====================
/// 添加新列
pub fn with_columns(&mut self, exprs: Vec<Expr>) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
self.lazy_df = Some(lazy_df.clone().with_columns(&exprs));
}
Ok(self)
}
/// 重命名列
pub fn rename_columns(&mut self, renames: HashMap<&str, &str>) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
let mut current_lazy = lazy_df.clone();
for (old_name, new_name) in renames {
current_lazy = current_lazy.rename(&[old_name], &[new_name]);
}
self.lazy_df = Some(current_lazy);
}
Ok(self)
}
/// 删除列
pub fn drop_columns(&mut self, columns: Vec<&str>) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
self.lazy_df = Some(lazy_df.clone().drop_columns(columns));
}
Ok(self)
}
// ==================== 聚合方法 ====================
/// 分组聚合
pub fn group_by_agg(
&mut self,
group_columns: Vec<&str>,
agg_exprs: Vec<Expr>,
) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
let group_cols: Vec<Expr> = group_columns.into_iter().map(|col| col(col)).collect();
self.lazy_df = Some(lazy_df.clone().group_by(&group_cols).agg(&agg_exprs));
}
Ok(self)
}
/// 按部门统计薪资
pub fn department_stats(&mut self) -> PolarsResult<&mut Self> {
let agg_exprs = vec![
col("salary").mean().alias("avg_salary"),
col("salary").count().alias("employee_count"),
col("salary").min().alias("min_salary"),
col("salary").max().alias("max_salary"),
col("age").mean().alias("avg_age"),
];
self.group_by_agg(vec!["department"], agg_exprs)
}
// ==================== 排序和去重方法 ====================
/// 排序
pub fn sort(&mut self, by: &str, descending: bool) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
let options = SortOptions {
descending,
..Default::default()
};
self.lazy_df = Some(lazy_df.clone().sort(by, options));
}
Ok(self)
}
/// 多列排序
pub fn sort_by_multiple(
&mut self,
sort_specs: Vec<(&str, bool)>,
) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
let mut current_lazy = lazy_df.clone();
for (column, descending) in sort_specs {
let options = SortOptions {
descending,
..Default::default()
};
current_lazy = current_lazy.sort(column, options);
}
self.lazy_df = Some(current_lazy);
}
Ok(self)
}
/// 去重
pub fn distinct(&mut self, columns: Option<Vec<String>>) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
self.lazy_df = Some(
lazy_df
.clone()
.unique(columns, UniqueKeepStrategy::First),
);
}
Ok(self)
}
// ==================== 字符串操作方法 ====================
/// 字符串处理
pub fn process_strings(&mut self) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
self.lazy_df = Some(lazy_df.clone().with_columns(&[
col("name").str().to_uppercase().alias("name_upper"),
col("name").str().to_lowercase().alias("name_lower"),
col("name").str().lengths().alias("name_length"),
col("department")
.str()
.contains(lit("IT"), false)
.alias("is_it_department"),
]));
}
Ok(self)
}
// ==================== 时间序列方法 ====================
/// 时间序列处理
pub fn process_datetime(&mut self) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
self.lazy_df = Some(lazy_df.clone().with_columns(&[
col("join_date").dt().year().alias("join_year"),
col("join_date").dt().month().alias("join_month"),
col("join_date").dt().day().alias("join_day"),
// 计算工作年限(假设当前日期)
(lit(2024) - col("join_date").dt().year()).alias("years_of_service"),
]));
}
Ok(self)
}
/// 计算移动平均
pub fn moving_average(&mut self, column: &str, window_size: usize) -> PolarsResult<&mut Self> {
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
let ma_expr = col(column).rolling_mean(RollingOptions {
window_size,
min_periods: 1,
..Default::default()
});
let alias = format!("{}_ma_{}", column, window_size);
self.lazy_df = Some(lazy_df.clone().with_columns(&[ma_expr.alias(alias)]));
}
Ok(self)
}
// ==================== 连接操作方法 ====================
/// 创建部门信息表用于连接演示
pub fn create_department_table(&self) -> PolarsResult<DataFrame> {
let departments = df! [
"department" => ["IT", "HR", "Finance", "Marketing"],
"manager" => ["John Doe", "Jane Smith", "Mike Johnson", "Sarah Wilson"],
"budget" => [1000000.0, 500000.0, 800000.0, 600000.0],
]?;
Ok(departments)
}
/// 连接操作
pub fn join_with_departments(&mut self) -> PolarsResult<&mut Self> {
let departments = self.create_department_table()?;
self.to_lazy();
if let Some(ref lazy_df) = self.lazy_df {
let departments_lazy = departments.lazy();
self.lazy_df = Some(lazy_df.clone().join(
departments_lazy,
[col("department")],
[col("department")],
JoinArgs::new(JoinType::Left),
));
}
Ok(self)
}
// ==================== 数据统计方法 ====================
/// 获取数据统计信息
pub fn describe(&self) -> PolarsResult<DataFrame> {
if let Some(ref df) = self.df {
df.describe(None)
} else if let Some(ref lazy_df) = self.lazy_df {
lazy_df.clone().describe().collect()
} else {
Err(PolarsError::NoData("No data available".into()))
}
}
/// 获取数值列的相关性矩阵
pub fn correlation(&self) -> PolarsResult<DataFrame> {
if let Some(ref df) = self.df {
let numeric_df = df
.clone()
.lazy()
.select([col("*").exclude([DataType::Utf8, DataType::Categorical, DataType::Boolean])])
.collect()?;
numeric_df.corr(2, None)
} else {
Err(PolarsError::NoData("No data available".into()))
}
}
// ==================== 数据信息方法 ====================
/// 显示数据概览
pub fn show_info(&self) -> PolarsResult<()> {
if let Some(ref df) = self.df {
println!("DataFrame 形状: {} 行 × {} 列", df.height(), df.width());
println!("列信息:");
for (i, name) in df.get_column_names().iter().enumerate() {
let dtype = df.column(name)?.dtype();
println!(" {}: {} ({:?})", i, name, dtype);
}
println!("\n前5行数据:");
println!("{}", df.head(Some(5)));
} else if let Some(ref lazy_df) = self.lazy_df {
println!("这是一个 LazyFrame,需要 collect() 后查看数据");
let plan = lazy_df.clone().describe_plan();
println!("执行计划:\n{}", plan);
} else {
println!("没有数据");
}
Ok(())
}
// ==================== 转换方法 ====================
/// 转换为惰性 DataFrame
pub fn to_lazy(&mut self) -> &mut Self {
if self.lazy_df.is_none() {
if let Some(ref df) = self.df {
self.lazy_df = Some(df.lazy());
}
}
self
}
/// 执行计算并获取 DataFrame
pub fn collect(&mut self) -> PolarsResult<&mut Self> {
if let Some(ref lazy_df) = self.lazy_df {
self.df = Some(lazy_df.clone().collect()?);
self.lazy_df = None;
}
Ok(self)
}
/// 获取最终的 DataFrame
pub fn get_dataframe(&self) -> Option<&DataFrame> {
self.df.as_ref()
}
/// 获取最终的 LazyFrame
pub fn get_lazyframe(&self) -> Option<&LazyFrame> {
self.lazy_df.as_ref()
}
/// 克隆当前数据
pub fn clone_data(&self) -> PolarsResult<Self> {
if let Some(ref df) = self.df {
Ok(Self::from_dataframe(df.clone()))
} else if let Some(ref lazy_df) = self.lazy_df {
Ok(Self::from_lazyframe(lazy_df.clone()))
} else {
Err(PolarsError::NoData("No data to clone".into()))
}
}
}
impl Default for DataDeal {
fn default() -> Self {
Self::new()
}
}
// ==================== 使用示例 ====================
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_basic_operations() -> PolarsResult<()> {
let mut data_deal = DataDeal::new();
// 创建示例数据
data_deal.create_sample_data()?
.show_info()?;
// 数据处理管道
data_deal
.process_strings()?
.process_datetime()?
.filter(col("age").gt(lit(30)))?
.sort("salary", true)?
.collect()?;
println!("处理后的数据:");
if let Some(df) = data_deal.get_dataframe() {
println!("{}", df);
}
// 部门统计
let mut stats = data_deal.clone_data()?;
stats.department_stats()?.collect()?;
println!("部门统计:");
if let Some(df) = stats.get_dataframe() {
println!("{}", df);
}
Ok(())
}
#[test]
fn test_advanced_operations() -> PolarsResult<()> {
let mut data_deal = DataDeal::new();
data_deal.create_sample_data()?
.join_with_departments()?
.moving_average("salary", 2)?
.collect()?;
println!("高级操作结果:");
data_deal.show_info()?;
// 相关性分析
if let Some(df) = data_deal.get_dataframe() {
let correlation = data_deal.correlation()?;
println!("相关性矩阵:\n{}", correlation);
}
Ok(())
}
}
```
|
|
|
|
|
|
|
|
```
let s1 = Series::new("Name".into(), &["Alice", "Bob", "Charlie"]);
let s2 = Series::new("Age".into(), &[25, 30, 35]);
let s3 = Series::new("City".into(), &["NYC", "LA", "Chicago"]);
// 从 Series 构建 DataFrame
let df = DataFrame::new(vec![
Column::new("Name".into(), s1),
Column::new("Age".into(), s2),
Column::new("City".into(), s3)
])?;
println!("DataFrame:\n{}", df);
let name = df.column("Name")?;
println!("Name column:\n{:?}", name);
```
```
DataFrame:
shape: (3, 3)
┌─────────┬─────┬─────────┐
│ Name ┆ Age ┆ City │
│ --- ┆ --- ┆ --- │
│ str ┆ i32 ┆ str │
╞═════════╪═════╪═════════╡
│ Alice ┆ 25 ┆ NYC │
│ Bob ┆ 30 ┆ LA │
│ Charlie ┆ 35 ┆ Chicago │
└─────────┴─────┴─────────┘
Name column:
Series(SeriesColumn { inner: shape: (3,)
Series: 'Name' [str]
[
"Alice"
"Bob"
"Charlie"
], materialized_at: None })
```
|
```
pub fn test_crt1() -> Result<(), Box<dyn std::error::Error>> {
// 使用宏创建 (更简洁)
let df2 = df!("Name" => ["Alice", "Bob", "Charlie"],
"Age" => [25, 30, 35],
"City" => ["NYC", "LA", "Chicago"])?;
println!("\nUsing df! macro:\n{}", df2);
Ok(())
}
```
```
Using df! macro:
shape: (3, 3)
┌─────────┬─────┬─────────┐
│ Name ┆ Age ┆ City │
│ --- ┆ --- ┆ --- │
│ str ┆ i32 ┆ str │
╞═════════╪═════╪═════════╡
│ Alice ┆ 25 ┆ NYC │
│ Bob ┆ 30 ┆ LA │
│ Charlie ┆ 35 ┆ Chicago │
└─────────┴─────┴─────────┘
```
|
|
|
|
|
|
|
|
DataType来自于Polars依赖包,通过use polars::prelude::*;导入。 Polars中可用的主要数据类型包括:
- DataType::Null - 空值类型
- DataType::Boolean - 布尔值类型
- DataType::UInt8 - 8位无符号整数
- DataType::UInt16 - 16位无符号整数
- DataType::UInt32 - 32位无符号整数
- DataType::UInt64 - 64位无符号整数
- DataType::Int8 - 8位有符号整数
- DataType::Int16 - 16位有符号整数
- DataType::Int32 - 32位有符号整数
- DataType::Int64 - 64位有符号整数
- DataType::Float32 - 32位浮点数
- DataType::Float64 - 64位浮点数
|
- DataType::String - 字符串类型
- DataType::Binary - 二进制数据类型
|
- DataType::Date - 日期类型(天) - DataType::Datetime(TimeUnit, Option<String>) - 日期时间类型 - TimeUnit: Nanoseconds, Microseconds, Milliseconds - Option<String>: 时区(可选) - DataType::Time - 时间类型 - DataType::Duration(TimeUnit) - 时间段类型 |
|
复合类型 DataType::List(Box<DataType>) - 列表类型 DataType::Struct(Vec<Field>) - 结构体类型 DataType::Object(String) - 对象类型 特殊类型 DataType::Categorical - 分类类型(优化存储的字符串) DataType::Unknown - 未知类型 |
|
|
```
// 创建数据
let s1 = Series::new("Name".into(), &["Alice", "Bob", "Charlie"]);
let s2 = Series::new("Age".into(), &[25, 30, 35]);
let s3 = Series::new("City".into(), &["NYC", "LA", "Chicago"]);
```
0.51版Series要求列类型为PlSmallStr
- The Series::new function expects a PlSmallStr for the name parameter instead of a &str.
- .into() 方法将字符串字面量转换为 PlSmallStr 类型。
PlSmallStr 相比 &str 有以下几个主要优势
```
1. 内存效率
PlSmallStr 使用小字符串优化(Small String Optimization)
对于短字符串(通常是 23 字节以下),数据直接存储在栈上,避免堆分配
&str 只是字符串引用,不能拥有数据
2. 所有权语义
PlSmallStr 拥有字符串数据,可以自由移动和修改
&str 只是借用,生命周期受限,不能独立存在
3. 性能优化
避免了频繁的堆分配和释放
减少了内存碎片
缓存友好性更好
4. 适合 DataFrame 列名
在 Polars 中,列名通常是短字符串且频繁使用:
// 更高效
let s1 = Series::new("Name".into(), &["Alice", "Bob"]);
// vs 传统方式需要额外的字符串管理
let name: String = "Name".to_string();
let s1 = Series::new(name.into(), &["Alice", "Bob"]);
5. 零拷贝转换
支持从多种字符串类型零拷贝或低成本转换:
"Name".into() // &str -> PlSmallStr
String::from("Name").into() // String -> PlSmallStr
这就是为什么 Polars 在内部广泛使用 PlSmallStr 来标识列名和其他元数据。
```
|
|
lit 是 Polars lazy API 中的基础函数,用于在表达式中嵌入常量值。
```
lit 是 Polars 中的一个函数,用于创建字面量表达式(Literal Expression)。
lit 的作用:
将值转换为表达式:将普通的 Rust 值(如数字、字符串等)转换为 Polars 可以处理的 Expr 类型
在表达式中使用常量:在复杂的表达式操作中用作常量值
在你的代码中:
let filtered = df.clone().lazy()
.filter(col("Age").gt(lit(28))) // lit(28) 将数字28转换为表达式
.collect()?;
这里 lit(28) 将数字 28 转换为 Polars 表达式,然后才能与 col("Age") 进行 gt(大于)比较。
```
```
其他常见用法:
// 数字字面量
lit(100)
lit(3.14)
// 字符串字面量
lit("hello")
// 布尔字面量
lit(true)
lit(false)
// 日期字面量
lit(datetime(2023, 1, 1))
// 在计算中使用
df.with_column((col("price") * lit(1.1)).alias("price_with_tax"))
```
|
```
#[allow(dead_code)]
pub fn test_select() -> Result<(), Box<dyn std::error::Error>> {
let df = df!("Name" => ["Alice", "Bob", "Charlie", "Diana"],
"Age" => [25, 30, 35, 28],
"City" => ["NYC", "LA", "Chicago", "NYC"])?;
// 选择列
let selected = df.select(vec!["Name", "Age"])?;
println!("Selected columns:\n{}", selected);
// 过滤行 (年龄 > 28)
let filtered = df.clone().lazy()
.filter(col("Age").gt(lit(28)))
.collect()?;
println!("\nFiltered (Age > 28):\n{}", filtered);
// 排序 (按年龄降序)
let sorted = df.sort(
vec!["Age"],
SortMultipleOptions::new().with_order_descending(true)
)?;
println!("\nSorted by Age (desc):\n{}", sorted);
Ok(())
}
```
``` Selected columns: shape: (4, 2) ┌─────────┬─────┐ │ Name ┆ Age │ │ --- ┆ --- │ │ str ┆ i32 │ ╞═════════╪═════╡ │ Alice ┆ 25 │ │ Bob ┆ 30 │ │ Charlie ┆ 35 │ │ Diana ┆ 28 │ └─────────┴─────┘ Filtered (Age > 28): shape: (2, 3) ┌─────────┬─────┬─────────┐ │ Name ┆ Age ┆ City │ │ --- ┆ --- ┆ --- │ │ str ┆ i32 ┆ str │ ╞═════════╪═════╪═════════╡ │ Bob ┆ 30 ┆ LA │ │ Charlie ┆ 35 ┆ Chicago │ └─────────┴─────┴─────────┘ Sorted by Age (desc): shape: (4, 3) ┌─────────┬─────┬─────────┐ │ Name ┆ Age ┆ City │ │ --- ┆ --- ┆ --- │ │ str ┆ i32 ┆ str │ ╞═════════╪═════╪═════════╡ │ Charlie ┆ 35 ┆ Chicago │ │ Bob ┆ 30 ┆ LA │ │ Diana ┆ 28 ┆ NYC │ │ Alice ┆ 25 ┆ NYC │ └─────────┴─────┴─────────┘ ``` |
|
with_column 方法的基本用法 ``` 1. 方法签名 fn with_column<C: IntoColumn>(&mut self, column: C) -> PolarsResult<&mut Self> 2. 主要功能 替换现有列: 用新的列数据替换同名的现有列 添加新列: 如果列名不存在,则添加新列 修改数据类型: 如我们在 data_type_change 中所做的 ```
```
3. 常见用法示例
a 修改现有列的数据类型
// 将某列转换为Float64类型
let casted_column = df.column("Amount")?.cast(&DataType::Float64)?;
df.with_column(casted_column)?;
b 基于现有列创建新列
use polars::prelude::*;
// 创建一个新的计算列
df.with_column(
(col("price") * col("quantity")).alias("total_amount")
)?;
c 使用函数转换列
// 对列应用函数
df.with_column(
col("name").str().to_uppercase().alias("upper_name")
)?;
```
``` 4. 在我们的实现中的应用 在 data_type_change 方法中,with_column 用于: // 1. 获取列 let column = df.column(col_name)?; // 2. 转换数据类型 let casted_column = column.cast(&DataType::Float64)?; // 3. 使用with_column替换原列 df_result.with_column(casted_column)?; ```
```
5. 注意事项
返回值: with_column 返回 &mut DataFrame,所以支持链式调用
列名: 新列会替换同名旧列
所有权: 需要确保 DataFrame 是可变的
6. 其他相关方法
除了 with_column,Polars 还提供了其他列操作方法:
// 添加新列而不替换
df.with_column(
lit(0).alias("new_column") // 添加常量列
)?;
// 选择列
df.select(["col1", "col2"])?;
// 删除列
df.drop(["col_to_drop"])?;
所以是的,with_column 是操作 DataFrame 列的核心方法,可以用于数据类型转换、计算新值、应用函数等各种列操作。
```
|
```
// 验证目标列是否存在
let existing_columns: HashSet<&str> = df.get_column_names().iter()
.map(|name| name.as_str())
.collect();
let valid_conversions: Vec<(String, DataType)> = type_conversions.into_iter()
.filter(|(col_name, _)| existing_columns.contains(col_name.as_str()))
.collect();
```
df.get_column_names().iter() 返回的类型
```
let file_path = "/ai/data/tmp/df_tra.csv";
let data_processor = Dtl::new();
let df = Dtl::read_csv(file_path).unwrap();
let column_names = df.get_column_names().to_vec();
let df_iter = column_names.iter();
// 遍历列名并打印column_name的类型
println!("遍历column_name的类型:");
for column_name in df_iter {
// 使用TypeId来获取类型信息
let type_id = std::any::TypeId::of::<&String>();
let actual_type_id = std::any::type_name_of_val(column_name);
println!("列名: {:<20} | column_name值: {:<15} | 实际类型: {}",
column_name, column_name, actual_type_id);
}
println!("--------------------------------------");
```
值得注意的是column_name被使用了两次,这就是引用的好处 ``` ------------------------ 遍历column_name的类型: 列名: From | column_name值: From | 实际类型: &polars_utils::pl_str::PlSmallStr 列名: To | column_name值: To | 实际类型: &polars_utils::pl_str::PlSmallStr 列名: Amount | column_name值: Amount | 实际类型: &polars_utils::pl_str::PlSmallStr 列名: Currency | column_name值: Currency | 实际类型: &polars_utils::pl_str::PlSmallStr 列名: Payment Format | column_name值: Payment Format | 实际类型: &polars_utils::pl_str::PlSmallStr 列名: time8 | column_name值: time8 | 实际类型: &polars_utils::pl_str::PlSmallStr 列名: time14 | column_name值: time14 | 实际类型: &polars_utils::pl_str::PlSmallStr -------------------------------------- ``` |
```
#[allow(dead_code)]
pub fn test_agg() -> Result<(), Box<dyn std::error::Error>> {
let df = df!("City" => ["NYC", "LA", "Chicago", "NYC", "LA"],
"Age" => [25, 30, 35, 28, 32],
"Salary" => [50000, 60000, 70000, 55000, 65000])?;
// 按城市分组,计算年龄和薪水的平均值
let grouped = df
.lazy()
.group_by([col("City")])
.agg([
col("Age").mean().alias("avg_age"),
col("Salary").mean().alias("avg_salary"),
])
.collect()?;
println!("Grouped by City:\n{}", grouped);
Ok(())
}
```
|
|
|
|
|
|
|
|