Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support using pandas dataframe to specify dlm #46

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ build/
*.sh~
*.csv~
dist/
pydlm.egg-info/
pydlm.egg-info/
.idea
*/__pycache__/
6 changes: 3 additions & 3 deletions pydlm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
__all__ = ['dlm', 'trend', 'seasonality', 'dynamic', 'autoReg', 'longSeason', 'modelTuner']

from pydlm.dlm import dlm
from pydlm.modeler.trends import trend
from pydlm.modeler.seasonality import seasonality
from pydlm.modeler.dynamic import dynamic
from pydlm.modeler.autoReg import autoReg
from pydlm.modeler.dynamic import dynamic
from pydlm.modeler.longSeason import longSeason
from pydlm.modeler.seasonality import seasonality
from pydlm.modeler.trends import trend
from pydlm.tuner.dlmTuner import modelTuner
7 changes: 2 additions & 5 deletions pydlm/access/_dlmGet.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

"""
from numpy import dot

from pydlm.core._dlm import _dlm


Expand All @@ -21,7 +22,6 @@ class _dlmGet(_dlm):
_getComponentVar: get the variance of a given component
"""


# function to get the corresponding latent state
def _getLatentState(self, name, filterType, start, end):
""" Get the latent states of a given component.
Expand Down Expand Up @@ -50,7 +50,6 @@ def _getLatentState(self, name, filterType, start, end):
else:
raise NameError('Incorrect filter type')


# function to get the corresponding latent covariance
def _getLatentCov(self, name, filterType, start, end):
""" Get the latent covariance of a given component.
Expand All @@ -69,7 +68,7 @@ def _getLatentCov(self, name, filterType, start, end):
end += 1
indx = self.builder.componentIndex[name]
patten = lambda x: x if x is None \
else x[indx[0]:(indx[1] + 1), indx[0]:(indx[1] + 1)]
else x[indx[0]:(indx[1] + 1), indx[0]:(indx[1] + 1)]

if filterType == 'forwardFilter':
return list(map(patten, self.result.filteredCov[start:end]))
Expand All @@ -80,7 +79,6 @@ def _getLatentCov(self, name, filterType, start, end):
else:
raise NameError('Incorrect filter type')


# function to get the component mean
def _getComponentMean(self, name, filterType, start, end):
""" Get the mean of a given component.
Expand Down Expand Up @@ -111,7 +109,6 @@ def _getComponentMean(self, name, filterType, start, end):
componentState[k]).tolist()[0][0])
return result


# function to get the component variance
def _getComponentVar(self, name, filterType, start, end):
""" Get the variance of a given component.
Expand Down
20 changes: 7 additions & 13 deletions pydlm/access/dlmAccessMod.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from copy import deepcopy
from pydlm.base.tools import getInterval

from pydlm.access._dlmGet import _dlmGet
from pydlm.base.tools import getInterval


class dlmAccessModule(_dlmGet):
""" A dlm module for all the access methods
"""


def getAll(self):
""" get all the _result class which contains all results

Expand All @@ -17,7 +17,6 @@ def getAll(self):
"""
return deepcopy(self.result)


def getMean(self, filterType='forwardFilter', name='main'):
""" get mean for data or component.

Expand All @@ -39,7 +38,7 @@ def getMean(self, filterType='forwardFilter', name='main'):
"""
# get the working date
start, end = self._checkAndGetWorkingDates(filterType=filterType)
end += 1 # To get the result for the last date.
end += 1 # To get the result for the last date.
# get the mean for the fitlered data
if name == 'main':
# get out of the matrix form
Expand All @@ -61,7 +60,6 @@ def getMean(self, filterType='forwardFilter', name='main'):
filterType=filterType,
start=start, end=(end - 1))


def getVar(self, filterType='forwardFilter', name='main'):
""" get the variance for data or component.

Expand Down Expand Up @@ -105,7 +103,6 @@ def getVar(self, filterType='forwardFilter', name='main'):
return self._getComponentVar(name=name, filterType=filterType,
start=start, end=(end - 1))


def getResidual(self, filterType='forwardFilter'):
""" get the residuals for data after filtering or smoothing.

Expand All @@ -123,7 +120,7 @@ def getResidual(self, filterType='forwardFilter'):
"""
# get the working date
start, end = self._checkAndGetWorkingDates(filterType=filterType)
end += 1 # To get the result for the last date.
end += 1 # To get the result for the last date.
# get the mean for the fitlered data
# get out of the matrix form
if filterType == 'forwardFilter':
Expand All @@ -141,7 +138,6 @@ def getResidual(self, filterType='forwardFilter'):
else:
raise NameError('Incorrect filter type.')


def getInterval(self, p=0.95, filterType='forwardFilter', name='main'):
""" get the confidence interval for data or component.

