Пример #1
0
    def _predict_update_no_noise(self, t):
        # extract t-1 parameters (時刻t-1のパラメータ取り出す)
        F = _last_dims(self.F, t - 1, 2)
        Q = _last_dims(self.Q, t - 1, 2)
        b = _last_dims(self.b, t - 1, 1)

        # predict t distribution (時刻tの予測分布の計算)
        self.x_pred[t] = F @ self.x_filt[t - 1] + b
        self.V_pred[t] = F @ self.V_filt[t - 1] @ F.T + Q
Пример #2
0
    def smooth(self):
        '''
        T : length of data y (時系列の長さ)
        x_smooth [n_time, n_dim_sys] {numpy-array, float}
            : mean of hidden state distributions for times
             [0...n_timesteps-1] given all observations
            時刻 t における状態変数の平滑化期待値 [時間軸,状態変数軸]
        V_smooth [n_time, n_dim_sys, n_dim_sys] {numpy-array, float}
            : covariances of hidden state distributions for times
             [0...n_timesteps-1] given all observations
            時刻 t における状態変数の平滑化共分散 [時間軸,状態変数軸,状態変数軸]
        A [n_dim_sys, n_dim_sys] {numpy-array, float}
            : fixed interval smoothed gain
            固定区間平滑化ゲイン [時間軸,状態変数軸,状態変数軸]
        '''

        # filter が実行されていない場合は実行
        try:
            self.x_pred[0]
        except:
            self.filter()

        T = self.y.shape[0]
        self.x_smooth = np.zeros((T, self.n_dim_sys), dtype=self.dtype)
        self.V_smooth = np.zeros((T, self.n_dim_sys, self.n_dim_sys),
                                 dtype=self.dtype)
        A = np.zeros((self.n_dim_sys, self.n_dim_sys), dtype=self.dtype)

        self.x_smooth[-1] = self.x_filt[-1]
        self.V_smooth[-1] = self.V_filt[-1]

        # t in [0, T-2] (tが1~Tの逆順であることに注意)
        for t in reversed(range(T - 1)):
            # 時間を可視化
            print("\r smooth calculating... t={}".format(T - t) + "/" + str(T),
                  end="")

            # 時刻 t のパラメータを取り出す
            F = _last_dims(self.F, t, 2)

            # 固定区間平滑ゲインの計算
            A = np.dot(self.V_filt[t],
                       np.dot(F.T, linalg.pinv(self.V_pred[t + 1])))

            # 固定区間平滑化
            self.x_smooth[t] = self.x_filt[t] \
                + np.dot(A, self.x_smooth[t + 1] - self.x_pred[t + 1])
            self.V_smooth[t] = self.V_filt[t] \
                + np.dot(A, np.dot(self.V_smooth[t + 1] - self.V_pred[t + 1], A.T))
Пример #3
0
    def _sigma_pair_smooth(self):
        '''
        T {int} : length of y (時系列の長さ) 
        V_pair [n_time, n_dim_sys, n_dim_sys] {numpy-array, float}
            : Covariance between hidden states at times t and t-1
             for t = [1...n_timesteps-1].  Time 0 is ignored.
            時刻t,t-1間の状態の共分散.0は無視する
        '''

        # 時系列の長さ
        T = self.y.shape[0]
        self.x_smooth = np.zeros((T, self.n_dim_sys), dtype=self.dtype)
        self.V_smooth = np.zeros((T, self.n_dim_sys, self.n_dim_sys),
                                 dtype=self.dtype)

        # pairwise covariance
        self.V_pair = np.zeros((T, self.n_dim_sys, self.n_dim_sys),
                               dtype=self.dtype)
        A = np.zeros((self.n_dim_sys, self.n_dim_sys), dtype=self.dtype)

        self.x_smooth[-1] = self.x_filt[-1]
        self.V_smooth[-1] = self.V_filt[-1]

        # t in [0, T-2] (tが1~Tの逆順であることに注意)
        for t in reversed(range(T - 1)):
            # 時間を可視化
            print("\r expectation step calculating... t={}".format(T - t) +
                  "/" + str(T),
                  end="")

            # 時刻 t のパラメータを取り出す
            F = _last_dims(self.F, t, 2)

            # 固定区間平滑ゲインの計算
            A = np.dot(self.V_filt[t],
                       np.dot(F.T, linalg.pinv(self.V_pred[t + 1])))

            # 固定区間平滑化
            self.x_smooth[t] = self.x_filt[t] \
                + np.dot(A, self.x_smooth[t + 1] - self.x_pred[t + 1])
            self.V_smooth[t] = self.V_filt[t] \
                + np.dot(A, np.dot(self.V_smooth[t + 1] - self.V_pred[t + 1], A.T))

            # 時点間共分散行列
            self.V_pair[t + 1] = np.dot(self.V_smooth[t], A.T)
