def test_acm_1d(self): """Test autocorrelation matrix for 1D input""" v = np.array([1, 2, 0, 0, 1, 2, 0, 0]) acm = lambda l: datatools.acm(v, l) self.assertEqual(np.mean(v**2), acm(0)) for l in range(1, 6): self.assertEqual(np.correlate(v[l:], v[:-l]) / (len(v) - l), acm(l))
def test_acm_1d(self): """Test autocorrelation matrix for 1D input""" v = np.array([1, 2, 0, 0, 1, 2, 0, 0]) acm = lambda l: datatools.acm(v, l) self.assertEqual(np.mean(v**2), acm(0)) for l in range(1, 6): self.assertEqual( np.correlate(v[l:], v[:-l]) / (len(v) - l), acm(l))
def from_yw(self, acms): """Determine VAR model from autocorrelation matrices by solving the Yule-Walker equations. Parameters ---------- acms : array, shape (n_lags, n_channels, n_channels) acms[l] contains the autocorrelation matrix at lag l. The highest lag must equal the model order. Returns ------- self : :class:`VAR` The :class:`VAR` object to facilitate method chaining (see usage example). """ if len(acms) != self.p + 1: raise ValueError("Number of autocorrelation matrices ({}) does not" " match model order ({}) + 1.".format( len(acms), self.p)) n_channels = acms[0].shape[0] acm = lambda l: acms[l] if l >= 0 else acms[-l].T r = np.concatenate(acms[1:], 0) rr = np.array([[acm(m - k) for k in range(self.p)] for m in range(self.p)]) rr = np.concatenate(np.concatenate(rr, -2), -1) c = sp.linalg.solve(rr, r) # calculate residual covariance r = acm(0) for k in range(self.p): bs = k * n_channels r -= np.dot(c[bs:bs + n_channels, :].T, acm(k + 1)) self.coef = np.concatenate( [c[m::n_channels, :] for m in range(n_channels)]).T self.rescov = r return self
def from_yw(self, acms): """Determine VAR model from autocorrelation matrices by solving the Yule-Walker equations. Parameters ---------- acms : array, shape (n_lags, n_channels, n_channels) acms[l] contains the autocorrelation matrix at lag l. The highest lag must equal the model order. Returns ------- self : :class:`VAR` The :class:`VAR` object to facilitate method chaining (see usage example). """ if len(acms) != self.p + 1: raise ValueError("Number of autocorrelation matrices ({}) does not" " match model order ({}) + 1.".format(len(acms), self.p)) n_channels = acms[0].shape[0] acm = lambda l: acms[l] if l >= 0 else acms[-l].T r = np.concatenate(acms[1:], 0) rr = np.array([[acm(m-k) for k in range(self.p)] for m in range(self.p)]) rr = np.concatenate(np.concatenate(rr, -2), -1) c = sp.linalg.solve(rr, r) # calculate residual covariance r = acm(0) for k in range(self.p): bs = k * n_channels r -= np.dot(c[bs:bs + n_channels, :].T, acm(k + 1)) self.coef = np.concatenate([c[m::n_channels, :] for m in range(n_channels)]).T self.rescov = r return self
def _calc_q_statistic(x, h, nt): """Calculate Portmanteau statistics up to a lag of h. """ t, m, n = x.shape # covariance matrix of x c0 = acm(x, 0) # LU factorization of covariance matrix c0f = sp.linalg.lu_factor(c0, overwrite_a=False, check_finite=True) q = np.zeros((3, h + 1)) for l in range(1, h + 1): cl = acm(x, l) # calculate tr(cl' * c0^-1 * cl * c0^-1) a = sp.linalg.lu_solve(c0f, cl) b = sp.linalg.lu_solve(c0f, cl.T) tmp = a.dot(b).trace() # Box-Pierce q[0, l] = tmp # Ljung-Box q[1, l] = tmp / (nt - l) # Li-McLeod q[2, l] = tmp q *= nt q[1, :] *= (nt + 2) q = np.cumsum(q, axis=1) for l in range(1, h + 1): q[2, l] = q[0, l] + m * m * l * (l + 1) / (2 * nt) return q
def _calc_q_statistic(x, h, nt): """Calculate Portmanteau statistics up to a lag of h. """ t, m, n = x.shape # covariance matrix of x c0 = acm(x, 0) # LU factorization of covariance matrix c0f = sp.linalg.lu_factor(c0, overwrite_a=False, check_finite=True) q = np.zeros((3, h + 1)) for l in range(1, h + 1): cl = acm(x, l) # calculate tr(cl' * c0^-1 * cl * c0^-1) a = sp.linalg.lu_solve(c0f, cl) b = sp.linalg.lu_solve(c0f, cl.T) tmp = a.dot(b).trace() # Box-Pierce q[0, l] = tmp # Ljung-Box q[1, l] = tmp / (nt - l) # Li-McLeod q[2, l] = tmp q *= nt q[1, :] *= (nt + 2) q = np.cumsum(q, axis=1) for l in range(1, h+1): q[2, l] = q[0, l] + m * m * l * (l + 1) / (2 * nt) return q
def test_yulewalker(self): np.random.seed(7353) x, var0 = self.generate_data([[1, 2], [3, 4]]) acms = [acm(x, l) for l in range(var0.p+1)] var = VAR(var0.p) var.from_yw(acms) assert_allclose(var0.coef, var.coef, rtol=1e-2, atol=1e-2) # that limit is rather generous, but we don't want tests to fail due to random variation self.assertTrue(np.all(np.abs(var0.coef - var.coef) < 0.02)) self.assertTrue(np.all(np.abs(var0.rescov - var.rescov) < 0.02))