Expand Down Expand Up @@ -202,7 +198,6 @@ def getInterval(self, p=0.95, filterType='forwardFilter', name='main'):
upper, lower = getInterval(compMean, compVar, p)
return (upper, lower)


def getLatentState(self, filterType='forwardFilter', name='all'):
""" get the latent states for different components and filters.

Expand Down Expand Up @@ -230,15 +225,15 @@ def getLatentState(self, filterType='forwardFilter', name='all'):
if name == 'all':
if filterType == 'forwardFilter':
return list(map(lambda x: x if x is None
else self._1DmatrixToArray(x),
else self._1DmatrixToArray(x),
self.result.filteredState[start:end]))
elif filterType == 'backwardSmoother':
return list(map(lambda x: x if x is None
else self._1DmatrixToArray(x),
else self._1DmatrixToArray(x),
self.result.smoothedState[start:end]))
elif filterType == 'predict':
return list(map(lambda x: x if x is None
else self._1DmatrixToArray(x),
else self._1DmatrixToArray(x),
self.result.smoothedState[start:end]))
else:
raise NameError('Incorrect filter type.')
Expand All @@ -249,7 +244,6 @@ def getLatentState(self, filterType='forwardFilter', name='all'):
self._getLatentState(name=name, filterType=filterType,
start=start, end=(end - 1))))


def getLatentCov(self, filterType='forwardFilter', name='all'):
""" get the error covariance for different components and
filters.
Expand Down
8 changes: 4 additions & 4 deletions pydlm/base/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# the base kalmanFilter for filtering

#__all__ = ['kalmanFilter', 'baseModel', 'tools']
# __all__ = ['kalmanFilter', 'baseModel', 'tools']

#import pydlm.base.kalmanFilter
#from .tools import tools
#from .baseModel import baseModel
# import pydlm.base.kalmanFilter
# from .tools import tools
# from .baseModel import baseModel
12 changes: 5 additions & 7 deletions pydlm/base/baseModel.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"""
# dependencies
import numpy as np

import pydlm.base.tools as tl


Expand All @@ -34,10 +35,9 @@ class baseModel:
validation: validate the matrix dimensions are consistent.
"""