Пример #4
0
    def _predict_update_noise(self, t):
        if np.any(np.ma.getmask(self.y[t - 1])):
            self._predict_update_no_noise(t)
        else:
            # extract t-1 parameters (時刻t-1のパラメータ取り出す)
            F = _last_dims(self.F, t - 1, 2)
            Q = _last_dims(self.Q, t - 1, 2)
            b = _last_dims(self.b, t - 1, 1)
            H = _last_dims(self.H, t - 1, 2)
            d = _last_dims(self.d, t - 1, 1)
            S = _last_dims(self.S, t - 1, 2)
            R = _last_dims(self.R, t - 1, 2)

            # predict t distribution (時刻tの予測分布の計算)
            SR = S @ linalg.pinv(R)
            F_SRH = F - SR @ H
            self.x_pred[t] = F_SRH @ self.x_filt[t - 1] + b + SR @ (
                self.y[t - 1] - d)
            self.V_pred[t] = F_SRH @ self.V_filt[t -
                                                 1] @ F_SRH.T + Q - SR @ S.T
Пример #5
0
    def filter(self):
        '''
        T {int} : 時系列の長さ,length of y
        x_pred_mean [n_time+1, n_dim_sys] {numpy-array, float}
            : mean of x_pred regarding to particles at time t
            時刻 t における x_pred の粒子平均 [時間軸,状態変数軸]
        x_filt_mean [n_time+1, n_dim_sys] {numpy-array, float}
            : mean of x_filt regarding to particles
            時刻 t における状態変数のフィルタ平均 [時間軸,状態変数軸]

        x_pred [n_dim_sys, n_particle]
            : hidden state at time t given observations for each particle
            状態変数の予測アンサンブル [状態変数軸,粒子軸]
        x_filt [n_dim_sys, n_particle] {numpy-array, float}
            : hidden state at time t given observations for each particle
            状態変数のフィルタアンサンブル [状態変数軸,粒子軸]

        w [n_particle] {numpy-array, float}
            : weight lambda of each particle
            各粒子の尤度 [粒子軸]
        v [n_dim_sys, n_particle] {numpy-array, float}
            : system noise particles
            各時刻の状態ノイズ [状態変数軸,粒子軸]
        '''

        # 時系列の長さ, number of time-series data
        T = len(self.y)

        # initial filter, prediction
        self.x_pred_mean = np.zeros((T + 1, self.n_dim_sys), dtype=self.dtype)
        self.x_filt_mean = np.zeros((T + 1, self.n_dim_sys), dtype=self.dtype)
        x_pred = np.zeros((self.n_dim_sys, self.n_particle), dtype=self.dtype)

        # initial distribution
        # sys x particle
        x_filt = rd.multivariate_normal(self.initial_mean,
                                        self.initial_covariance,
                                        size=self.n_particle).T

        # initial setting
        self.x_pred_mean[0] = self.initial_mean
        self.x_filt_mean[0] = self.initial_mean

        for t in range(T):
            print("\r filter calculating... t={}".format(t), end="")

            ## filter update
            # 一期先予測, prediction
            f = _last_dims(self.f, t, 1)[0]

            # システムノイズをパラメトリックに発生, raise parametric system noise
            v = self.q[0](*self.q[1], size=self.n_particle).T

            # アンサンブル予測, ensemble prediction
            # sys x particle
            x_pred = f(*[x_filt, v])

            # mean
            # sys
            self.x_pred_mean[t + 1] = np.mean(x_pred, axis=1)

            # 欠測値の対処, treat missing values
            if np.any(np.ma.getmask(self.y[t])):
                x_filt = x_pred
                self.x_filt_mean[t + 1] = self.x_pred_mean[t + 1]
            else:
                # log likelihood for each particle for y[t]
                # 対数尤度の計算
                lf = self._last_likelihood(self.lf, t)
                lfp = self._last_likelihood(self.lfp, t)
                try:
                    # particle
                    w = lf(self.y[t], x_pred, *lfp)
                except:
                    raise ValueError('you must check likelihood_functions' +
                                     'and parameters.')

                # 発散防止, avoid evaporation
                if self.likelihood_function_is_log_form:
                    w = np.exp(w - np.max(w))
                else:
                    w = w / np.max(w)

                # 重みの正規化, normalization
                # particle
                w = w / np.sum(w)

                # 重み付き平均の計算
                # sys
                self.x_filt_mean[t + 1] = w @ x_pred.T

                # 重み付き共分散の計算
                # sys x particle
                x_pred.T[:] -= self.x_filt_mean[t + 1]

                # sys x sys
                V_filt = np.dot(np.multiply(x_pred, w), x_pred.T)

                # sys x particle
                x_filt = rd.multivariate_normal(self.x_filt_mean[t + 1],
                                                V_filt,
                                                size=self.n_particle).T
