Polars LazyFrames中高效实现除索引列外的多列乘法操作

DDD
发布: 2025-11-19 12:35:42
原创
247人浏览过

Polars LazyFrames中高效实现除索引列外的多列乘法操作

本教程详细介绍了如何在polars lazyframes中对两个数据帧进行除指定索引列(如时间列)外的所有数值列执行元素级乘法操作。通过利用polars的结构体(`struct`)表达式、高效的连接(`join`)机制以及解嵌套(`unnest`)功能,我们能够优雅地解决在pandas中常见的跨dataframe列操作问题,同时保持polars的惰性计算优势,实现高性能的数据处理。

引言

在数据处理领域,Pandas因其直观的DataFrame操作而广受欢迎。例如,对两个具有相同索引和列名的Pandas DataFrame执行元素级乘法,可以直接使用df1 * df2这样的简洁语法。然而,随着数据规模的增长,高性能数据处理框架如Polars逐渐成为主流。Polars以其内存效率和惰性计算能力著称,但在某些特定操作上,其语法模式与Pandas有所不同。本教程将专注于解决一个常见问题:如何在Polars LazyFrames中,对除一个指定列(如时间戳)之外的所有列执行元素级乘法。

数据准备

首先,我们创建两个Polars LazyFrame,它们模拟了Pandas中的两个DataFrame,包含一个时间列作为“索引”和多个数值列。

import polars as pl
import pandas as pd
import numpy as np

# 设置数据行数
n = 5

# 创建第一个Polars LazyFrame
df1 = pl.DataFrame(data={
    'time': pd.date_range('2023-01-01', periods=n, freq='1 min'),
    'foo': np.random.uniform(0,127, size=n).astype(np.float64),
    'bar': np.random.uniform(1e3,32767, size=n).astype(np.float64),
    'baz': np.random.uniform(1e6,2147483, size=n).astype(np.float64)
}).lazy()

# 创建第二个Polars LazyFrame
df2 = pl.DataFrame(data={
    'time': pd.date_range('2023-01-01', periods=n, freq='1 min'),
    'foo': np.random.uniform(0,127, size=n).astype(np.float64),
    'bar': np.random.uniform(1e3,32767, size=n).astype(np.float64),
    'baz': np.random.uniform(1e6,2147483, size=n).astype(np.float64)
}).lazy()

print("df1 (LazyFrame):")
print(df1.collect())
print("\ndf2 (LazyFrame):")
print(df2.collect())
登录后复制

Polars中的挑战与常见误区

在Polars中,直接像Pandas那样对两个LazyFrame进行乘法操作并不直接支持。一种常见的尝试是使用pl.concat将两个LazyFrame堆叠,然后按时间列进行group_by,再尝试聚合乘法。

例如,如果尝试对所有列进行聚合求和,这会按预期工作:

# 聚合求和示例
sum_result = pl.concat([df1, df2]).group_by('time').sum().sort('time').collect()
print("\n聚合求和结果:")
print(sum_result)
登录后复制

然而,如果尝试将sum替换为某种乘法聚合,例如pl.col("*").mul(pl.col("*")),结果通常不是我们期望的元素级乘法。这是因为group_by后的聚合操作通常是对每个组内的值进行处理,而不是跨原始的两个DataFrame进行元素级对应。尝试使用agg(pl.col("*").mul(pl.col("*")))会得到一个包含列表的列,其中每个列表包含了组内元素的自乘结果,而非两个原始DataFrame对应列的乘积。

# 错误的乘法聚合尝试
incorrect_product_attempt = pl.concat([df1, df2]).group_by('time').agg(pl.col("*").mul(pl.col("*"))).sort('time').collect()
print("\n错误的乘法聚合尝试结果:")
print(incorrect_product_attempt)
登录后复制

上述输出显示,每个单元格都是一个包含两个浮点数的列表,这表明pl.col("*").mul(pl.col("*"))是在每个组内对数据进行操作,而不是实现df1['foo'] * df2['foo']这样的跨DataFrame乘法。

Polars的解决方案:基于结构体和连接

Polars提供了一种更符合其表达系统和惰性计算范式的方法来解决这个问题,即利用结构体(struct)类型和join操作。

步骤一:封装非索引列为结构体

首先,我们需要将每个LazyFrame中除“time”列之外的所有列打包成一个结构体(struct)。这使得我们可以将所有要进行乘法运算的列视为一个整体。

Clipfly
Clipfly

一站式AI视频生成和编辑平台,提供多种AI视频处理、AI图像处理工具。

Clipfly 98
查看详情 Clipfly
# 将df1的非时间列封装为结构体
df1_struct = df1.select("time", cols=pl.struct(pl.exclude("time")))
print("\ndf1封装为结构体后的LazyFrame:")
print(df1_struct.collect())

# 将df2的非时间列封装为结构体
df2_struct = df2.select("time", cols=pl.struct(pl.exclude("time")))
print("\ndf2封装为结构体后的LazyFrame:")
print(df2_struct.collect())
登录后复制

