Python Polars 速查表(基于我们的 O'Reilly 书籍)
摘要
此速查表提供了在 Python 中使用 Polars 库的快速参考,涵盖安装、数据结构以及数据分析和转换的方法。
暂无内容
查看缓存全文
缓存时间: 2026/08/18 15:59
# Python Polars:权威速查表
来源:https://opensource.posit.co/resources/cheatsheets/polars/
Polars(https://pola.rs/)是一个用于快速、高效地转换、分析和可视化数据的库,提供富有表现力的DataFrame API。该库由Ritchie Vink于2020年首次发布。
从终端安装Polars及其所有可选依赖项:
```
uv pip install "polars[all]"
```
在Python中导入Polars,并确认已安装的Polars及其依赖项版本:
```
import polars as pl
pl.show_versions()
```
Polars查询通常包括读取数据、转换数据和将结果写回。一个完整的查询通常是一连串的方法调用:
```
fruit = pl.read_csv("fruit.csv")
fruit.filter(
(pl.col("weight") > 1000) & pl.col("is_round")
).write_parquet("fruit.parquet")
```
在本速查表中,`df`表示`DataFrame`,`lf`表示`LazyFrame`,`o`表示与`df`组合的第二个DataFrame,`e`表示任意表达式。因此`e.abs()`表示“在表达式上调用`.abs()`”,例如`pl.col("x").abs()`。
## 数据结构
Polars的所有数据都存储在Series或DataFrame中。
| 结构 | 描述 |
|------|------|
| `Series` | 一维结构。存储相同数据类型的值序列。 |
| `DataFrame` | 二维结构。具有行和列。由一个或多个长度相同的Series组成。 |
| `LazyFrame` | 类似DataFrame但不包含实际数据。是生成DataFrame的蓝图。 |
与pandas不同,Polars的DataFrame没有行索引,其API更倾向于不可变性和方法链式调用,而非就地修改。
- 通过传递名称和值序列创建Series:
```
series = pl.Series("sales", [150.00, 300.00, 250.00])
```
- 从列字典创建DataFrame,每个值可以是Series或普通Python序列。也可以使用任何`pl.read_*()`函数从文件创建:
```
df = pl.DataFrame({
"sales": series,
"id": [41, 42, 43]
})
```
- 由于没有行索引,需要时可以显式添加一列作为索引。
- 将DataFrame转换为LazyFrame。或者直接使用任何`pl.scan_*()`函数从LazyFrame开始。
## 及早API与惰性API
及早API立即执行,而惰性API首先构建优化的查询计划。优化器会自动应用谓词下推(尽早过滤)和投影下推(丢弃未使用的列)。
通过`.lazy()`和`.collect()`在两种表示之间转换:`.lazy()`将DataFrame转换为LazyFrame,`.collect()`执行LazyFrame并返回DataFrame。
- 将DataFrame转换为LazyFrame,并执行LazyFrame获取DataFrame:
```
lf = df.lazy()
df = lf.collect()
```
- 使用流式引擎处理超出内存的数据集:
```
lf.collect(engine="streaming")
```
- 打印优化后的查询计划文本或可视化图形,查看优化器的决策:
```
lf.explain()
lf.show_graph()
```
- 执行查询并返回各节点计时信息,了解时间实际消耗在何处。
## 数据类型
Polars实现了大部分Apache Arrow内存规范,这是一种用于扁平和层次数据的高效列式格式。
| 分组 | 类型 | 说明 |
|------|------|------|
| 数值型 | `Decimal` | 128位,带精度和标度 |
| | `Float32` | 范围 ±3.4×10³⁸ |
| | `Float64` | 范围 ±1.8×10³⁰⁸ |
| | `Int8` | 范围 ±128 |
| | `Int16` | 范围 ±32,768 |
| | `Int32` | 范围 ±2.1×10⁹ |
| | `Int64` | 范围 ±9.2×10¹⁸ |
| | `Int128` | 范围 ±3.4×10³⁸ |
| | `UInt8` | 范围 0–255 |
| | `UInt16` | 范围 0–65,535 |
| | `UInt32` | 范围 0–4.3×10⁹ |
| | `UInt64` | 范围 0–1.8×10¹⁹ |
| 时间型 | `Date` | 自Unix纪元以来的天数 |
| | `Datetime` | 自纪元以来的微秒数 |
| | `Duration` | 时间长度/差值 |
| | `Time` | 一天中的时间 |
| 嵌套型 | `Array` | 固定长度序列 |
| | `List` | 可变长度序列 |
| | `Struct` | 具有多个命名字段的结构 |
| 字符串型 | `String` | UTF-8文本,可变长度 |
| | `Categorical` | 字符串字典 |
| | `Enum` | 固定字符串字典 |
| 其他 | `Boolean` | 真/假 |
| | `Binary` | 原始字节 |
| | `Null` | 表示空值/无值 |
### 检查类型
- 获取列名和数据类型的字典,或仅获取数据类型列表:
- 每列打印一行,包括数据类型,对于宽DataFrame(直接打印难以阅读)很有用:
- 计算每列的汇总统计,包括空值数量:
- 报告DataFrame的内存大小,使用指定单位。
### 类型转换
- 将列转换为其他数据类型。默认转换是严格的,不匹配的值会引发错误:
```
df.select(pl.col("id").cast(pl.UInt64))
```
- 传递`strict=False`进行宽松转换。溢出目标类型的值将变为空值:
```
df.select(pl.col("id").cast(pl.Int8, strict=False))
```
## 读写数据
Polars有四大类输入输出函数,具体使用取决于您是采用及早还是惰性方式:
- `read_*()`将数据读入DataFrame。
- `scan_*()`创建LazyFrame,推迟实际读取直到collect时。
- `write_*()`将DataFrame写入磁盘或云存储。
- `sink_*()`将数据流式传输到磁盘或云存储,无需全部加载到内存。
并非所有格式都支持所有四种操作:
| 格式 | read | scan | write | sink |
|------|------|------|-------|------|
| Avro | ✓ | ✓ | ✓ | ✓ |
| 剪贴板 | ✓ | | ✓ | |
| CSV | ✓ | ✓ | ✓ | ✓ |
| 数据库 | ✓ | | ✓ | |
| Delta Lake | ✓ | ✓ | ✓ | ✓ |
| Excel / ODS | ✓ | | ✓ | |
| Iceberg | ✓ | ✓ | ✓ | |
| IPC / Feather | ✓ | ✓ | ✓ | ✓ |
| JSON | ✓ | | ✓ | |
| NDJSON | ✓ | ✓ | ✓ | ✓ |
| Parquet | ✓ | ✓ | ✓ | ✓ |
| PyArrow Dataset | ✓ | | | |
许多函数接受的通用关键字参数包括`schema_overrides`、`n_rows`、`row_index_name`、`storage_options`和`compression`。
- 通过传递带通配符模式的URI扫描云存储文件,并使用`storage_options`提供凭证和区域设置:
```
pl.scan_parquet(
"s3://bucket/*.parquet",
storage_options={"aws_region": "us-east-2"}
)
```
- 将查询直接流式传输到分区Parquet数据集,为键列的每个唯一值写入一个目录:
```
lf.sink_parquet(pl.PartitionBy("out/", key="x"))
```
## 数据转换
### 选择列
根据名称、数据类型或位置保留列。
- 按名称选择列:
- 选择表达式的结果,以便在输出时转换列:
```
df.select(pl.col("x") * 2)
```
- 使用关键字参数为表达式结果命名,生成新列:
```
df.select(doubled=pl.col("x") * 2)
```
- 选择名称匹配正则表达式的列。模式必须以`^`开头,`$`结尾:
```
df.select(pl.col("^.*_color$"))
```
- 选择所有列:
使用列选择器获得更灵活的选择。它们可以使用集合运算符`|`、`&`、`-`、`^`和`~`组合。
- 导入选择器模块,然后按数据类型或名称模式选择列。另见`cs.string()`、`cs.contains()`和`cs.first()`:
```
import polars.selectors as cs
df.select(cs.numeric())
df.select(cs.starts_with("val"))
```
- 删除列而非保留。传递`strict=False`以便忽略不存在的名称而非引发错误:
```
df.drop("a", "y", strict=False)
```
### 创建列
新列添加到现有列的右侧。
- 添加由表达式计算的新列,使用关键字参数命名:
```
df.with_columns(new=pl.col("a") + 1)
```
- 通过生成同名表达式替换现有列。此处列`a`中的空值被替换为零:
```
df.with_columns(pl.col("a").fill_null(0))
```
- 添加每行具有相同字面值的列:
```
df.with_columns(ones=pl.lit(1))
```
- 添加行索引列。使用`offset`从非零值开始计数:
```
df.with_row_index(name="id", offset=1)
```
### 过滤行
根据一列或多列的值保留行。
- 通过传递布尔列名进行过滤:
- 使用单个表达式过滤:
```
df.filter(pl.col("x") > 5)
```
- 传递多个表达式以逻辑与组合。也可以显式使用`&`,此时每个比较需要自己的括号:
```
df.filter(pl.col("valid"), pl.col("x") > 5)
df.filter(pl.col("valid") & (pl.col("x") > 5))
```
- 使用`|`进行逻辑或:
```
df.filter(pl.col("valid") | (pl.col("x") > 5))
```
- 使用关键字参数约束,这是测试相等性并将结果与与组合的简写:
```
df.filter(valid=True, x=5)
```
- 仅保留没有缺失值的行,或限制检查特定列:
```
df.drop_nulls()
df.drop_nulls("x")
```
- 删除重复行。使用`subset`决定哪些列定义重复,使用`keep`选择哪个重复项保留:
```
df.unique(subset=["x"], keep="first")
```
### 切片和采样行
根据位置保留行。
- 保留前几行或后几行。默认均为五行:
- 通过提供偏移量和长度保留连续切片。此处保留第三行到第七行:
- 保留每第*n*行:
- 随机采样行。使用`with_replacement=True`允许同一行被多次抽取,或使用`fraction`按比例采样而非固定数量:
```
df.sample(10)
df.sample(10, with_replacement=True)
df.sample(fraction=0.2)
```
### 排序行
根据一列或多列的值重新排序行。
- 按单列排序(默认升序),或多列依次排序:
```
df.sort("x")
df.sort("x", "y")
```
- 将空值移到末尾而非开头:
```
df.sort("x", nulls_last=True)
```
- 反转顺序。按多列排序时,传递布尔列表设置每列方向:
```
df.sort("x", descending=True)
df.sort("x", "y", descending=[False, True])
```
- 按表达式结果而非列值排序,例如计算的比率或列表长度:
```
df.sort(pl.col("x") / pl.col("y"))
df.sort(pl.col("l").list.len())
```
- 仅保留按列排序的前*k*个最大或最小行,这比先排序整个表再切片更高效:
```
df.top_k(5, by="score")
df.bottom_k(5, by="score")
```
### 重塑数据
在宽格式和长格式之间转换。
- 通过将一列或多列的值转换为行使DataFrame变长,保留`index`列作为标识符:
```
df.unpivot(on=["c"], index="id")
```
- 通过将一列的值转换为新列使DataFrame变宽。如果`on`和`index`的组合不唯一,请提供`aggregate_function`决定如何合并冲突:
```
df.pivot(on="c", index="id", values="x")
df.pivot(on="c", index="id", values="x", aggregate_function="sum")
```
- 展开列表列,使每个元素占据一行,重复其他列:
- 展开结构列,使每个字段成为自己的列:
- 交换行和列。使用`include_header=True`保留原始列名作为一列:
```
df.transpose(include_header=True)
```
- 将DataFrame拆分为较小DataFrame的列表,每个对应给定列的每个唯一值。
### 汇总和聚合
分割. 应用. 合并。
- 按一列或多列将DataFrame分组。这会给你一个`GroupBy`对象,然后进行聚合:
```
dfg = df.group_by("x")
dfg = df.group_by("x", "y")
```
- 对每个组应用现成的汇总。计算每组的行数、获取每组的前几行或计算每组每列的平均值:
```
dfg.len()
dfg.head(2)
dfg.mean()
```
- 当没有内置聚合函数适用时,对每个组应用自定义函数。
- 使用`agg()`完全控制聚合。传递不带聚合方法的表达式会将值收集到列表中,使用关键字参数命名结果可以为新列提供合理的名称:
```
dfg.agg(...)
dfg.agg(pl.col("y"))
dfg.agg(avg=pl.col("y").mean())
```
- 使用窗口表达式与`over()`将聚合添加为原始DataFrame的新列,而不折叠行:
```
df.with_columns(avg=pl.col("y").mean().over("x"))
```
- 按时间值或索引而非类别分组。`group_by_dynamic()`创建固定持续时间的窗口,`group_by`在此基础上添加常规分组:
```
df.group_by_dynamic("timestamp", every="1h", group_by="store")
```
- 使用`rolling()`创建随每行移动而非固定步长的窗口。计算每店七天滚动销售总额:
```
df.rolling(index_column="date", period="7d", group_by="store").agg(
pl.col("sales").sum()
)
```
- 创建常规时间序列中缺失的行,确保每个间隔都有表示:
```
df.upsample(
time_column="date",
every="1d",
group_by="store",
maintain_order=True
)
```
- 跨列聚合而非沿列聚合。水平函数在每行内组合多列:
```
df.select(pl.sum_horizontal(cs.numeric()))
df.select(pl.any_horizontal(cs.boolean()))
```
### 连接和连接
将多个DataFrame组合为一个。
- 在共享键上连接两个DataFrame。默认是内连接,仅保留两侧匹配的行。
- 使用`how`选择不同的连接策略。左连接保留`df`的每一行:
```
df.join(o, on="key", how="left")
```
- 当键在每个DataFrame中名称不同时,显式命名两侧:
```
df.join(o, left_on="a", right_on="b")
```
- 全外连接保留两侧的所有行。添加`coalesce=True`将两个键列合并为一个:
```
df.join(o, on="key", how="full", coalesce=True)
```
- 过滤连接仅返回`df`的列,并将`o`纯粹用作过滤器。半连接保留有匹配的`df`行,反连接保留没有匹配的行:
```
df.join(o, on="key", how="semi")
df.join(o, on="key", how="anti")
```
- 交叉连接生成两个DataFrame的笛卡尔积,因此不需要键。
- 在最近匹配而非精确匹配上连接,这是对齐两个时间序列的常用方式。使用`by`先精确匹配某些列:
```
df.join_asof(o, on="ts", by="i")
```
- 在不等式或其他非等值连接的任意谓词上连接:
```
df.join_where(o, pl.col("a") >= pl.col("b"))
```
`df.join()`的常用关键字参数包括`left_on`、`right_on`、`coalesce`、`join_nulls`、`suffix`和`validate`,其中`validate`接受`"m:m"`、`"m:1"`、`"1:m"`和`"1:1"`。
- 将DataFrame堆叠在彼此之上,这需要列匹配:
- 或者将DataFrame并排放置,或者取它们的列并集,用空值填充空隙:
```
pl.concat([df, o], how="horizontal")
pl.concat([df, o], how="diagonal")
```
- 使用宽松策略强制转换不匹配的数据类型,而非引发错误:
```
pl.concat([df, o], how="vertical_relaxed")
```
- 使用另一个DataFrame的非空值更新`df`中的值,在键上匹配行:
```
df.update(o, on="id", how="left")
```
## 表达式
相似文章
@gp_pulipaka: 速查表!Python! #BigData #Analytics #DataScience #AI #MachineLearning #IoT #IIoT #PyTorch #Python #RStats #TensorFl…
一条推文分享了来自巴黎-萨克雷大学的Python 3速查表(备忘单),以CC BY 4.0许可提供免费PDF,涵盖面向初学者的基本编程概念。
@MIT_CSAIL: 关键Python函数与概念指南,由 @PythonDvz 提供。
MIT CSAIL 和 PythonDvz 分享的 Python 关键函数与概念指南。
py-evoFE:面向表格机器学习的自动化演化特征工程(Python实现)(遗传算法 + Scikit-Learn + Polars)[P]
py-evoFE是一个开源的Python库,它利用遗传算法来自动化并优化表格机器学习数据集的特征工程,具备scikit-learn兼容性,并采用Polars提升性能。
@ParamSiddh:"Data Structures & Algorithms using Python" 这本书涵盖了从数组到图的所有类型的数据结构。简单易懂……
推广一本名为《Data Structures & Algorithms using Python》的免费书籍,内容涵盖了从数组到图的所有类型的数据结构。
Otary — 图像与几何 Python 库现在已有教程
Otary 是一个用于图像和几何处理的 Python 库,现在提供了教程,帮助用户理解其功能。