# define the components of a baseModel
def __init__(self, transition = None, evaluation = None, noiseVar = None, \
sysVar = None, innovation = None, state = None, df = None):
def __init__(self, transition=None, evaluation=None, noiseVar=None, \
sysVar=None, innovation=None, state=None, df=None):
self.transition = transition
self.evaluation = evaluation
self.noiseVar = noiseVar
Expand All @@ -51,7 +51,6 @@ def __init__(self, transition = None, evaluation = None, noiseVar = None, \
# a hidden data field used only for model prediction
self.prediction = __model__()


# initialize the observation mean and variance
def initializeObservation(self):
""" Initialize the value of obs and obsVar
Expand All @@ -62,7 +61,6 @@ def initializeObservation(self):
self.obsVar = np.dot(np.dot(self.evaluation, self.sysVar), self.evaluation.T) \
+ self.noiseVar


# checking if the dimension matches with each other
def validation(self):
""" Validate the model components are consistent
Expand All @@ -81,12 +79,12 @@ def validation(self):
tl.checker.checkVectorDimension(self.evaluation, self.transition)
tl.checker.checkVectorDimension(self.state, self.transition)


# define an inner class to store intermediate results
class __model__:

# to store result for prediction
def __init__(self, step = 0, state = None, obs = None, sysVar = None, obsVar = None):
def __init__(self, step=0, state=None, obs=None, sysVar=None, obsVar=None):
self.step = 0
self.state = state
self.obs = obs
Expand Down
33 changes: 11 additions & 22 deletions pydlm/base/kalmanFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
"""
# This code take care of the Kalman filter
import numpy as np

import pydlm.base.tools as tl


# Define the class of Kalman filter which offers a forward filter
# backward smoother and backward sampler for one-step move

Expand All @@ -38,7 +40,6 @@ class kalmanFilter:
updateDiscount: for updating the discount factors
"""


def __init__(self, discount=[0.99], \
updateInnovation='whole',
index=None):
Expand All @@ -55,8 +56,7 @@ def __init__(self, discount=[0.99], \
self.updateInnovation = updateInnovation
self.index = index


def predict(self, model, dealWithMissingEvaluation = False):
def predict(self, model, dealWithMissingEvaluation=False):
""" Predict the next states of the model by one step

Args:
Expand Down Expand Up @@ -98,7 +98,7 @@ def predict(self, model, dealWithMissingEvaluation = False):
model.prediction.state = np.dot(model.transition, model.prediction.state)
model.prediction.obs = np.dot(model.evaluation, model.prediction.state)
model.prediction.sysVar = np.dot(np.dot(model.transition, \
model.prediction.sysVar),\
model.prediction.sysVar), \
model.transition.T)
model.prediction.obsVar = np.dot(np.dot(model.evaluation, \
model.prediction.sysVar), \
Expand All @@ -109,8 +109,7 @@ def predict(self, model, dealWithMissingEvaluation = False):
if dealWithMissingEvaluation:
self._recoverTransitionAndEvaluation(model, loc)


def forwardFilter(self, model, y, dealWithMissingEvaluation = False):
def forwardFilter(self, model, y, dealWithMissingEvaluation=False):
""" The forwardFilter used to run one step filtering given new data

Args:
Expand Down Expand Up @@ -144,7 +143,7 @@ def forwardFilter(self, model, y, dealWithMissingEvaluation = False):

# update new states
model.df += 1
lastNoiseVar = model.noiseVar # for updating model.sysVar
lastNoiseVar = model.noiseVar # for updating model.sysVar
model.noiseVar = model.noiseVar * \
(1.0 - 1.0 / model.df + \
err * err / model.df / model.prediction.obsVar)
Expand Down Expand Up @@ -181,7 +180,6 @@ def forwardFilter(self, model, y, dealWithMissingEvaluation = False):
if dealWithMissingEvaluation:
self._recoverTransitionAndEvaluation(model, loc)


# The backward smoother for a given unsmoothed states at time t
# what model should store:
# model.state: the last smoothed states (t + 1)
Expand Down Expand Up @@ -234,10 +232,9 @@ def backwardSmoother(self, model, rawState, rawSysVar):
model.evaluation.T) + model.noiseVar

# recover the evaluation and the transition matrix
#if dealWithMissingEvaluation:
# if dealWithMissingEvaluation:
# self._recoverTransitionAndEvaluation(model, loc)


def backwardSampler(self, model, rawState, rawSysVar):
""" The backwardSampler for one step backward sampling

Expand Down Expand Up @@ -275,8 +272,7 @@ def backwardSampler(self, model, rawState, rawSysVar):
model.obsVar = np.dot(np.dot(model.evaluation, model.sysVar), \
model.evaluation.T) + model.noiseVar
model.obs = np.matrix(np.random.multivariate_normal(model.obs.A1, \
model.obsVar)).T

model.obsVar)).T

# for updating the discounting factor
def updateDiscount(self, newDiscount):
Expand All @@ -289,7 +285,6 @@ def updateDiscount(self, newDiscount):
self.__checkDiscount__(newDiscount)
self.discount = np.matrix(np.diag(1 / np.sqrt(newDiscount)))


def __checkDiscount__(self, discount):
""" Check whether the discount fact is within (0, 1)

Expand All @@ -299,16 +294,14 @@ def __checkDiscount__(self, discount):
if discount[i] < 0 or discount[i] > 1:
raise tl.matrixErrors('discount factor must be between 0 and 1')


# update the innovation
def __updateInnovation__(self, model):
""" update the innovation matrix of the model

"""

model.innovation = np.dot(np.dot(self.discount, model.prediction.sysVar), \
self.discount) - model.prediction.sysVar

self.discount) - model.prediction.sysVar

# update the innovation
def __updateInnovation2__(self, model):
Expand All @@ -319,13 +312,12 @@ def __updateInnovation2__(self, model):
"""

innovation = np.dot(np.dot(self.discount, model.prediction.sysVar), \
self.discount) - model.prediction.sysVar
self.discount) - model.prediction.sysVar
model.innovation = np.matrix(np.zeros(innovation.shape))
for name in self.index:
indx = self.index[name]
model.innovation[indx[0]: (indx[1] + 1), indx[0]: (indx[1] + 1)] = \
innovation[indx[0]: (indx[1] + 1), indx[0]: (indx[1] + 1)]

innovation[indx[0]: (indx[1] + 1), indx[0]: (indx[1] + 1)]

# a generalized inverse of matrix A
def _gInverse(self, A):
Expand All @@ -334,7 +326,6 @@ def _gInverse(self, A):
"""
return np.linalg.pinv(A)


def _modifyTransitionAccordingToMissingValue(self, model):
""" When evaluation contains None value, we modify the corresponding entries
in the transition to deal with the missing value
Expand All @@ -348,7 +339,6 @@ def _modifyTransitionAccordingToMissingValue(self, model):
model.evaluation[0, i] = 0.0
return loc


def _recoverTransitionAndEvaluation(self, model, loc):
""" We recover the transition and evaluation use the results from
_modifyTransitionAccordingToMissingValue
Expand All @@ -357,4 +347,3 @@ def _recoverTransitionAndEvaluation(self, model, loc):
for i in loc:
model.evaluation[0, i] = None
model.transition[i, i] = 1.0

Loading