Пример #6
0
    def _calc_em(self, given={}):
        '''
        T {int} : length of observation y
        '''

        # length of y
        T = self.y.shape[0]

        # observation_matrices を最初に更新
        if 'observation_matrices' not in given:
            '''math
            y_t : observation, d_t : observation_offsets
            x_t : system, H : observation_matrices

            H &= ( \sum_{t=0}^{T-1} (y_t - d_t) \mathbb{E}[x_t]^T )
             ( \sum_{t=0}^{T-1} \mathbb{E}[x_t x_t^T] )^-1
            '''
            res1 = np.zeros((self.n_dim_obs, self.n_dim_sys), dtype=self.dtype)
            res2 = np.zeros((self.n_dim_sys, self.n_dim_sys), dtype=self.dtype)

            for t in range(T):
                # 欠測がない y_t に関して
                if not np.any(np.ma.getmask(self.y[t])):
                    d = _last_dims(self.d, t, 1)
                    # それぞれの要素毎の積を取りたいので,outer(外積)を使う
                    res1 += np.outer(self.y[t] - d, self.x_smooth[t])
                    res2 += self.V_smooth[t] \
                        + np.outer(self.x_smooth[t], self.x_smooth[t])

            # observation_matrices (H) を更新
            self.H = np.dot(res1, linalg.pinv(res2))

        # 次に observation_covariance を更新
        if 'observation_covariance' not in given:
            '''math
            R : observation_covariance, H_t : observation_matrices,
            x_t : system, d_t : observation_offsets, y_t : observation

            R &= \frac{1}{T} \sum_{t=0}^{T-1}
                [y_t - H_t \mathbb{E}[x_t] - d_t]
                    [y_t - H_t \mathbb{E}[x_t] - d_t]^T
                + H_t Var(x_t) H_t^T
            '''

            # 計算補助
            res1 = np.zeros((self.n_dim_obs, self.n_dim_obs), dtype=self.dtype)
            n_obs = 0

            for t in range(T):
                if not np.any(np.ma.getmask(self.y[t])):
                    H = _last_dims(self.H, t)
                    d = _last_dims(self.d, t, 1)
                    err = self.y[t] - np.dot(H, self.x_smooth[t]) - d
                    res1 += np.outer(err, err) \
                         + np.dot(H, np.dot(self.V_smooth[t], H.T))
                    n_obs += 1

            # temporary
            # tmp = self.R

            # 観測が1回でも確認できた場合
            if n_obs > 0:
                self.R = (1.0 / n_obs) * res1
            else:
                self.R = res1

            # covariance_structure によって場合分け
            if self.observation_cs == 'triD1':
                # 新しい R を定義しておく
                new_R = np.zeros_like(self.R, dtype=self.dtype)

                # 対角成分に関して平均を取る
                np.fill_diagonal(new_R, self.R.diagonal().mean())

                # 三重対角成分に関して平均を取る
                rho = (self.R.diagonal(1).mean() +
                       self.R.diagonal(-1).mean()) / 2

                # 結果の統合
                self.R = new_R + np.diag(rho * np.ones(self.n_dim_obs - 1), 1) \
                     + np.diag(rho * np.ones(self.n_dim_obs - 1), -1)
            elif self.observation_cs == 'triD2':
                # 新しい R を定義しておく
                new_R = np.zeros_like(self.R, dtype=self.dtype)

                # 対角成分に関して平均を取る
                np.fill_diagonal(new_R, self.R.diagonal().mean())

                # 三重対角成分, 隣接成分に関して平均を取る
                td = np.ones(self.n_dim_obs - 1)
                td[self.observation_v - 1::self.observation_v - 1] = 0
                condition = np.diag(td, 1) + np.diag(td, -1) \
                    + np.diag(
                        np.ones(self.n_dim_obs - self.observation_v),
                        self.observation_v
                        ) \
                    + np.diag(
                        np.ones(self.n_dim_obs - self.observation_v),
                        self.observation_v
                        )
                rho = self.R[condition.astype(bool)].mean()

                # 結果の統合
                self.R = new_R + rho * condition.astype(self.dtype)

        # 次に transition_matrices の更新
        if 'transition_matrices' not in given:
            '''math
            F : transition_matrices, x_t : system,
            b_t : transition_offsets

            F &= ( \sum_{t=1}^{T-1} \mathbb{E}[x_t x_{t-1}^{T}]
                - b_{t-1} \mathbb{E}[x_{t-1}]^T )
             ( \sum_{t=1}^{T-1} \mathbb{E}[x_{t-1} x_{t-1}^T] )^{-1}
             '''
            #計算補助
            res1 = np.zeros((self.n_dim_sys, self.n_dim_sys), dtype=self.dtype)
            res2 = np.zeros((self.n_dim_sys, self.n_dim_sys), dtype=self.dtype)
            for t in range(1, T):
                b = _last_dims(self.b, t - 1, 1)
                res1 += self.V_pair[t] + np.outer(self.x_smooth[t],
                                                  self.x_smooth[t - 1])
                res1 -= np.outer(b, self.x_smooth[t - 1])
                res2 += self.V_smooth[t - 1] \
                    + np.outer(self.x_smooth[t - 1], self.x_smooth[t - 1])

            self.F = np.dot(res1, linalg.pinv(res2))

        # 次に transition_covariance の更新
        if 'transition_covariance' not in given:
            '''math
            Q : transition_covariance, x_t : system, 
            b_t : transition_offsets, F_t : transition_matrices

            Q &= \frac{1}{T-1} \sum_{t=0}^{T-2}
                (\mathbb{E}[x_{t+1}] - A_t \mathbb{E}[x_t] - b_t)
                    (\mathbb{E}[x_{t+1}] - A_t \mathbb{E}[x_t] - b_t)^T
                + F_t Var(x_t) F_t^T + Var(x_{t+1})
                - Cov(x_{t+1}, x_t) F_t^T - F_t Cov(x_t, x_{t+1})
            '''
            # 計算補助
            res1 = np.zeros((self.n_dim_sys, self.n_dim_sys), dtype=self.dtype)

            # 全てを最適化するわけではないので,素朴な計算になっている
            for t in range(T - 1):
                F = _last_dims(self.F, t)
                b = _last_dims(self.b, t, 1)
                err = self.x_smooth[t + 1] - np.dot(F, self.x_smooth[t]) - b
                Vt1t_F = np.dot(self.V_pair[t + 1], F.T)
                res1 += (np.outer(err, err) +
                         np.dot(F, np.dot(self.V_smooth[t], F.T)) +
                         self.V_smooth[t + 1] - Vt1t_F - Vt1t_F.T)

            self.Q = (1.0 / (T - 1)) * res1

            # covariance_structure によって場合分け
            if self.transition_cs == 'triD1':
                # 新しい R を定義しておく
                new_Q = np.zeros_like(self.Q, dtype=self.dtype)

                # 対角成分に関して平均を取る
                np.fill_diagonal(new_Q, self.Q.diagonal().mean())

                # 三重対角成分に関して平均を取る
                rho = (self.Q.diagonal(1).mean() +
                       self.Q.diagonal(-1).mean()) / 2

                # 結果の統合
                self.Q = new_Q + np.diag(rho * np.ones(self.n_dim_sys - 1), 1)\
                     + np.diag(rho * np.ones(self.n_dim_sys - 1), -1)
            elif self.transition_cs == 'triD2':
                # 新しい R を定義しておく
                new_Q = np.zeros_like(self.Q, dtype=self.dtype)

                # 対角成分に関して平均を取る
                np.fill_diagonal(new_Q, self.Q.diagonal().mean())

                # 三重対角成分, 隣接成分に関して平均を取る
                td = np.ones(self.n_dim_sys - 1)
                td[self.transition_v - 1::self.transition_v - 1] = 0
                condition = np.diag(td, 1) + np.diag(td, -1) \
                    + np.diag(
                        np.ones(self.n_dim_sys - self.transition_v),
                        self.transition_v
                        ) \
                    + np.diag(
                        np.ones(self.n_dim_sys - self.transition_v),
                        self.transition_v
                        )
                rho = self.Q[condition.astype(bool)].mean()

                # 結果の統合
                self.Q = new_Q + rho * condition.astype(self.dtype)

        # 次に initial_mean の更新
        if 'initial_mean' not in given:
            '''math
            x_0 : system of t=0
                \mu_0 = \mathbb{E}[x_0]
            '''
            tmp = self.initial_mean
            self.initial_mean = self.x_smooth[0]

        # 次に initial_covariance の更新
        if 'initial_covariance' not in given:
            '''math
            mu_0 : system of t=0
                \Sigma_0 = \mathbb{E}[x_0, x_0^T] - \mu_0 \mu_0^T
            '''
            x0 = self.x_smooth[0]
            x0_x0 = self.V_smooth[0] + np.outer(x0, x0)

            self.initial_covariance = x0_x0 - np.outer(self.initial_mean, x0)
            self.initial_covariance += - np.outer(x0, self.initial_mean)\
                 + np.outer(self.initial_mean, self.initial_mean)

        # 次に transition_offsets の更新
        if 'transition_offsets' not in given:
            '''math
            b : transition_offsets, x_t : system
            F_t : transition_matrices
                b = \frac{1}{T-1} \sum_{t=1}^{T-1}
                        \mathbb{E}[x_t] - F_{t-1} \mathbb{E}[x_{t-1}]
            '''
            self.b = np.zeros(self.n_dim_sys, dtype=self.dtype)

            # 最低でも3点での値が必要
            if T > 1:
                for t in range(1, T):
                    F = _last_dims(self.F, t - 1)
                    self.b += self.x_smooth[t] - np.dot(
                        F, self.x_smooth[t - 1])
                self.b *= (1.0 / (T - 1))

        # 最後に observation_offsets の更新
        if 'observation_offsets' not in given:
            '''math
            d : observation_offsets, y_t : observation
            H_t : observation_matrices, x_t : system
                d = \frac{1}{T} \sum_{t=0}^{T-1} y_t - H_{t} \mathbb{E}[x_{t}]
            '''
            self.d = np.zeros(self.n_dim_obs, dtype=self.dtype)
            n_obs = 0
            for t in range(T):
                if not np.any(np.ma.getmask(self.y[t])):
                    H = _last_dims(self.H, t)
                    self.d += self.y[t] - np.dot(H, self.x_smooth[t])
                    n_obs += 1
            if n_obs > 0:
                self.d *= (1.0 / n_obs)
