如何在sympy中提取所有系数

59
您可以使用coeff()函数来获取特定项的系数。
x, a = symbols("x, a")
expr = 3 + x + x**2 + a*x*2
expr.coeff(x)
# 2*a + 1

我想提取所有 x、x**2(等等)的系数,例如:

# for example
expr.coefficients(x)
# want {1: 3, x: (2*a + 1), x**2: 1}

有一个方法as_coefficients_dict(),但似乎它不能按照我想要的方式工作。

expr.as_coefficients_dict()
# {1: 3, x: 1, x**2: 1, a*x: 2}
expr.collect(x).as_coefficients_dict()
# {1: 3, x**2: 1, x*(2*a + 1): 1}

1
你的表达式 expr 有限制吗?例如,它总是一个多项式吗?它的次数受到限制吗? - Carsten
1
@Carsten 如果有一种“无限”的方法就太好了,实际上我认为一定有,特别是因为collect()(可能)是无限的,但至少需要一种适用于多项式的方法。 - akai
5个回答

65

all_coeffs() 有时比使用 coeffs() 更好,因为它们的输出结果不同。 coeffs() 返回一个包含具有值的所有系数的列表,并忽略系数为 0 的项,而 all_coeffs() 则返回所有系数,包括系数为零的项。

>>> a = Poly(x**3 + a*x**2 - b, x)
>>> a.coeffs()
[1, a, -b]

>>> a.all_coeffs()
[1, a, 0, -b]

11
谢谢。我被coeffs()函数忽略了零系数的情况所困扰。值得注意的是,当使用numpy多项式时,它使用相反的顺序,因此在使用numpy多项式时进行a.reverse()操作是值得的。 - Alexander McFarlane
我可以问一下,当你写 a = Poly(x**3 + a*x**2 - b, x) 时发生了什么?看起来你输入了一个带有 a 的方程,但我猜这不是你正在做的事情,因为 SymPy 不知道你正在将多项式赋值给一个同名的变量 "a"。但是你选择这个名称是否有特定的原因,而不是例如称其为 "p",表示多项式?否则,我觉得有点混淆。 - HelloGoodbye

47

最简单的方法是使用Poly

>>> a = Poly(expr, x)
>>> a.coeffs()
[1, 2*a + 1, 3]

6
请注意,这会隐藏零项。如果您执行Poly(x**2 + 1).coeffs(),将得到[1,1]而不是[1,0,1] - Thomas Ahle

6

使用Poly可以处理系数的集合,然后使用Expr.as_independent将单项式分离为相关部分和独立部分:

def codict(expr, *x):
  collected = Poly(expr, *x).as_expr()
  i, d = collected.as_independent(*x, as_Add=True)
  rv = dict(i.as_independent(*x, as_Mul=True)[::-1] for i in Add.make_args(d))
  if i:
      assert 1 not in rv
      rv.update({S.One: i})
  return rv

>>> var('a x z y')
(a, x, z, y)
>>> expr = 3 + x + x**2 + a*x*2
>>> codict(expr, x)
{x**2: 1, x: 2*a + 1, 1: 3}
>>> codict(expr+y+z, x)
{x**2: 1, x: 2*a + 1, 1: y + z + 3}
>>> codict(expr+y+z, x,y)
{y: 1, x**2: 1, x: 2*a + 1, 1: z + 3}
>>> codict(expr+y+z, x,y,z)
{y: 1, z: 1, x**2: 1, x: 2*a + 1, 1: 3}

1
这个不行。有时候字典里会有多条记录的键为1,所以只存储最后一条记录。你需要对字典中所有相同键的记录求和。 - user9413641
1
谢谢。代码和示例已经更新。 - smichr

4

您可以使用字典推导式来实现:

dict = {x**p: expr.collect(x).coeff(x**p) for p in range(1,n)}

n是最高幂次+1,例如这里n=3。所以你会得到列表[1,2]

这将给出

dict = {x: (2*a+1), x**2: 1}

然后您可以使用以下方式添加单个术语:
dict[1] = 3

So

 dict = {1:3,x:(2*a+1),x**2:1}

您也可以尝试以下方法:
a = list(reversed(expr.collect(x).as_ordered_terms()))
dict = {x**p: a[p],coeff(x**p) for p in range(1,n)}
dict[1] = a[0] # Would only apply if there is single term such as the 3 in the example

其中n是最高指数+1。


作为一个例外,这适用于series(),而Poly()则不适用。另外,你也可以写.coeff(x, p),它允许p=0(常数项)。 - user202729

0

基于RDizzl3的回答,我进行了如下修改:

d_c = collect(my_poly, x)
# replace n by highest power + 1 
dict = {x**p: d_c.coeff(x, p) for p in range(0,n)}

这不会跳过常量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接