通过pl.struct(pl.exclude("time")),我们创建了一个名为cols的结构体列,它包含了foo、bar和baz这三列的数据。

步骤二:通过时间列连接两个LazyFrame

接下来,我们使用“time”列作为键,对这两个包含结构体的LazyFrame进行左连接(left join)。这将确保两个LazyFrame中相同时间戳的数据行能够对齐。

# 连接两个包含结构体的LazyFrame
joined_df = (
    df1_struct
    .join(
        df2_struct,
        on = "time",
        how = "left"
    )
)
print("\n连接后的LazyFrame:")
print(joined_df.collect())
登录后复制

连接操作会产生两列结构体:cols(来自df1_struct)和cols_right(来自df2_struct)。

步骤三:执行结构体乘法并解嵌套

现在,我们可以直接对这两列结构体执行乘法操作。Polars会自动识别并对结构体内部的对应字段进行元素级乘法。然后,使用unnest("cols")将结果结构体展开,恢复到原始的列结构。

# 执行结构体乘法并解嵌套
final_result = (
    df1_struct
    .join(
       df2_struct,
       on = "time",
       how = "left"
    )
    .select("time", pl.col("cols") * pl.col("cols_right")) # 对结构体列进行乘法
    .unnest("cols") # 解嵌套结果结构体
    .sort("time") # 排序以保持一致性
)
print("\n最终乘法结果:")
print(final_result.collect())
登录后复制

最终结果是一个新的LazyFrame,其中包含time列和经过元素级乘法运算后的foo、bar、baz列。

完整代码示例

将上述步骤整合,以下是完整的解决方案代码:

import polars as pl
import pandas as pd
import numpy as np

# 设置数据行数
n = 5

# 创建第一个Polars LazyFrame
df1 = pl.DataFrame(data={
    'time': pd.date_range('2023-01-01', periods=n, freq='1 min'),
    'foo': np.random.uniform(0,127, size=n).astype(np.float64),
    'bar': np.random.uniform(1e3,32767, size=n).astype(np.float64),
    'baz': np.random.uniform(1e6,2147483, size=n).astype(np.float64)
}).lazy()

# 创建第二个Polars LazyFrame
df2 = pl.DataFrame(data={
    'time': pd.date_range('2023-01-01', periods=n, freq='1 min'),
    'foo': np.random.uniform(0,127, size=n).astype(np.float64),
    'bar': np.random.uniform(1e3,32767, size=n).astype(np.float64),
    'baz': np.random.uniform(1e6,2147483, size=n).astype(np.float64)
}).lazy()

# 核心解决方案
product_of_columns = (
    df1.select("time", cols=pl.struct(pl.exclude("time"))) # 将df1的非时间列打包成结构体
    .join(
       df2.select("time", cols=pl.struct(pl.exclude("time"))), # 将df2的非时间列打包成结构体
       on = "time", # 以时间列为键进行连接
       how = "left" # 使用左连接
    )
    .select("time", pl.col("cols") * pl.col("cols_right")) # 对两个结构体列执行元素级乘法
    .unnest("cols") # 解嵌套结果结构体,恢复原始列结构
    .sort("time") # 对结果按时间列排序
    .collect() # 触发惰性计算并获取结果
)

print("\n最终所有非时间列的元素级乘法结果:")
print(product_of_columns)
登录后复制

注意事项与最佳实践

  1. 惰性计算优势: Polars的LazyFrame在调用.collect()之前不会执行任何计算,这使得它在处理大型数据集时能够进行查询优化,并有效管理内存。
  2. pl.struct的灵活性: pl.struct表达式是Polars中处理多列操作的强大工具。它允许我们将一组相关的列视为一个单一的复合类型,从而简化复杂的数据转换逻辑。
  3. pl.exclude的便捷性: pl.exclude("column_name")表达式非常方便,它允许我们轻松地选择除指定列之外的所有列,避免手动列举大量列名。
  4. join操作的重要性: 在Polars中,当需要对齐来自不同DataFrame的数据时,join操作是核心。确保on参数指定了正确的键列,并且how参数符合您的业务逻辑(例如,left、inner、outer等)。
  5. 列名一致性: 为确保结构体乘法和解嵌套的正确性,两个LazyFrame中被排除的非索引列的名称和顺序应保持一致。Polars的结构体乘法会基于字段名进行匹配。

总结

通过本教程,我们学习了如何在Polars LazyFrames中优雅地实现对除索引列外的所有列进行元素级乘法操作。这种方法利用了Polars强大的表达式系统,特别是pl.struct、join和unnest,提供了一种高效且符合Polars设计哲学的解决方案。掌握这种模式对于从Pandas迁移到Polars,并充分利用Polars的性能优势至关重要。

以上就是Polars LazyFrames中高效实现除索引列外的多列乘法操作的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号