Пример #7
0
    def filter(self):
        '''
        T {int} : length of data y (時系列の長さ)
        x_pred [n_time, n_dim_sys] {numpy-array, float}
            : mean of hidden state at time t given observations
             from times [0...t-1]
            時刻 t における状態変数の予測期待値 [時間軸,状態変数軸]
        V_pred [n_time, n_dim_sys, n_dim_sys] {numpy-array, float}
            : covariance of hidden state at time t given observations
             from times [0...t-1]
            時刻 t における状態変数の予測共分散 [時間軸,状態変数軸,状態変数軸]
        x_filt [n_time, n_dim_sys] {numpy-array, float}
            : mean of hidden state at time t given observations from times [0...t]
            時刻 t における状態変数のフィルタ期待値 [時間軸,状態変数軸]
        V_filt [n_time, n_dim_sys, n_dim_sys] {numpy-array, float}
            : covariance of hidden state at time t given observations
             from times [0...t]
            時刻 t における状態変数のフィルタ共分散 [時間軸,状態変数軸,状態変数軸]
        K [n_dim_sys, n_dim_obs] {numpy-array, float}
            : Kalman gain matrix for time t [状態変数軸,観測変数軸]
            カルマンゲイン
        '''

        T = self.y.shape[0]
        self.x_pred = np.zeros((T, self.n_dim_sys), dtype=self.dtype)
        self.V_pred = np.zeros((T, self.n_dim_sys, self.n_dim_sys),
                               dtype=self.dtype)
        self.x_filt = np.zeros((T, self.n_dim_sys), dtype=self.dtype)
        self.V_filt = np.zeros((T, self.n_dim_sys, self.n_dim_sys),
                               dtype=self.dtype)
        K = np.zeros((self.n_dim_sys, self.n_dim_obs), dtype=self.dtype)

        # 各時刻で予測・フィルタ計算
        for t in range(T):
            # 計算している時間を可視化
            print("\r filter calculating... t={}".format(t) + "/" + str(T),
                  end="")

            if t == 0:
                # initial setting (初期分布)
                self.x_pred[0] = self.initial_mean
                self.V_pred[0] = self.initial_covariance
            else:
                self.predict_update(t)

            # y[t] の何れかがマスク処理されていれば,フィルタリングはカットする
            if np.any(np.ma.getmask(self.y[t])):
                self.x_filt[t] = self.x_pred[t]
                self.V_filt[t] = self.V_pred[t]
            else:
                # extract t parameters (時刻tのパラメータを取り出す)
                H = _last_dims(self.H, t, 2)
                R = _last_dims(self.R, t, 2)
                d = _last_dims(self.d, t, 1)

                # filtering (フィルタ分布の計算)
                K = self.V_pred[t] @ (
                    H.T @ linalg.pinv(H @ (self.V_pred[t] @ H.T + R)))
                self.x_filt[t] = self.x_pred[t] + K @ (
                    self.y[t] - (H @ self.x_pred[t] + d))
                self.V_filt[t] = self.V_pred[t] - K @ (H @ self.V_pred[t])
