0

0

Polars中利用列值作为字典键进行数据过滤的策略与优化

聖光之護

聖光之護

发布时间:2025-10-13 11:25:22

|

556人浏览过

|

来源于php中文网

原创

Polars中利用列值作为字典键进行数据过滤的策略与优化

在polars中,直接使用列表达式作为python字典的键会导致`typeerror: unhashable type: 'expr'`。本文将深入探讨两种有效解决此问题的方法:一是利用`map_elements`进行行级别转换,这种方法直观但效率较低;二是将嵌套字典扁平化为polars dataframe,并通过`join`操作实现高效过滤,这是处理大规模数据的推荐方案。文章将详细阐述每种方法的实现细节、适用场景及其性能考量。

在Polars进行数据处理时,我们有时会遇到需要根据DataFrame中的列值去查询一个外部Python字典的情况,特别是当字典是多层嵌套时。例如,尝试使用pl.col("cliente")和pl.col("cluster")作为nested_dict的键来过滤数据,如下所示:

df_x = (
    df_x
    .filter(pl.col("score") == nested_dict[pl.col("cliente")][pl.col("cluster")])
)

这段代码会抛出TypeError: unhashable type: 'Expr'错误。这是因为pl.col("cliente")和pl.col("cluster")返回的是Polars表达式(Expr对象),而不是实际的列值。Python字典的键必须是可哈希的(hashable),而Expr对象不可哈希,因此无法直接用作字典键进行查询。

为了解决这个问题,我们可以采用两种主要策略:一种是利用map_elements在行级别应用Python函数,另一种是将外部字典转换为Polars DataFrame并进行连接(join)操作。

策略一:使用 map_elements 进行行级别转换

map_elements方法允许我们对DataFrame中的元素应用一个Python函数。通过这种方式,我们可以在函数内部解析列值,并使用这些实际值来查询Python字典。

实现步骤

  1. 组合相关列: 使用pl.struct()将需要作为字典键的列(例如'cliente'和'cluster')组合成一个结构体(Struct)。
  2. 应用 map_elements: 对这个结构体应用map_elements函数。该函数会接收每一行的结构体作为输入,其中包含各列的实际值。
  3. 字典查询: 在map_elements内部的lambda函数中,使用结构体中的实际值来查询nested_dict。

示例代码

import polars as pl

# 示例数据和嵌套字典
df_x = pl.DataFrame({
    "cliente": ["A", "B", "A", "C"],
    "cluster": ["X", "Y", "Z", "X"],
    "score": [10, 20, 30, 40]
})

nested_dict = {
    "A": {"X": 10, "Z": 25},
    "B": {"Y": 20},
    "C": {"X": 40}
}

# 使用 map_elements 进行过滤
df_filtered_map = (
    df_x
    .filter(
        pl.col('score').eq(
            pl.struct('cliente', 'cluster')
                .map_elements(lambda x: (
                    nested_dict.get(x['cliente'], {}).get(x['cluster']) # 使用 .get 避免 KeyError
                ), return_dtype=pl.Int64) # 指定返回类型
        )
    )
)

print("使用 map_elements 过滤后的 DataFrame:")
print(df_filtered_map)

注意事项

  • 性能: map_elements会强制Polars将数据传递给Python函数进行处理,这会引入Python解释器的开销,通常比纯Polars的向量化操作效率低。对于大规模数据集,这可能成为性能瓶颈
  • 错误处理: 在lambda函数中,建议使用字典的.get()方法来安全地访问键,以防止当cliente或cluster的组合在nested_dict中不存在时引发KeyError。
  • 返回类型: 必须为map_elements指定return_dtype,否则Polars可能无法推断出正确的列类型。

策略二:扁平化字典并进行连接(Join)

更高效且Polars-idiomatic 的方法是将嵌套的Python字典转换为一个Polars DataFrame,然后通过join操作将其与主DataFrame连接起来,最后再进行过滤。这种方法将字典查询转换为Polars的向量化操作,从而显著提高性能。

MaxAI
MaxAI

MaxAI.me是一款功能强大的浏览器AI插件,集成了多种AI模型。

下载

实现步骤

  1. 扁平化嵌套字典: 将nested_dict转换为一个包含cliente、cluster和cluster_value(即对应的分数)的Polars DataFrame。
  2. 执行连接操作: 使用join方法将主DataFrame与扁平化的字典DataFrame连接起来,连接键为cliente和cluster。
  3. 进行过滤: 连接后,cluster_value列将可用,可以直接用于过滤条件。

示例代码

import polars as pl

# 示例数据和嵌套字典
df_x = pl.DataFrame({
    "cliente": ["A", "B", "A", "C", "D"],
    "cluster": ["X", "Y", "Z", "X", "Y"],
    "score": [10, 20, 30, 40, 50]
})

nested_dict = {
    "A": {"X": 10, "Z": 25},
    "B": {"Y": 20},
    "C": {"X": 40}
}

# 1. 扁平化嵌套字典为 Polars DataFrame
df_nested_prelim = pl.from_dict(nested_dict)

