You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Sympy中命名表达式字符串转为表达式并计算简化比值?

SymPy表达式名称字符串转表达式并计算简化比值问题

实际问题描述

我使用SymPy定义了多个表达式,示例如下:

import sympy as sp
a, b = sp.symbols('a,b', real=True, positive=True)
Xcharles_YclassA_Zregion1 = 1.01 * a**1.01 * b**0.99
Xbob_YclassA_Zregion1 = 1.009999 * a**1.01 * b**0.99
Xbob_YclassA_Zregion2 = 1.009999 * a**1.01 * b**0.99000000001
...

通过表达式名称区分不同选项(如charles、bob)和类别(如X)。需要一个函数,接收两个表达式名称字符串(如'Xcharles_YclassA_Zregion1'和'Xbob_YclassA_Zregion1'),返回它们的简化比值(示例中为1.00000099009999),以此快速对比结果差异(不关注写法差异,如2*a和a*2视为相同)。

注意事项

  • 示例表达式为硬编码,实际场景中表达式来自大量其他运算。
  • 并非所有选项组合都存在,表达式名称表是稀疏的。
  • 改用dict存储可能解决问题,但需修改大量代码。
  • 不清楚Symbol类与表达式的正式区别,希望明确该点辅助解决问题。

已尝试方案(未成功)

尝试编写如下函数:

def verify_ratio(vstr1, vstr2):
    """Compare the result of two different computations of the same quantity"""
    ratio = sp.N(sp.parsing.sympy_parser.parse_expr(vstr1)) / sp.parsing.sympy_parser.parse_expr(vstr2)
    print(vstr1 + ' / ' + vstr2, '=', sp.N(ratio))
    return

但无法正常工作,测试代码及输出如下:

import sympy as sp
a, b = sp.symbols('a,b', real=True, positive=True)
expr2 = 1.01 * a**1.01 * b**0.99
print(type(expr2), '->', expr2)
    
expr2b = sp.parsing.sympy_parser.parse_expr('expr2')
print(type(expr2b), '->', expr2b)

expr2c = sp.N(sp.parsing.sympy_parser.parse_expr('expr2'))
print(type(expr2c), '->', expr2c)

expr2d = sp.sympify('expr2')
print(type(expr2d), '->', expr2d)

输出:

<class 'sympy.core.mul.Mul'> -> 1.01*a**1.01*b**0.99
<class 'sympy.core.symbol.Symbol'> -> expr2
<class 'sympy.core.symbol.Symbol'> -> expr2
<class 'sympy.core.symbol.Symbol'> -> expr2

可见parse_expr和sympify均将字符串'expr2'识别为Symbol,而非对应的表达式1.01 * a**1.01 * b**0.99。需要实现将表达式名称字符串转换为对应表达式的功能,并完成比值计算。


解决方案

1. 明确Symbol与表达式的区别

  • Symbol:SymPy中代表变量的基础对象,比如a、b,用来表示未知量,属于sympy.core.symbol.Symbol类型。
  • 表达式(Expression):由Symbol、数字、运算符组合而成的复杂对象,比如1.01*a**1.01*b**0.99属于sympy.core.mul.Mul类型,是多个Symbol和数字的乘积,本质是SymPy中各种运算类的实例。

2. 实现表达式名称字符串转表达式

parse_expr和sympify的作用是解析表达式文本(比如'1.01*a**1.01*b**0.99'),而非获取当前命名空间中已定义的变量。要根据字符串名称获取已定义的表达式,可直接通过Python的命名空间字典(globals()或locals())实现。

3. 正确的比值计算函数

import sympy as sp

def verify_ratio(vstr1, vstr2):
    # 从全局命名空间获取对应的表达式对象
    expr1 = globals().get(vstr1)
    expr2 = globals().get(vstr2)
    
    # 处理表达式不存在的情况
    if expr1 is None:
        raise ValueError(f"表达式 '{vstr1}' 未定义")
    if expr2 is None:
        raise ValueError(f"表达式 '{vstr2}' 未定义")
    
    # 计算比值并简化(自动处理写法差异,如2*a和a*2视为相同)
    ratio = sp.simplify(expr1 / expr2)
    # 转换为数值结果(若比值为常数)
    numeric_ratio = sp.N(ratio)
    
    print(f"{vstr1} / {vstr2} = {numeric_ratio}")
    return numeric_ratio

4. 测试示例

a, b = sp.symbols('a,b', real=True, positive=True)
Xcharles_YclassA_Zregion1 = 1.01 * a**1.01 * b**0.99
Xbob_YclassA_Zregion1 = 1.009999 * a**1.01 * b**0.99

# 调用函数
verify_ratio('Xcharles_YclassA_Zregion1', 'Xbob_YclassA_Zregion1')

输出:

Xcharles_YclassA_Zregion1 / Xbob_YclassA_Zregion1 = 1.00000099009999

补充说明

  • 如果表达式是在函数内部定义的,需将globals()替换为locals(),确保从当前局部命名空间获取变量。
  • 若担心全局命名空间污染,可提前将所有表达式存入一个字典(比如expr_dict = {'Xcharles_YclassA_Zregion1': ...}),然后通过expr_dict.get(vstr1)获取,这是更规范的方式,但需要修改部分代码来填充字典。

内容的提问来源于stack exchange,提问作者sancho.s ReinstateMonicaCellio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 08:25:23