Пример #8
0
    def smooth(self, lag=10):
        '''
        lag {int} : ラグ,lag of smoothing
        T {int} : 時系列の長さ,length of y

        x_pred_mean [n_time+1, n_dim_sys] {numpy-array, float}
            : mean of x_pred regarding to particles at time t
            時刻 t における x_pred の粒子平均 [時間軸,状態変数軸]
        x_filt_mean [n_time+1, n_dim_sys] {numpy-array, float}
            : mean of x_filt regarding to particles at time t
            時刻 t における状態変数のフィルタ平均 [時間軸,状態変数軸]
        x_smooth_mean [n_time, n_dim_sys] {numpy-array, float}
            : mean of x_smooth regarding to particles at time t
            時刻 t における状態変数の平滑化平均 [時間軸,状態変数軸]

        x_pred [n_dim_sys, n_particle]
            : hidden state at time t given observations[:t-1] for each particle
            状態変数の予測アンサンブル [状態変数軸,粒子軸]
        x_filt [n_particle, n_dim_sys] {numpy-array, float}
            : hidden state at time t given observations[:t] for each particle
            状態変数のフィルタアンサンブル [状態変数軸,粒子軸]
        x_smooth [n_time, n_dim_sys, n_particle] {numpy-array, float}
            : hidden state at time t given observations[:t+lag] for each particle
            状態変数の平滑化アンサンブル [時間軸,状態変数軸,粒子軸]

        w [n_particle] {numpy-array, float}
            : weight lambda of each particle
            各粒子の尤度 [粒子軸]
        v [n_dim_sys, n_particle] {numpy-array, float}
            : system noise particles
            各時刻の状態ノイズ [状態変数軸,粒子軸]
        k [n_particle] {numpy-array, float}
            : index number for resampling
            各時刻のリサンプリングインデックス [粒子軸]
        '''

        # 時系列の長さ, number of time-series data
        T = len(self.y)

        # initial filter, prediction
        self.x_pred_mean = np.zeros((T + 1, self.n_dim_sys), dtype=self.dtype)
        self.x_filt_mean = np.zeros((T + 1, self.n_dim_sys), dtype=self.dtype)
        self.x_smooth_mean = np.zeros((T + 1, self.n_dim_sys),
                                      dtype=self.dtype)
        x_pred = np.zeros((self.n_dim_sys, self.n_particle), dtype=self.dtype)
        x_filt = np.zeros((self.n_dim_sys, self.n_particle), dtype=self.dtype)
        x_smooth = np.zeros((T + 1, self.n_dim_sys, self.n_particle),
                            dtype=self.dtype)

        # initial distribution
        x_filt = rd.multivariate_normal(self.initial_mean,
                                        self.initial_covariance,
                                        size=self.n_particle).T

        # initial setting
        self.x_pred_mean[0] = self.initial_mean
        self.x_filt_mean[0] = self.initial_mean
        self.x_smooth_mean[0] = self.initial_mean

        for t in range(T):
            print("\r filter and smooth calculating... t={}".format(t), end="")

            ## filter update
            # 一期先予測, prediction
            f = _last_dims(self.f, t, 1)[0]

            # システムノイズをパラメトリックに発生, raise parametric system noise
            v = self.q[0](*self.q[1], size=self.n_particle).T

            # アンサンブル予測, ensemble prediction
            x_pred = f(*[x_filt, v])

            # mean
            self.x_pred_mean[t + 1] = np.mean(x_pred, axis=1)

            # 欠測値の対処, treat missing values
            if np.any(np.ma.getmask(self.y[t])):
                x_filt = x_pred
            else:
                # log likelihood for each particle for y[t]
                # 対数尤度の計算
                lf = self._last_likelihood(self.lf, t)
                lfp = self._last_likelihood(self.lfp, t)
                try:
                    w = lf(self.y[t], x_pred, *lfp)
                except:
                    raise ValueError('you must check likelihood_functions' +
                                     ' and parameters.')

                # 発散防止, avoid evaporation
                if self.likelihood_function_is_log_form:
                    w = np.exp(w - np.max(w))
                else:
                    w = w / np.max(w)

                # resampling
                k = self._stratified_resampling(w)
                x_filt = x_pred[:, k]

                # regularization
                if self.regularization:
                    x_filt += self.eta[0](*self.eta[1], size=self.n_particle).T

            # initial smooth value
            x_smooth[t + 1] = x_filt

            # mean
            self.x_filt_mean[t + 1] = np.mean(x_filt, axis=1)

            # smoothing
            if (t > lag - 1):
                x_smooth[t - lag:t + 1] = x_smooth[t - lag:t + 1, :, k]
            else:
                x_smooth[:t + 1] = x_smooth[:t + 1, :, k]

        # x_smooth_mean
        self.x_smooth_mean = np.mean(x_smooth, axis=2)
