Polars简明基础教程二:懒惰模式 1:引入懒惰模式

到本讲结束时,您将能够:

  • 从CSV文件创建一个LazyFrame
  • 解释DataFrame和LazyFrame之间的区别
  • 打印优化的查询计划

懒加载模式对于充分利用Polars的查询优化和流式处理大数据集至关重要。我们在本课中介绍懒加载模式,并在整个课程中反复提及它。

代码还是查询?

数据分析通常涉及多个步骤:

  1. 从文件或数据库加载数据
  2. 转换数据
  3. 按列分组
  4. ...

我们称这组步骤为一个查询。

我们可以编写几行代码,在急迫模式下逐步执行查询。

import polars as pl

# 创建一个示例 DataFrame
df = pl.DataFrame({
    'a': [1, 2, 3, 4, 5],
    'b': [5, 4, 3, 2, 1],
    'c': ['x', 'y', 'z', 'x', 'y']
})

# 步骤 1: 筛选出 'a' 列大于 2 的行
filtered_df = df.filter(pl.col('a') > 2)
print(filtered_df)

# 步骤 2: 添加一列 'cumulative_sum',表示 'a' 列的累加和
filtered_df = filtered_df.with_columns(pl.col('a').cum_sum().alias('cumulative_sum'))
print(filtered_df)

# 步骤 3: 筛选出 'b' 列大于 3 的行
filtered_df = filtered_df.filter(pl.col('b') > 3)
print(filtered_df)

# 步骤 4: 按 'c' 列分组并计算 'cumulative_sum' 的平均值
result_df = filtered_df.group_by('c').agg(pl.col('cumulative_sum').mean())
print(result_df)

但这种方法存在两个问题:

  • 每行代码都不知道其他代码在做什么。
  • 每行代码都需要复制整个数据框。

相反,我们可以将步骤作为懒加载模式下的集成查询来编写。

import polars as pl

# 创建一个示例 DataFrame
df = pl.DataFrame({
    'a': [1, 2, 3, 4, 5],
    'b': [5, 4, 3, 2, 1],
    'c': ['x', 'y', 'z', 'x', 'y']
})

# 构建惰性执行的查询计划
df_lazy = (
    df.lazy()
    .filter(pl.col('a') > 2)
    .with_columns(pl.col('a').cum_sum().alias('cumulative_sum'))
    .filter(pl.col('b') > 3)
    .group_by('c')
    .agg(pl.col('cumulative_sum').mean())
)

# 执行查询计划并获取结果
result_df = df_lazy.collect()

print(result_df)

使用集成查询:

  1. 查询优化器可以识别效率
  2. 查询引擎可以最小化内存使用并产生单一输出

那么什么是急切模式和懒加载模式呢?

急切模式:每行代码在遇到时就会立即执行。

懒加载模式:每行代码都会添加到查询计划中,并对查询计划进行优化。

import polars as pl

csv_file = "../data/titanic.csv"

DataFrames 和 LazyFrames

我们使用 pl.read_csv 在急切模式下读取CSV文件,这会创建一个**DataFrame**。

df_eager = pl.read_csv(csv_file)
df_eager.head(2)

我们在懒加载模式下使用 pl.scan_csv 扫描CSV文件,这会创建一个**LazyFrame**。

df_lazy = pl.scan_csv(csv_file)
df_lazy

当我们使用Polars扫描CSV文件时:

  1. Polars会打开文件
  2. 从文件中获取列名作为表头
  3. 从前100行推断每列的数据类型

LazyFrame实际上是一个查询计划——一个关于Polars如何转换你的数据的计划。

我们通过在一个LazyFrame上调用collect方法将LazyFrame转换为一个DataFrame——这会根据查询计划处理你的数据。

(
    df_lazy
    .head(3)
    .collect()
)

我们可以通过调用schema来获取LazyFrame的数据类型架构(这是从列名到数据类型的映射)

