创建
series
#![allow(unused)] fn main() { // 从 Vec, 切片和数组, series 可以携带名称 let s = Series::new("from vec", vec![1, 2, 3]); let s = Series::new("from slice", &[true, false, true]); let s = Series::new("from array", ["rookie", "long", "lin"]); }
dataframe
空 dataframe
#![allow(unused)] fn main() { let df = DataFrame::default(); assert!(df.is_empty()); }
从多个 Vec<Series>
创建
#![allow(unused)] fn main() { let s1 = Series::new("Fruit", &["Apple", "Apple", "Pear"]); let s2 = Series::new("Color", &["Red", "Yellow", "Green"]); let df: Result<DataFrame> = DataFrame::new(vec![s1, s2]); }
使用 df!
宏, 注意, 返回类型为Result<DataFrame>
#![allow(unused)] fn main() { let df: Result<DataFrame> = df!("Fruit" => &["Apple", "Apple", "Pear"], "Color" => &["Red", "Yellow", "Green"]); }
查看数据
查看头和尾, 与 pandas 中同名函数类似, head, tail
#![allow(unused)] fn main() { let countries: DataFrame = df!( "Rank by GDP (2021)" => &[1, 2, 3, 4, 5], "Continent" => &["North America", "Asia", "Asia", "Europe", "Europe"], "Country" => &["United States", "China", "Japan", "Germany", "United Kingdom"], "Capital" => &["Washington", "Beijing", "Tokyo", "Berlin", "London"] )?; assert_eq!(countries.shape(), (5, 4)); println!("{}", countries.head(Some(3))); }
output
shape: (3, 4)
┌────────────────────┬───────────────┬───────────────┬────────────┐
│ Rank by GDP (2021) ┆ Continent ┆ Country ┆ Capital │
│ --- ┆ --- ┆ --- ┆ --- │
│ i32 ┆ str ┆ str ┆ str │
╞════════════════════╪═══════════════╪═══════════════╪════════════╡
│ 1 ┆ North America ┆ United States ┆ Washington │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 2 ┆ Asia ┆ China ┆ Beijing │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ Asia ┆ Japan ┆ Tokyo │
└────────────────────┴───────────────┴───────────────┴────────────┘
#![allow(unused)] fn main() { let countries: DataFrame = df!("Rank (2021)" => &[105, 106, 107, 108, 109], "Apple Price (€/kg)" => &[0.75, 0.70, 0.70, 0.65, 0.52], "Country" => &["Kosovo", "Moldova", "North Macedonia", "Syria", "Turkey"])?; assert_eq!(countries.shape(), (5, 3)); println!("{}", countries.tail(Some(2))); }
Output
shape: (2, 3)
┌─────────────┬────────────────────┬─────────┐
│ Rank (2021) ┆ Apple Price (€/kg) ┆ Country │
│ --- ┆ --- ┆ --- │
│ i32 ┆ f64 ┆ str │
╞═════════════╪════════════════════╪═════════╡
│ 108 ┆ 0.65 ┆ Syria │
├╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌┤
│ 109 ┆ 0.52 ┆ Turkey │
└─────────────┴────────────────────┴─────────┘
获取列名
#![allow(unused)] fn main() { let df: DataFrame = df!("Language" => &["Rust", "Python"], "Designer" => &["Graydon Hoare", "Guido van Rossum"])?; assert_eq!(df.get_column_names(), &["Language", "Designer"]); }
统计汇总方法
polars DataFrame 没有提供 describe 这样的快速统计方法, 但调用 mean, std 等方法也非常简单便捷
count
对于整个 DataFrame 可以调用 shape 获取 DataFrame 形状, 如果想获取某个列经操作变形后个数, 可以使用 count
#![allow(unused)] fn main() { let df1: DataFrame = df!("D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3])?; let df2 = df1 .lazy() .select(&[ col("D1").count().alias("total"), col("D1").filter(col("D1").gt(lit(3))).count().alias("D1 > 3"), ]) .collect() .unwrap(); println!("{}", df2); }
Output
shape: (1, 2)
┌───────┬────────┐
│ total ┆ D1 > 3 │
│ --- ┆ --- │
│ u32 ┆ u32 │
╞═══════╪════════╡
│ 5 ┆ 2 │
└───────┴────────┘
mean
DataFrame mean
Expr mean
如果要计算滑动平均等带时间窗口数据, 请查看 rolling_mean
其他方法
其他统计学方法名称与 pandas 中同名或类似
转置
transpose 可转置 DataFrame, 这个操作消耗大量性能
#![allow(unused)] fn main() { let df1: DataFrame = df!("D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3])?; println!("{}", df1.transpose()?); }
Output
shape: (2, 5)
┌──────────┬──────────┬──────────┬──────────┬──────────┐
│ column_0 ┆ column_1 ┆ column_2 ┆ column_3 ┆ column_4 │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ i32 ┆ i32 ┆ i32 ┆ i32 ┆ i32 │
╞══════════╪══════════╪══════════╪══════════╪══════════╡
│ 1 ┆ 3 ┆ 1 ┆ 5 ┆ 6 │
├╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌┤
│ 3 ┆ 2 ┆ 3 ┆ 5 ┆ 3 │
└──────────┴──────────┴──────────┴──────────┴──────────┘
排序
#![allow(unused)] fn main() { let df1: DataFrame = df!("D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3])?; println!("{}", df1.sort(["D1"], vec![true])?); }
Output
shape: (5, 2)
┌─────┬─────┐
│ D1 ┆ D2 │
│ --- ┆ --- │
│ i32 ┆ i32 │
╞═════╪═════╡
│ 6 ┆ 3 │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 5 ┆ 5 │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 3 ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 1 ┆ 3 │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 1 ┆ 3 │
└─────┴─────┘
查询&更新数据
获取一个或多个列
这些函数返回一个或多个 Series.
在 select context 里, 可以用col 构建一个列选择表达式, 接着对其进行操作.
polars DataFrame 实现了 Index trait, 所以你也可以通过以下方式获取列, 请注意, pandas 中这种方式拿到的是 slice.
#![allow(unused)] fn main() { let df1: DataFrame = df!("D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3])?; println!("{}", df1[1]); println!("{}", df1["D1"]); }
Output
shape: (5,)
Series: 'D2' [i32]
[
3
2
3
5
3
]
shape: (5,)
Series: 'D1' [i32]
[
1
3
1
5
6
]
获取切片
#![allow(unused)] fn main() { let df1: DataFrame = df!("D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3])?; println!("{}", df1.slice(2, 3)); }
如果要获取子区域, 可以使用 select + columns
#![allow(unused)] fn main() { let df1: DataFrame = df!( "D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3], "D3" => &[9, 7, 5, 2, 4] )?; let df2 = df1 .lazy() .select([cols(["D1", "D3"]).slice(2, 3)]) .collect()?; println!("{}", df2); }
Output
shape: (3, 2)
┌─────┬─────┐
│ D1 ┆ D3 │
│ --- ┆ --- │
│ i32 ┆ i32 │
╞═════╪═════╡
│ 1 ┆ 5 │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 5 ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┤
│ 6 ┆ 4 │
└─────┴─────┘
获取某个标量
#![allow(unused)] fn main() { let df1: DataFrame = df!( "D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3], "D3" => &[9, 7, 5, 2, 4] )?; println!("{}", df1["D1"].get(0)); }
Output
1
布尔索引
polars 中没有布尔索引, 但可以通过 filter 达到相同效果
#![allow(unused)] fn main() { let df1: DataFrame = df!( "D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3], "D3" => &[9, 7, 5, 2, 4] )?; let df2 = df1.lazy().filter(col("D1").gt(3)).collect()?; println!("{}", df2); }
Output
shape: (2, 3)
┌─────┬─────┬─────┐
│ D1 ┆ D2 ┆ D3 │
│ --- ┆ --- ┆ --- │
│ i32 ┆ i32 ┆ i32 │
╞═════╪═════╪═════╡
│ 5 ┆ 5 ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 6 ┆ 3 ┆ 4 │
└─────┴─────┴─────┘
添加新列
通过 lazy frame 的 with_column 可以方便地根据已有列添加新列
#![allow(unused)] fn main() { let df1: DataFrame = df!( "D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3], "D3" => &[9, 7, 5, 2, 4] )?; let df2 = df1 .lazy() .with_column( when(col("D1").gt(3)) .then(lit(true)) .otherwise(lit(false)) .alias("D1 > 3"), ) .collect()?; println!("{}", df2); }
Output
shape: (5, 4)
┌─────┬─────┬─────┬────────┐
│ D1 ┆ D2 ┆ D3 ┆ D1 > 3 │
│ --- ┆ --- ┆ --- ┆ --- │
│ i32 ┆ i32 ┆ i32 ┆ bool │
╞═════╪═════╪═════╪════════╡
│ 1 ┆ 3 ┆ 9 ┆ false │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ 3 ┆ 2 ┆ 7 ┆ false │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ 1 ┆ 3 ┆ 5 ┆ false │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ 5 ┆ 5 ┆ 2 ┆ true │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌╌╌╌┤
│ 6 ┆ 3 ┆ 4 ┆ true │
└─────┴─────┴─────┴────────┘
修改数据
DataFrame 可以通过 replace + set_at_idx 实现
#![allow(unused)] fn main() { let mut df1: DataFrame = df!( "D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3], "D3" => &[9, 7, 5, 2, 4] )?; let new_d1 = df1["D1"] .i32() .and_then(|s| s.set_at_idx(vec![0], Some(100)))?; let df2 = df1.replace("D1", new_d1)?; println!("{}", df2); }
Output
shape: (5, 3)
┌─────┬─────┬─────┐
│ D1 ┆ D2 ┆ D3 │
│ --- ┆ --- ┆ --- │
│ i32 ┆ i32 ┆ i32 │
╞═════╪═════╪═════╡
│ 100 ┆ 3 ┆ 9 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 3 ┆ 2 ┆ 7 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 1 ┆ 3 ┆ 5 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 5 ┆ 5 ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 6 ┆ 3 ┆ 4 │
└─────┴─────┴─────┘
缺失值处理
在 polars 里缺失值使用 [Null(https://pola-rs.github.io/polars/polars/prelude/struct.Null.html] 表示.
可以通过 null_count, is_null 分别查看列是否包含缺失值, 以及缺失值 bit mask.
#![allow(unused)] fn main() { let df1: DataFrame = df!( "D1" => &[1, 3, 1, 5, 6], "D2" => &[3, 2, 3, 5, 3], "D3" => &[Some(9), Some(7), Some(5), Some(2), None] )?; println!("{}", df1.null_count()); println!("{}", df1["D3"].is_null().into_series()); }
Output
shape: (1, 3)
┌─────┬─────┬─────┐
│ D1 ┆ D2 ┆ D3 │
│ --- ┆ --- ┆ --- │
│ u32 ┆ u32 ┆ u32 │
╞═════╪═════╪═════╡
│ 0 ┆ 0 ┆ 1 │
└─────┴─────┴─────┘
shape: (5,)
Series: 'D3' [bool]
[
false
false
false
false
true
]
过滤掉包含缺失值的行
#![allow(unused)] fn main() { let df1: DataFrame = df!( "D1" => &[1, 2, 3, 4, 5], "D2" => &[Some(3), Some(2), None, Some(5), Some(3)], "D3" => &[Some(9), Some(7), Some(5), Some(2), None] )?; let df2 = df1.lazy().filter(all().is_not_null()).collect()?; }
Output
shape: (3, 3)
┌─────┬─────┬─────┐
│ D1 ┆ D2 ┆ D3 │
│ --- ┆ --- ┆ --- │
│ i32 ┆ i32 ┆ i32 │
╞═════╪═════╪═════╡
│ 1 ┆ 3 ┆ 9 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 2 ┆ 2 ┆ 7 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 4 ┆ 5 ┆ 2 │
└─────┴─────┴─────┘
只针对某个列过滤
#![allow(unused)] fn main() { let df1: DataFrame = df!( "D1" => &[1, 2, 3, 4, 5], "D2" => &[Some(3), Some(2), None, Some(5), Some(3)], "D3" => &[Some(9), Some(7), Some(5), Some(2), None] )?; let df2 = df1.lazy().filter(col("D3").is_not_null()).collect()?; println!("{}", df2); }
Output
shape: (4, 3)
┌─────┬──────┬─────┐
│ D1 ┆ D2 ┆ D3 │
│ --- ┆ --- ┆ --- │
│ i32 ┆ i32 ┆ i32 │
╞═════╪══════╪═════╡
│ 1 ┆ 3 ┆ 9 │
├╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌┤
│ 2 ┆ 2 ┆ 7 │
├╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌┤
│ 3 ┆ null ┆ 5 │
├╌╌╌╌╌┼╌╌╌╌╌╌┼╌╌╌╌╌┤
│ 4 ┆ 5 ┆ 2 │
└─────┴──────┴─────┘
填充缺失值
填充缺失值的方法大概包括
- 字面量
- 前向或后向填充
- 表达式, 例如根据其他列填充
- 插值
#![allow(unused)] fn main() { let df1: DataFrame = df!( "D1" => &[1, 2, 3, 4, 6], "D2" => &[3, 2, 8, 5, 3], "D3" => &[Some(9), Some(7), None, Some(2), Some(4)] )?; // 对全部 null 全部更换为 200 let df2 = df1.clone().lazy().fill_null(lit(200)).collect()?; println!("对全部 null 全部更换为 200\n{}", df2); // 以下一个值填充 let df2 = df1 .clone() .lazy() .with_column(col("D3").backward_fill(None)) .collect()?; println!("以下一个值填充\n{}", df2); // 以前一个值填充 let df2 = df1 .clone() .lazy() .with_column(col("D3").forward_fill(None)) .collect()?; println!("以前一个值填充\n{}", df2); // 插值 let df2 = df1 .clone() .lazy() .with_column(col("D3").interpolate()) .collect()?; println!("插值\n{}", df2); }
Output
对全部 null 全部更换为 200
shape: (5, 3)
┌─────┬─────┬─────┐
│ D1 ┆ D2 ┆ D3 │
│ --- ┆ --- ┆ --- │
│ i32 ┆ i32 ┆ i32 │
╞═════╪═════╪═════╡
│ 1 ┆ 3 ┆ 9 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 2 ┆ 2 ┆ 7 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 3 ┆ 8 ┆ 200 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 4 ┆ 5 ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 6 ┆ 3 ┆ 4 │
└─────┴─────┴─────┘
以下一个值填充
shape: (5, 3)
┌─────┬─────┬─────┐
│ D1 ┆ D2 ┆ D3 │
│ --- ┆ --- ┆ --- │
│ i32 ┆ i32 ┆ i32 │
╞═════╪═════╪═════╡
│ 1 ┆ 3 ┆ 9 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 2 ┆ 2 ┆ 7 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 3 ┆ 8 ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 4 ┆ 5 ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 6 ┆ 3 ┆ 4 │
└─────┴─────┴─────┘
以前一个值填充
shape: (5, 3)
┌─────┬─────┬─────┐
│ D1 ┆ D2 ┆ D3 │
│ --- ┆ --- ┆ --- │
│ i32 ┆ i32 ┆ i32 │
╞═════╪═════╪═════╡
│ 1 ┆ 3 ┆ 9 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 2 ┆ 2 ┆ 7 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 3 ┆ 8 ┆ 7 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 4 ┆ 5 ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 6 ┆ 3 ┆ 4 │
└─────┴─────┴─────┘
插值
shape: (5, 3)
┌─────┬─────┬─────┐
│ D1 ┆ D2 ┆ D3 │
│ --- ┆ --- ┆ --- │
│ i32 ┆ i32 ┆ i32 │
╞═════╪═════╪═════╡
│ 1 ┆ 3 ┆ 9 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 2 ┆ 2 ┆ 7 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 3 ┆ 8 ┆ 5 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 4 ┆ 5 ┆ 2 │
├╌╌╌╌╌┼╌╌╌╌╌┼╌╌╌╌╌┤
│ 6 ┆ 3 ┆ 4 │
└─────┴─────┴─────┘