对于一个项目,我想使用sympy
来构造和计算离散数量的数据点的高斯分布的最大似然。
我可以在mathworld找到我遵循的方法。
但是当我尝试在带有Product
和/或Sum
的符号表达式中使用数组时遇到了麻烦。以下是我之前尝试的简化版本。
在Anaconda的Yupyter的笔记本中,我创建了一个python数组,比如x
:
N = 10
x = range(N)
我想在x
中的符号表达式中使用sympy
,如下所示:
from sympy import *, Symbol
i = Symbol('i', integer=True)
mu = Symbol('mu')
s = Sum( (x[i]-mu)**2, (i, 0, N-1))
但这不起作用,因为评估单元格导致:
TypeError Traceback (most recent call last)
<ipython-input-1-19c174235872> in <module>()
7 mu = Symbol('mu')
8
----> 9 s = Sum( (x[i]-mu)**2, (i,0,N-1))
TypeError: list indices must be integers, not Symbol
另一次尝试:
X = MatrixSymbol(X, 1, N) # No clue how to convince `sympy` to use 1-dimensional arrays using only one index.
s = Sum((X[0,i]-mu)**2, (i,0,N-1))
s.doit()
给出:
(-mu + X[0, 0])**2 + (-mu + X[0, 1])**2 + (-mu + X[0, 2])**2 + (-mu + X[0, 3])**2 + (-mu + X[0, 4])**2 + (-mu + X[0, 5])**2 + (-mu + X[0, 6])**2 + (-mu + X[0, 7])**2 + (-mu + X[0, 8])**2 + (-mu + X[0, 9])**2
有点工作,但如何将x
的真实值纳入该符号表达式,即将X[0,i]
中的每一个替换为x[i]
的值}?
另一次尝试:
X = Matrix(1,N, range(N))
s = Sum((X[i]-mu)**2, (i, 0, N-1))
s.doit()
现在python / sympy非常不高兴:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-7-6d106fb975e1> in <module>()
1 X = Matrix(1,N, range(N))
2
----> 3 s = Sum((X[i]-mu)**2, (i, 0, N-1))
4 s.doit()
/Users/twan/anaconda/lib/python2.7/site-packages/sympy/matrices/dense.pyc in __getitem__(self, key)
94 if isinstance(key, slice):
95 return self._mat[key]
---> 96 return self._mat[a2idx(key)]
97
98 def __setitem__(self, key, value):
/Users/twan/anaconda/lib/python2.7/site-packages/sympy/matrices/matrices.pyc in a2idx(j, n)
4412 j = j.__index__()
4413 except AttributeError:
-> 4414 raise IndexError("Invalid index a[%r]" % (j, ))
4415 if n is not None:
4416 if j < 0:
IndexError: Invalid index a[i]
我不知道该尝试什么,我在这里遇到sympy
。我很好奇我是否遇到sympy
的限制因为统计中非常重要的计算。
修改:
我应该提到要求将被发展为(E**(-((x-mu)**2)/(2 * s**2)))/(s * sqrt(2 * pi))
。取幂使得问题略有不同。
尽管@ unutbu的解决方案对我不起作用,但尝试使用该建议指出我应该将域限制为实数。
@Marshmallow的建议确实有效,完整的解决方案现在是:
from sympy import symbols, E, pi, sqrt, init_printing
from sympy import diff, IndexedBase
from sympy.solvers import solve
x, mu = symbols('x mu', real=True)
sigma = symbols('sigma', real=True, positive=True)
bell = (E**(-((x-mu)**2)/(2 * sigma**2)))/(sigma * sqrt(2 * pi))
def likelihood(factor, xs):
return np.prod([factor.subs(x,i) for i in xs])
def loglikelihood(factor, xs):
return expand_log(log(likelihood(factor, xs)))
N = 3
X = IndexedBase('X')
Xs = [X[i] for i in range(N)]
solve(diff(loglikelihood(gauss,Xs), mu).subs(sigma, 1), mu)
非常感谢@Marshmellow和@unutbu。
答案 0 :(得分:1)
由于您的列表x
是数字,因此您无需使用符号和来处理它。只需使用Python的列表理解对(xi-mu)**2
的列表求和:
from sympy import *
N = 10
x = range(N)
mu = Symbol('mu')
s = sum([(xi-mu)**2 for xi in x])
print(s)
print(s.diff(mu)) # to show this is a symbolic expression
输出:
mu**2 + (-mu + 1)**2 + (-mu + 2)**2 + (-mu + 3)**2 + (-mu + 4)**2 + (-mu + 5)**2 + (-mu + 6)**2 + (-mu + 7)**2 + (-mu + 8)**2 + (-mu + 9)**2
20*mu - 90
答案 1 :(得分:1)
您可以使用IndexedBase
来表示包含元素的数组。
X = sy.IndexedBase('X')
s = sy.Sum((X[i]-mu)**2, (i, 0, N-1))
可以使用lambdify
将NmPy数组替换为SymPy符号。在这种情况下,我们希望用来自NumPy数组的值替换X[i]
。
目前,lambdify
can not be applied to IndexedBase
个对象。但它可以应用于DeferredVector
。例如:
import sympy as sy
import numpy as np
i = sy.Symbol('i', integer=True)
mu = sy.Symbol('mu')
N = 10
X = sy.IndexedBase('X')
s = sy.Sum(sy.exp((X[i]-mu)**2), (i, 0, N-1))
f = sy.lambdify(sy.DeferredVector('X'), s, 'sympy')
x = np.arange(N)
print(f(x))
打印
exp(mu**2) + exp((-mu + 1)**2) + exp((-mu + 2)**2) + exp((-mu + 3)**2) + exp((-mu + 4)**2) + exp((-mu + 5)**2) + exp((-mu + 6)**2) + exp((-mu + 7)**2) + exp((-mu + 8)**2) + exp((-mu + 9)**2)
请注意,由于f(x)
仍然是SymPy表达式,因此我使用'sympy'
作为lambdify
的第三个参数,以便sy.exp
不会被数字{{1}替换功能。