Пример #9
0
    def filter(self):
        '''
		T {int} : length of data y (時系列の長さ)
		x_pred_mean [n_time+1, n_dim_sys] {numpy-array, float}
			: mean of x_pred regarding to particles at time t
			時刻 t における x_pred の粒子平均 [時間軸,状態変数軸]
		V_pred [n_time+1, n_dim_sys, n_dim_sys] {numpy-array, float}
			: covariance of hidden state at time t given observations
			 from times [0...t-1]
			時刻 t における状態変数の予測共分散 [時間軸,状態変数軸,状態変数軸]
		x_filt [n_time+1, n_particle, n_dim_sys] {numpy-array, float}
			: hidden state at time t given observations for each particle
			状態変数のフィルタアンサンブル [時間軸,粒子軸,状態変数軸]
		x_filt_mean [n_time+1, n_dim_sys] {numpy-array, float}
			: mean of x_filt regarding to particles
			時刻 t における状態変数のフィルタ平均 [時間軸,状態変数軸]
		X5 [n_time, n_dim_sys, n_dim_obs] {numpy-array, float}
			: right operator for filter, smooth calulation
			filter, smoothing 計算で用いる各時刻の右作用行列

		x_pred [n_particle, n_dim_sys] {numpy-array, float}
			: hidden state at time t given observations for each particle
			状態変数の予測アンサンブル [粒子軸,状態変数軸]
		x_pred_center [n_particle, n_dim_sys] {numpy-array, float}
			: centering of x_pred
			x_pred の中心化 [粒子軸,状態変数軸]
		w_ensemble [n_particle, n_dim_obs] {numpy-array, float}
			: observation noise ensemble
			観測ノイズのアンサンブル [粒子軸,観測変数軸]
		Inovation [n_dim_obs, n_particle] {numpy-array, float}
			: Inovation from observation [観測変数軸,粒子軸]
			観測と予測のイノベーション
		'''

        # 時系列の長さ, lenght of time-series
        T = self.y.shape[0]

        ## 配列定義, definition of array
        # 時刻0における予測・フィルタリングは初期値, initial setting
        self.x_pred_mean = np.zeros((T + 1, self.n_dim_sys), dtype=self.dtype)
        self.x_filt = np.zeros((T + 1, self.n_particle, self.n_dim_sys),
                               dtype=self.dtype)
        self.x_filt[0, :] = self.initial_mean
        self.x_filt_mean = np.zeros((T + 1, self.n_dim_sys), dtype=self.dtype)
        self.X5 = np.zeros((T + 1, self.n_particle, self.n_particle),
                           dtype=self.dtype)
        self.X5[:] = np.eye(self.n_particle, dtype=self.dtype)

        # 初期値のセッティング, initial setting
        self.x_pred_mean[0] = self.initial_mean
        self.x_filt_mean[0] = self.initial_mean

        # initial setting
        x_pred = np.zeros((self.n_particle, self.n_dim_sys), dtype=self.dtype)
        x_pred_center = np.zeros((T + 1, self.n_particle, self.n_dim_sys),
                                 dtype=self.dtype)
        w_ensemble = np.zeros((self.n_particle, self.n_dim_obs),
                              dtype=self.dtype)

        # イノベーション, observation inovation
        Inovation = np.zeros((self.n_dim_obs, self.n_particle),
                             dtype=self.dtype)

        # 各時刻で予測・フィルタ計算, prediction and filtering
        for t in range(T):
            # 計算している時間を可視化, visualization for calculation
            print("\r filter calculating... t={}".format(t + 1) + "/" + str(T),
                  end="")

            ## filter update
            # 一期先予測, prediction
            f = _last_dims(self.f, t, 1)[0]

            # システムノイズをパラメトリックに発生, raise parametric system noise
            v = self.q[0](*self.q[1], size=self.n_particle)

            # アンサンブル予測, ensemble prediction
            x_pred = f(*np.transpose([self.x_filt[t], v], (0, 2, 1))).T

            # x_pred_mean を計算, calculate x_pred_mean
            self.x_pred_mean[t + 1] = np.mean(x_pred, axis=0)

            # 欠測値の対処, treat missing values
            if np.any(np.ma.getmask(self.y[t])):
                self.x_filt[t + 1] = x_pred
            else:
                # x_pred_center を計算, calculate x_pred_center
                x_pred_center = x_pred - self.x_pred_mean[t + 1]

                # 観測ノイズのアンサンブルを発生, raise observation noise ensemble
                R = _last_dims(self.R, t)
                w_ensemble = rd.multivariate_normal(np.zeros(self.n_dim_obs),
                                                    R,
                                                    size=self.n_particle)

                # イノベーションの計算
                H = _last_dims(self.H, t)
                Inovation.T[:] = self.y[t]
                Inovation += w_ensemble.T - H @ x_pred.T

                # 特異値分解
                U, s, _ = linalg.svd(H @ x_pred_center.T + w_ensemble.T, False)

                # 右作用行列の計算
                X1 = np.diag(1 / (s * s)) @ U.T
                X2 = X1 @ Inovation
                X3 = U @ X2
                X4 = (H @ x_pred_center.T).T @ X3
                self.X5[t + 1] = np.eye(self.n_particle, dtype=self.dtype) + X4

                # フィルタ分布のアンサンブルメンバーの計算
                self.x_filt[t + 1] = self.X5[t + 1].T @ x_pred

            # フィルタ分布のアンサンブル平均の計算
            self.x_filt_mean[t + 1] = np.mean(self.x_filt[t + 1], axis=0)
