Issue
I'd like to sequentially update a covariance matrix of a multivariate Gaussian distribution, but getting an AttributeError. Below is a simple piece of code to reproduce the error:
import numpy as np
from scipy.stats import multivariate_normal
# Initial mean
init_pose = np.array([0, 0, 0]).T
# Multi-variate Gaussian
belief = multivariate_normal(mean=init_pose, cov=np.diag([1e-10, 1e-10, 1e-10]))
print(belief.mean, belief.cov)
# Update mean and covariance
belief.mean = np.array([10, 20, 30]).T
belief.cov = np.diag([1, 2, 3])
The error messages are:
AttributeError Traceback (most recent call last)
Cell In[42], line 7
5 print(belief.mean, belief.cov)
6 belief.mean = np.array([10, 20, 30]).T
----> 7 belief.cov = np.diag([1, 2, 3])
8 print(belief.mean, belief.cov)
AttributeError: can't set attribute
I checked the attributes of the variable, belief
, by using belief.__dict__
, which gives the following:
{'_dist': <scipy.stats._multivariate.multivariate_normal_gen object at 0x2b84d81cfc10>,
'dim': 3, 'mean': array([0., 0., 0.]),
'cov_object': <scipy.stats._covariance.CovViaPSD object at 0x2b84d81cfbe0>,
'allow_singular': False, 'maxpts': 3000000, 'abseps': 1e-05, 'releps': 1e-05}
As the error suggests, the variable doesn't have cov
attribute but has cov_object
instead. Is there any way to update the covariance using a numpy array?
Solution
Updating the covariance matrix is not officially supported in the existing infrastructure. cov
is a read-only attribute as you can see in the source. (This is not documented, though, and that is one of many known issues with the multivariate distributions.)
You can (although not officially supported) update the cov_object
attribute you found. If you use stats.Covariance
, which I'd recommend, this might look like:
import numpy as np
from scipy.stats import multivariate_normal, Covariance
x = [1, 1, 1]
# Initial mean and covariance
init_pose = np.array([0, 0, 0]).T
cov = Covariance.from_diagonal(np.array([1, 2, 3]))
# Multi-variate Gaussian
belief = multivariate_normal(mean=init_pose, cov=cov)
belief.pdf(x) # 0.01036457019516129
# Update covariance
cov = Covariance.from_diagonal(np.array([2, 4, 6]))
belief.cov_object = cov
belief.pdf(x) # 0.005795060058469202
# same as
# multivariate_normal(mean=init_pose, cov=cov).pdf(x)
As long as your new mean
and cov_object
don't violate the conditions you can infer from _process_parameters_Covariance
(basically just consistent dimensionality), I expect it to work correctly. If you change the mean
and cov_object
to represent a multivariate normal in a different number of dimensions, you'll also need to update the dim
attribute accordingly.
In the comments, you wrote:
However, I don't know how to define a non-diagonal covariance matrix.
Covariance
has several other options for defining your covariance matrix. The SciPy documentation appears to have certificate issues ATM, but you will find other methods like from_precision
, from_cholesky
, and from_eigendecomposition
that will work for more general covariance matrices.
So, does that mean a value cannot be set to the covariance in this way because the covariance is a property and not an attribute?
Well, it's because it's a read-only attribute created using the @property
decoratory; it's not a normal attribute defined in, say, the __init__
method like self.cov = cov
.
Answered By - Matt Haberland
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.