df_lazy.schema

然而,当我们尝试获取LazyFrame的架构时,会得到一个警告,指出这可能是一个昂贵的操作,因为Polars需要遍历查询计划的逻辑来确定最终的列和数据类型会是什么。

不过,不要对这里的“昂贵”一词过于担心——对于一个简单的LazyFrame,这可能只需要1毫秒。Polars的开发人员所说的“昂贵”实际上是指到达架构需要一些计算,并且随着查询计划的增长,这种计算所需的时间也会增长。

如果你有一个长而复杂的查询计划——想象一下你正在摄入许多文件并进行大量的连接、拼接和聚合操作——那么你可能开始注意到这需要多长时间。

获取LazyFrame架构的首选方式——在内部与.schema等效——是使用collect_schema。

(
    df_lazy
    .collect_schema()
)

使用collect_schema计算架构仍然比使用collect评估完整查询要快得多(见下文),因为collect_schema不会处理你的数据,它只是运行经过优化的查询计划。

我们无法免费获取LazyFrame的形状,因为Polars不知道从CSV扫描中有多少行。如果我们想要知道长度,我们必须触发一些查询的评估。

(
    df_lazy
    .select(pl.len())
    .collect()
)

在这个查询中,Polars从CSV中加载一列,并使用pl.len计算其长度。

在下一节中,我们将通过调用collect来学习更多关于评估惰性查询的知识。

从数据创建LazyFrame

我们也可以通过带有一些数据的构造函数直接创建一个LazyFrame

pl.LazyFrame({"values":[0,1,2]})

或者我们可以在DataFrame上调用.lazy方法

pl.DataFrame({"values":[0,1,2]}).lazy()

DataFrame和LazyFrame之间有什么区别?

如果我们打印一个DataFrame,我们会看到数据...

print(df_eager.head(2))

shape: (2, 3)
┌─────┬─────┬─────┐
│ a   ┆ b   ┆ c   │
│ --- ┆ --- ┆ --- │
│ i64 ┆ i64 ┆ str │
╞═════╪═════╪═════╡
│ 1   ┆ 5   ┆ x   │
│ 2   ┆ 4   ┆ y   │
└─────┴─────┴─────┘

...但是如果我们打印一个LazyFrame,我们会看到一个查询计划

print(df_lazy)


naive plan: (run LazyFrame.explain(optimized=True) to see the optimized plan)

AGGREGATE
	[col("cumulative_sum").mean()] BY [col("c")] FROM
  FILTER [(col("b")) > (3)] FROM
     WITH_COLUMNS:
     [col("a").cum_sum().alias("cumulative_sum")] 
      FILTER [(col("a")) > (2)] FROM
        DF ["a", "b", "c"]; PROJECT */3 COLUMNS; SELECTION: None

核心信息:

  • 在DataFrame上的方法直接作用于数据。
  • 在LazyFrame上的方法作用于查询计划。

Polars简明基础教程系列

Polars简明基础教程十四:可视化(四)

Polars简明基础教程十三:可视化(三)

Polars简明基础教程十二:可视化(二)

Polars简明基础教程十一:可视化(一)

Polars简明基础教程十:Numpy和Pandas的相互转换(2)

Polars简明基础教程九:Numpy和Pandas的相互转换(1)

Polars简明基础教程八:Series 和 DataFrame 以及它们之间的转换_B

Polars简明基础教程七:Series 和 DataFrame 以及它们之间的转换_A

Polars简明基础教程六:什么是Polars的“DataFrame(数据框)_下”

Polars简明基础教程五:什么是Polars的“DataFrame(数据框)_上”

Polars简明基础教程四:懒惰模式 2:评估查询

Polars简明基础教程三:懒惰模式 1:引入懒惰模式(续)

Polars简明基础教程二:懒惰模式 1:引入懒惰模式

Polars简明基础教程一:Polars快速入门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值