Пример #10
0
    def filter(self):
        '''
        T {int} : length of data y (時系列の長さ)
        <class variables>
        x_pred_mean [n_time+1, n_dim_sys] {numpy-array, float}
            : mean of x_pred regarding to particles at time t
            時刻 t における x_pred の粒子平均 [時間軸,状態変数軸]
        x_filt [n_time+1, n_dim_sys, n_particle] {numpy-array, float}
            : hidden state at time t given observations for each particle
            状態変数のフィルタアンサンブル [時間軸,状態変数軸,粒子軸]
        x_filt_mean [n_time+1, n_dim_sys] {numpy-array, float}
            : mean of x_filt regarding to particles
            時刻 t における状態変数のフィルタ平均 [時間軸,状態変数軸]

        <global variables>
        x_pred [n_dim_sys, n_particle] {numpy-array, float}
            : hidden state at time t given observations for each particle
            状態変数の予測アンサンブル [状態変数軸,粒子軸]
        x_pred_center [n_dim_sys, n_particle] {numpy-array, float}
            : centering of x_pred
            x_pred の中心化 [状態変数軸,粒子軸]
        v [n_dim_sys, n_particle] {numpy-array, float}
            : system noise for transition
            システムノイズ [状態変数軸,粒子軸]
        y_background [n_dim_obs, n_particle] {numpy-array, float}
            : background value of observation space
            観測空間における背景値(=一気先予測値) [観測変数軸,粒子軸]
        y_background_mean [n_dim_obs] {numpy-array, float}
            : mean of y_background for particles
            y_background の粒子平均 [観測変数軸]
        y_background_center [n_dim_obs, n_particle] {numpy-array, float}
            : centerized value of y_background for particles
            y_background の粒子中心化 [観測変数軸,粒子軸]

        <local variables>
        x_pred_mean_local [n_dim_local] {numpy-array, float}
            : localization from x_pred_mean
            x_pred_mean の局所値 [局所変数軸]
        x_pred_center_local [n_dim_local, n_particle] {numpy-array, float}
            : localization from x_pred_center
            x_pred_center の局所値 [局所変数軸,粒子軸]
        y_background_mean_local [n_dim_local] {numpy-array, float}
            : localization from y_background_mean
            y_background_mean の局所値 [局所変数軸]
        y_background_center_local [n_dim_local, n_particle] {numpy-array, float}
            : localization from y_background_center
            y_background_center の局所値 [局所変数軸,粒子軸]
        y_local [n_dim_local] {numpy-array, float}
            : localization from observation y
            観測 y の局所値 [局所変数軸]
        R_local [n_dim_local, n_dim_local] {numpy-array, float}
            : localization from observation covariance R
            観測共分散 R の局所値 [局所変数軸,局所変数軸]
        '''

        # 時系列の長さ, lenght of time-series
        T = self.y.shape[0]

        ## 配列定義, definition of array
        # 時刻0における予測・フィルタリングは初期値, initial setting
        self.x_pred_mean = np.zeros((T + 1, self.n_dim_sys), dtype=self.dtype)
        self.x_filt = np.zeros((T + 1, self.n_dim_sys, self.n_particle),
                               dtype=self.dtype)
        self.x_filt[0].T[:] = self.initial_mean
        self.x_filt_mean = np.zeros((T + 1, self.n_dim_sys), dtype=self.dtype)

        # 初期値のセッティング, initial setting
        self.x_pred_mean[0] = self.initial_mean
        self.x_filt_mean[0] = self.initial_mean

        # 各時刻で予測・フィルタ計算, prediction and filtering
        for t in range(T):
            # 計算している時間を可視化, visualization for calculation
            print('\r filter calculating... t={}'.format(t + 1) + '/' + str(T),
                  end='')

            ## filter update
            # 一期先予測, prediction
            f = _last_dims(self.f, t, 1)[0]

            # システムノイズをパラメトリックに発生, raise parametric system noise
            # sys x particle
            v = self.q[0](*self.q[1], size=self.n_particle).T

            # アンサンブル予測, ensemble prediction
            # sys x particle
            x_pred = f(*[self.x_filt[t], v])

            # x_pred_mean を計算, calculate x_pred_mean
            # time x sys
            self.x_pred_mean[t + 1] = np.mean(x_pred, axis=1)

            # 欠測値の対処, treat missing values
            if np.any(np.ma.getmask(self.y[t])):
                # time x sys x particle
                self.x_filt[t + 1] = x_pred
            else:
                ## Step1 : model space -> observation space
                h = _last_dims(self.h, t, 1)[0]
                R = _last_dims(self.R, t)

                # y_background : obs x particle
                y_background = h(x_pred)

                # y_background mean : obs
                y_background_mean = np.mean(y_background, axis=1)

                # y_background center : obs x particle
                y_background_center = (y_background.T - y_background_mean).T

                ## Step2 : calculate for model space
                # x_pred_center : sys x particle
                x_pred_center = (x_pred.T - self.x_pred_mean[t + 1]).T

                ## Step3 : select data for grid point
                # global を local に移す写像(並列処理)
                # n_dim_sys x local_sys
                x_pred_mean_local = self._parallel_global_to_local(
                    self.x_pred_mean[t], self.n_dim_sys, self.A_sys)

                # n_dim_sys x local_sys x particle
                x_pred_center_local = self._parallel_global_to_local(
                    x_pred_center, self.n_dim_sys, self.A_sys)

                # n_dim_sys x local_obs
                y_background_mean_local = self._parallel_global_to_local(
                    y_background_mean, self.n_dim_obs, self.A_obs)

                # n_dim_sys x local_obs x particle
                y_background_center_local = self._parallel_global_to_local(
                    y_background_center, self.n_dim_obs, self.A_obs)

                # n_dim_sys x local_obs
                y_local = self._parallel_global_to_local(
                    self.y[t], self.n_dim_obs, self.A_obs)

                # n_dim_sys x local_obs x local_obs
                R_local = np.zeros(self.n_dim_sys, dtype=object)
                for i in range(self.n_dim_sys):
                    R_local[i] = R[self.A_obs[i]][:, self.A_obs[i]]

                ## Step4-9 : local processing
                p = Pool(self.cpu_number)
                self.x_filt[t + 1] = p.starmap(
                    local_multi_processing,
                    zip(x_pred_mean_local, x_pred_center_local,
                        y_background_mean_local, y_background_center_local,
                        y_local, R_local, range(self.n_dim_sys), self.A_sys,
                        itertools.repeat(self.n_particle),
                        itertools.repeat(self.rho)))
                p.close()

            # フィルタ分布のアンサンブル平均の計算
            self.x_filt_mean[t + 1] = np.mean(self.x_filt[t + 1], axis=1)