Polars는 속도와 메모리 효율성을 위해 구축된 강력한 rust기반의 데이터 조작 라이브러리다. Pandas와 유사한 API를 제공하지만 성능이 더 좋고, 대규모 데이터 세트를 처리하는 데 적합하다. -> 파이썬용, 러스트용 두가지 제공
Polars는 지연 평가 (lazy evaluation)와 병렬 작업 실행 기능 덕분에 메모리에 맞지 않는 대규모 데이터 세트를 처리하도록 설계되었다.
지연 평가 및 병렬 처리는 메모리 사용량을 최소화함으로써 대규모 데이터 세트를 효율적으로 처리할 수 있다. 또한 분산 컴퓨팅을 지원하며 Apache Arrow와 원활하게 통합될 수 있다.
Polars는 매우 빠른 dataframe 라이브러리를 제공하는 것을 목표로한다.
# Cargo.toml
[dependencies]
polars = { version = "0.26.1", features = ["lazy", "temporal", "describe", "json", "parquet", "dtype-datetime"] }
그 밖의 features 들은 공식 문서 참고(https://pola-rs.github.io/polars/user-guide/installation/#rust)
Polars는 완전히 Arrow의 데이터 타입과 메모리 구조를 따른다. 따라서 데이터 전처리를 캐시 효율적이게 하고, 프로세스 간 통신이 잘 지원된다. Utf-8(=LargeUtf8), Categorical, Object 을 제외한 대부분의 데이터 타입들은 Arrow의 구현을 따른다. 눈여겨 볼건 Nested 타입들.
| 그룹 | 타입 | 세부사항 |
|---|---|---|
| Nested | Struct | Struct 배열은 Vec 로 표시되며, 단일 열에 multiple/heterogenous한 값들을 묶는데 유용함 |
List | List배열은 리스트 값과 오프셋 배열을 갖는 child 배열을 포함(실제로 Arrow의 LargeList도 내부적으로 이렇게 되어있음) |
pandas와 마찬가지로 시리즈, 데이터 프레임이 있다. 데이터프레임에 사용하는 함수(head,tail,sample,describe)
Polars는 다음 두가지 특성으로 핵심적인 데이터 변환(eg.group_by로 그룹 크기 계산..)을 매우 빠르게 수행할 수 있다.
Polars는 두 가지 모드를 지원하는데: lazy 와 eager 이다. eager API에서 쿼리는 즉각적으로 실행되는 반면, lazy API에서 쿼리는 필요할 때만 evaluated된다. 실행을 마지막 순간까지 연기하면 상당한 성능 이점을 얻을 수 있으므로 대부분의 경우 Lazy API가 선호된다.
//eager API 예시
let df = CsvReader::from_path("docs/data/iris.csv")
.unwrap()
.finish()
.unwrap();
let mask = df.column("sepal_length")?.f64()?.gt(5.0);
let df_small = df.filter(&mask)?;
let df_agg = df_small
.group_by(["species"])?
.select(["sepal_width"])
.mean()?;
println!("{}", df_agg);
// lazy API 예시
let q = LazyCsvReader::new("docs/data/iris.csv")
.has_header(true)
.finish()?
.filter(col("sepal_length").gt(lit(5)))
.group_by(vec![col("species")])
.agg([col("sepal_width").mean()]);
let df = q.collect()?;
println!("{}", df);
지연API를 사용할 경우, 모든 단계가 정의될 때까지 실행을 기다려서 쿼리 플래너가 다음과 같은 다양한 최적화를 수행할 수 있다.
이를 통해 메모리 및 CPU의 부하가 크게 줄어들어 더 큰 데이터 세트를 메모리에 맞추고 더 빠르게 처리할 수 있다. 쿼리가 정의되면 collect를 호출하여 Polars에게 실행하겠다고 알린다.
일반적으로 중간 결과에 관심이 있거나 탐색 작업을 수행 중이고 쿼리가 어떻게 나타날지 아직 모르는 경우가 아니면 lazy API를 쓴다.
lazy API의 또 다른 이점 중 하나는 쿼리를 스트리밍 방식으로 실행할 수 있다는 점인데, 데이터를 한꺼번에 처리하는 대신 쿼리를 batches로 실행하여 메모리보다 큰 데이터 세트를 처리할 수 있다.
Polars에게 스트리밍 모드에서 쿼리를 실행하고 싶다고 알리기 위해 streaming=True인수를 collect()에 전달한다.
//Streaming 예시
let q = LazyCsvReader::new("docs/data/iris.csv")
.has_header(true)
.finish()?
.filter(col("sepal_length").gt(lit(5)))
.group_by(vec![col("species")])
.agg([col("sepal_width").mean()]);
let df = q.with_streaming(true).collect()?;
println!("{}", df);
모든 lazy 작업이 스트리밍을 지원하는 건 아니고, 스트리밍이 지원되지 않는 작업이 있는 경우 Polars는 비스트림 모드에서 쿼리를 실행한다.
filter, slice, head,tailwith_columns,selectgroup_byjoinsortexplode,meltscan_csv, scan_parquet,scan_ipc