df_nested_parts = []
for col_name in df_nested_prelim.columns:
    df_nested_parts.append(
        df_nested_prelim.lazy()
        .select(col_name).unnest(col_name) # 展开内部字典为列
        .unpivot(
            on=[], # 不指定on,对所有非id列进行unpivot
            index=[], # 没有id列,所有列都参与unpivot
            variable_name='cluster', 
            value_name='cluster_value'
        )
        .with_columns(cliente=pl.lit(col_name)) # 添加原始的cliente名称
    )

df_nested = pl.concat(df_nested_parts).collect()

# 2. 移除可能产生的null值(如果原始字典中没有对应的cluster)
df_nested = df_nested.filter(pl.col("cluster_value").is_not_null())

print("\n扁平化后的字典 DataFrame:")
print(df_nested)

# 3. 执行连接并过滤
df_filtered_join = (
    df_x
    .join(df_nested, on=['cliente', 'cluster'], how='inner') # 使用inner join确保只匹配存在的值
    .filter(pl.col('score') == pl.col('cluster_value'))
    .select(df_x.columns) # 仅保留原始 df_x 的列
)

print("\n使用 join 过滤后的 DataFrame:")
print(df_filtered_join)

扁平化字典的详细解释

上述扁平化字典的代码可能看起来有些复杂,我们来逐步解析:

  1. df_nested_prelim = pl.from_dict(nested_dict): 将nested_dict转换为Polars DataFrame。此时,nested_dict的顶层键(如"A", "B", "C")会成为DataFrame的列名,而它们对应的值(内层字典)会成为这些列中的结构体(Struct)。 例如,df_nested_prelim可能看起来像:

    shape: (1, 3)
    ┌───────────┬───────────┬───────────┐
    │ A         ┆ B         ┆ C         │
    │ struct[2] ┆ struct[1] ┆ struct[1] │
    ╞═══════════╪═══════════╪═══════════╡
    │ {10,25}   ┆ {20}      ┆ {40}      │
    └───────────┴───────────┴───────────┘
  2. for col_name in df_nested_prelim.columns:: 遍历df_nested_prelim中的每一列(即原始的cliente名称)。

  3. select(col_name).unnest(col_name): 选择当前列,并将其解嵌套。例如,对于列"A",它包含{"X": 10, "Z": 25}这个结构体。unnest("A")会将其展开为两列:"X"和"Z"。

    shape: (1, 2)
    ┌─────┬─────┐
    │ X   ┆ Z   │
    │ i64 ┆ i64 │
    ╞═════╪═════╡
    │ 10  ┆ 25  │
    └─────┴─────┘
  4. unpivot(on=[], index=[], variable_name='cluster', value_name='cluster_value'): 将宽格式的DataFrame(X, Z作为列)转换为长格式。variable_name指定了新的列名,用于存放原始的列名(X, Z),value_name指定了存放原始列值(10, 25)的列名。 结果会是:

    shape: (2, 2)
    ┌─────────┬───────────────┐
    │ cluster ┆ cluster_value │
    │ str     ┆ i64           │
    ╞═════════╪═══════════════╡
    │ X       ┆ 10            │
    │ Z       ┆ 25            │
    └─────────┴───────────────┘
  5. with_columns(cliente=pl.lit(col_name)): 添加一个名为cliente的新列,其值就是当前循环的原始cliente名称(例如"A")。

    shape: (2, 3)
    ┌─────────┬───────────────┬─────────┐
    │ cluster ┆ cluster_value ┆ cliente │
    │ str     ┆ i64           ┆ str     │
    ╞═════════╪═══════════════╪═════════╡
    │ X       ┆ 10            ┆ A       │
    │ Z       ┆ 25            ┆ A       │
    └─────────┴───────────────┴─────────┘
  6. pl.concat(df_nested_parts).collect(): 将所有cliente循环生成的DataFrame片段拼接在一起,形成最终的扁平化字典DataFrame。

优势

  • 高性能: join和filter操作都是Polars的高度优化和向量化操作,能够充分利用多核CPU,处理大规模数据集时效率远高于map_elements。
  • Polars范式: 这种方法更符合Polars的设计哲学,即尽量将操作保持在DataFrame级别,避免Python循环和UDF。

总结

当需要在Polars中根据列值查询外部Python字典时,直接使用列表达式作为字典键是不可行的。

  • map_elements方法 提供了一种快速实现的方式,尤其适用于数据量较小或逻辑复杂难以用Polars表达式表达的场景。但其性能开销较大。
  • 扁平化字典并进行join的方法 是处理大规模数据集时的首选方案。它将字典查询转换为高效的Polars DataFrame操作,提供了卓越的性能和可扩展性。

在实际应用中,应根据数据规模和性能要求选择最合适的方法。对于生产环境和大数据场景,强烈推荐采用扁平化字典并进行连接的策略。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

510

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

204

2025.07.04

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

215

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

193

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

61

2026.01.05

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

69

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

109

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

326

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

62

2026.03.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 5万人学习

SciPy 教程
SciPy 教程

共10课时 | 2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

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