8.3 使用 query() 和 eval() 提高性能


文档摘要

8.3 使用 query() 和 eval() 提高性能 Pandas 性能优化: 和 的妙用 8.3.1 :高效的数据筛选 方法允许你使用字符串表达式来筛选 DataFrame 中的数据。它比传统的布尔索引更加简洁易懂,而且在某些情况下,性能也更胜一筹。 语法: expr: 字符串表达式,用于筛选数据。 inplace: 是否修改原始 DataFrame。 kwargs: 传递给表达式的其他变量。 示例: 性能对比: 在大多数情况下, 的性能优于传统的布尔索引,尤其是在处理大型数据集和复杂查询时。 这是因为 内部使用了 库,它能够对表达式进行优化,并利用多线程加速计算。 的优势: 简洁易懂: 使用字符串表达式,代码更易读。 性能提升: 利用 优化计算。

8.3 使用 query() 和 eval() 提高性能

Pandas 性能优化:query()eval() 的妙用

8.3.1 query():高效的数据筛选

query() 方法允许你使用字符串表达式来筛选 DataFrame 中的数据。它比传统的布尔索引更加简洁易懂,而且在某些情况下,性能也更胜一筹。

语法:

DataFrame.query(expr, inplace=False, **kwargs)
  • expr: 字符串表达式,用于筛选数据。

  • inplace: 是否修改原始 DataFrame。

  • kwargs: 传递给表达式的其他变量。

示例:

import pandas as pd import numpy as np # 创建一个示例 DataFrame np.random.seed(42) df = pd.DataFrame({ 'A': np.random.rand(100000), 'B': np.random.rand(100000), 'C': np.random.randint(0, 10, 100000) }) # 传统布尔索引 filtered_df_bool = df[(df['A'] > 0.5) & (df['B'] < 0.3)] # 使用 query() filtered_df_query = df.query('A > 0.5 and B < 0.3') # 验证结果是否一致 print(filtered_df_bool.equals(filtered_df_query)) # 输出 True

性能对比:

import time # 传统布尔索引 start_time = time.time() filtered_df_bool = df[(df['A'] > 0.5) & (df['B'] < 0.3)] end_time = time.time() bool_time = end_time - start_time print(f"布尔索引耗时: {bool_time:.4f} 秒") # 使用 query() start_time = time.time() filtered_df_query = df.query('A > 0.5 and B < 0.3') end_time = time.time() query_time = end_time - start_time print(f"query() 耗时: {query_time:.4f} 秒") print(f"query() 比 布尔索引 快:{(bool_time - query_time)/bool_time * 100:.2f}%")

在大多数情况下,query() 的性能优于传统的布尔索引,尤其是在处理大型数据集和复杂查询时。 这是因为 query() 内部使用了 Numexpr 库,它能够对表达式进行优化,并利用多线程加速计算。

query() 的优势:

  • 简洁易懂: 使用字符串表达式,代码更易读。

  • 性能提升: 利用 Numexpr 优化计算。

  • 支持局部变量: 可以在表达式中使用 DataFrame 之外的变量。

threshold = 0.7 filtered_df = df.query('A > @threshold') # @符号引用外部变量

query() 的局限性:

  • 语法限制: 只能使用 Numexpr 支持的语法。

  • 表达式求值: query() 会对表达式进行求值,因此需要注意潜在的安全风险,避免执行恶意代码。

最佳实践:

  • 尽量使用 query() 来筛选数据,尤其是在处理大型数据集时。

  • 避免在 query() 表达式中使用复杂的 Python 函数,以确保性能。

  • 注意表达式的安全性,避免执行未知的代码。

8.3.2 eval():加速数值计算

eval() 方法允许你使用字符串表达式来计算 DataFrame 的新列。 类似于 query(),它也利用 Numexpr 库来优化计算,从而提高性能。

语法:

DataFrame.eval(expr, inplace=False, **kwargs)
  • expr: 字符串表达式,用于计算新列。

  • inplace: 是否修改原始 DataFrame。

  • kwargs: 传递给表达式的其他变量。

示例:

# 创建一个示例 DataFrame np.random.seed(42) df = pd.DataFrame({ 'A': np.random.rand(100000), 'B': np.random.rand(100000), 'C': np.random.rand(100000) }) # 传统方法 df['D'] = df['A'] + df['B'] * df['C'] # 使用 eval() df['E'] = df.eval('A + B * C') # 验证结果是否一致 print(np.allclose(df['D'], df['E'])) # 输出 True

性能对比:

# 传统方法 start_time = time.time() df['D'] = df['A'] + df['B'] * df['C'] end_time = time.time() traditional_time = end_time - start_time print(f"传统方法耗时: {traditional_time:.4f} 秒") # 使用 eval() start_time = time.time() df['E'] = df.eval('A + B * C') end_time = time.time() eval_time = end_time - start_time print(f"eval() 耗时: {eval_time:.4f} 秒") print(f"eval() 比 传统方法 快:{(traditional_time - eval_time)/traditional_time * 100:.2f}%")

eval() 在进行数值计算时,通常比传统方法更快。 这是因为 eval() 避免了创建临时对象,并直接在 NumPy 数组上进行计算。

eval() 的优势:

  • 性能提升: 利用 Numexpr 优化计算。

  • 减少内存占用: 避免创建临时对象。

  • 链式操作: 可以方便地进行链式计算。

df = df.eval('F = A + B').eval('G = F / C')

eval() 的局限性:

  • 语法限制: 只能使用 Numexpr 支持的语法。

  • 赋值操作: 只能创建新的列,不能修改现有的列。

  • 安全性:query() 类似,需要注意表达式的安全性。

最佳实践:

  • 尽量使用 eval() 来计算新的列,尤其是在进行复杂的数值计算时。

  • 避免在 eval() 表达式中使用 Python 函数,以确保性能。

  • 注意表达式的安全性,避免执行未知的代码。

8.3.3 query()eval() 的内部机制

query()eval() 的性能提升主要归功于 Numexpr 库。Numexpr 能够:

  1. 解析表达式: 将字符串表达式解析成抽象语法树。

  2. 优化表达式: 对表达式进行优化,例如消除公共子表达式、重排计算顺序等。

  3. 编译表达式: 将表达式编译成机器码,以便高效执行。

  4. 并行计算: 利用多线程并行计算,加速计算过程。

通过这些优化,Numexpr 能够显著提高数值计算的效率。

8.3.4 总结

query()eval() 是 Pandas 中非常有用的性能优化工具。 它们能够利用 Numexpr 库,加速数据筛选和数值计算,从而提高数据分析的效率。 在实际应用中,我们应该根据具体情况选择合适的工具,并注意表达式的安全性,以充分发挥它们的优势。

性能优化流程 (Graph TD):

关键要点:

  • query() 用于高效的数据筛选。

  • eval() 用于加速数值计算。

  • 两者都利用 Numexpr 库进行优化。

  • 注意表达式的语法和安全性。

  • 根据实际情况选择合适的工具。

通过学习和实践,我们可以更好地利用 query()eval(),提升 Pandas 数据分析的效率,从而更好地应对大数据时代的挑战。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U