Polars入门指南:从数据类型到高效数据操作
Polars 是一个高性能的 DataFrame 库,专为处理大规模数据而设计,使用 Rust 编写并提供了 Python 和 Node.js 的接口。它旨在提供比 Pandas 更快的性能,特别是在处理大型数据集时。
主要特点
高性能:
基于 Rust 的 Apache Arrow 实现
多线程查询引擎
延迟/惰性评估(Lazy evaluation)优化查询计划
内存高效:
零拷贝数据处理
内存使用效率高
易用性:
API 设计与 Pandas 相似,学习曲线平缓
支持链式方法调用
功能丰富:
支持多种数据操作(过滤、分组、聚合、连接等)
支持时间序列操作
支持缺失值处理
相关网址:
【英文官方文档】(Index - Polars user guide)
【polars github仓库】(pola-rs/polars: Dataframes powered by a multithreaded, vectorized query engine, written in Rust)
【中文官方文档】(介绍 - Polars - 用户指南)
安装
使用命令安装:
pip install polars
安装相关包:
pip install fastexcel xlsx2csv openpyxl
数据类型
Polars
完全基于Arrow
数据类型,并由Arrow
内存阵列支持。这使得数据处理缓存效率高,支持进程间通信。大多数数据类型遵循确切的实现来自Arrow
,除了Utf8
(实际上是LargeUtf8
)、category
和Object
(支持有限)。
基本类型:
Int8/Int16/Int32/Int64:有符号整数
UInt8/UInt16/UInt32/UInt64:无符号整数
Float32/Float64:浮点数
Boolean:布尔值
Utf8:字符串类型
复合类型:
List:列表类型,可以包含相同类型的元素
Struct:结构体类型,可以包含多个不同类型的字段
Categorical:分类类型,适用于有限集合的字符串
时间类型:
Date:日期(年月日)
Datetime:日期时间(带时区)
Duration:时间间隔
Time:时间(时分秒)
Series
Series是Polars中的一维数据结构,类似于Pandas中的Series,但性能更高:
基本特性:
单一数据类型(同质)
长度不可变(创建后不能增减元素)
支持向量化操作
创建方式:
# 从列表创建
s = pl.Series("age", [25, 30, 35])
# 从numpy数组创建
import numpy as np
s = pl.Series("values", np.array([1.1, 2.2, 3.3]))
# 从Pandas Series创建
import pandas as pd
s = pl.from_pandas(pd.Series([1, 2, 3], name="id"))
常用操作:
# 基本统计
s.mean(), s.median(), s.std()
# 过滤
s.filter(s > 30)
# 排序
s.sort()
# 唯一值
s.unique()
DataFrame
DataFrame是Polars的核心数据结构,是一个二维表格:
基本特性:
由多个Series组成(每列一个Series)
列可以有不同的数据类型
不可变设计(操作返回新DataFrame)
创建方式:
# 从字典创建
df = pl.DataFrame({
"name": ["Alice", "Bob", "Charlie"],
"age": [25, 30, 35],
"city": ["NY", "LA", "Chicago"]
})
# 从Pandas创建
df = pl.from_pandas(pd.DataFrame(...))
# 从CSV读取
df = pl.read_csv("data.csv")
基本操作:
# 查看前几行
df.head()
# 描述性统计
df.describe()
# 添加列
df = df.with_columns((pl.col("age") + 1).alias("age_plus_one"))
# 删除列
df = df.drop("city")
行列操作
获取/修改列名
使用df.columns
属性获取当前列名,使用df.rename
方法修改列名
df_renamed = df.rename({
"symbol": "A",
"volume": "B"
})# 修改列名
df_renamed.columns # 查看修改后的列名
选择列
使用df.select
可以选择列
df.select("date")#选择某列
df.select(["date","symbol","close"J) # 选择多列
过滤行
使用df.filter
可以按照特定的规则进行过滤查看你想要的行
df.filter(
pl.col("symbol") = "AAPL",
pl.col("symbol")
.str.strip_chars() # 去除掉前后空格
.str.contains("^(M|S).+"), # 使用正则表达式筛选
pl.col("symbol").is_in(["aapl","msft","googl"])
pl.max_horizontal(pl.col("low") <= pl.col("open"), pl.col("close") <= pl.col("high")),
pl.col("date").is_not_null(),
) # 通过pl.xxx对行进行过滤操作
新增/修改列
使用df.with_columns
可以修改列的属性或者值等
df.with_columns(
pl.col("symbol").str.to_lowercase(), # 修改列所有值
pl.col("symbol").cast(pl.Categorical), # 修改列的数据格式
pl.col("date").str.strptime(pl.Date, "%Y/%m/%d", strict=False),#修改列所有值的数据格式
((pl.col("high")-pl.col("low"))/pl.col("open")).alias("daily_amplitude"),#使用.alias增加新列
)
行切片
选择前后几行
df.head(5) # 前 5 行
df.tail(5) # 后 5 行
基本切片
# 选取第 2 行到第 4 行(左闭右开,索引从 0 开始)
df.slice(2, 3) # 从索引 2 开始,取 3 行
排序
使用df.sort
可以选择某列进行排序
df.sort(
pl.col("date"),
# descending=True # 降序(默认升序)
)
去重
使用df.unique
可以对表进行去重
df.unique(
subset=["symbol", "date", "volume"],
keep="first"
)
其中, subset
参数表示按指定列去重,如果不传则对全表去重, keep
这个参数有三个选项:
keep="first"
:保留第一次出现的那一行(默认值)keep="Last"
:保留最后一次出现的那一行keep=False
:删除所有重复项,只保留完全唯一的行(即所有重复的都去掉)
分组与聚合
分组,在数据分析中,指的是把数据按照某个(或某几个)字段的取值,把数据划分成若干“组”,每组内的数据具有相同的分组字段值。
分组后,通常会对每组分别进行统计、聚合、分析等操作。
假设有如下表格:
按"班级"分组,就会得到:
A 组: 90, 80
B 组: 85, 95
C 组: 88
你可以对每组分别求平均分、总分等。
使用df.group_by().agg()
进行分组和聚合的操作
df.group_by("symbol").agg( # 聚合
pl.len().alias("symbol_group_count"), # 统计每个分组的行数
pl.col("score").sum().alias("total_score"),
pl.col("score").mean().alias("avg_score"),
)
常见的聚合函数如下:
也可以对多列进行分组
df.group_by(["volume", "symbol"]).agg(
pl.col("volume").sum().alias("total_volume")
)