Polars针对处理已排序的数据进行了优化。
要访问这些优化,你需要使用set_sorted标志告诉Polars数据已经排序。
set_sorted
主要用于以下两种情况:
-
标记单个或多个列已排序:当你知道 DataFrame 的某个或某些列是按升序或降序排列时,你可以使用
set_sorted
来标记这些列。这将告诉 Polars 这些列的排序状态,从而使其在执行查询时能够选择更有效的算法。 -
在 Lazy 模式下使用:在 Polars 的 Lazy 模式中,
set_sorted
可以在执行计划生成阶段提供额外的信息,这有助于优化器选择更高效的执行路径。
调用方式
set_sorted
可以以多种方式调用:
-
标记单个列已排序:
df = df.with_columns(pl.col("column_name").set_sorted())
-
标记单个列已排序并指定排序方向:
df = df.with_columns(pl.col("column_name").set_sorted(ascending=True))
这里,
ascending
参数指定了列是升序还是降序排列。
-
标记多个列已排序:
df = df.with_columns( [ pl.col("column1").set_sorted(), pl.col("column2").set_sorted(), ... ] )
在下面这个简单的例子中,当我们告诉Polars序列已排序时,我们找到中位数的速度提高了1500倍。
# 创建一个有一千万个条目的series
s = pl.Series("a", range(0,int(1e7)))
# 调用没有设置set_sorted 的.median
s.median()
# 耗时: 0.3 s
# 调用设置了set_sorted 的.median
s.set_sorted().median()
# 耗时: 0.0002 s
显然,使用 set_sorted
后可以显著提升某些操作的性能,特别是涉及到以下操作时:
- 二分查找:Polars 可以使用二分查找算法,这在大型数据集上比线性查找快得多。
- 分组和聚合:如果分组键已排序,Polars 可以使用更高效的算法进行分组和聚合操作。
- 窗口函数:对于基于排序的窗口函数(如
rank
,cumsum
,cummean
等),如果数据已排序,Polars 可以避免不必要的排序步骤。
另外,使用set_sorted
时,应注意以下几点:
- 数据一致性:使用
set_sorted
前,请确保数据实际上已按你声明的方式排序。如果数据未排序,Polars 的行为可能不可预测,甚至可能导致错误结果。 - 仅限于已排序数据:
set_sorted
不会对数据进行排序,它只是一种声明,告知 Polars 数据是已排序的。 - Lazy 模式下的优化:在 Lazy 模式下使用
set_sorted
,可以触发更深层次的优化,因为Polars的查询优化器能够利用这些信息来优化执行计划。
你可能已经在不知不觉中利用了set_sorted。如果你在操作中隐式或显式地对数据进行了排序,Polars会自动应用set_sorted。
set_sorted也适用于其他操作——在我的一些工作流程中,对Polars知道已排序的列进行大型数据集的groupby操作,速度提高了40%。