読者です 読者をやめる 読者になる 読者になる

たけし備忘録

自分の好奇心の赴くままに勉強メモ LL系が大好き Python bash Julia C

PyKalmanパッケージのインストールとコードの修正

Pythonでカルマンフィルタをやりたいなと思って調べたところ、PyKalmanというパッケージがありました。便利そうな作りなのでしばらくこれで遊んでみることにします。

PyKalmanのインストール

最新バージョンは PyKalman 0.95 です。

公式リファレンス: pykalman — pykalman 0.9.2 documentation
GitHub: GitHub - pykalman/pykalman: Kalman Filter, Smoother, and EM Algorithm for Python

pipでのインストール

$ pip install pykalman

でインストール出来ます。 ただし、何故かアンイストールが上手くできず、いつも停止します。僕だけかもしれない。

condaでのインストール

$ conda install pykalman -c phios

でインストールできます。 他のチャンネルでインストールしたい場合は

$ anaconda search -t conda pykalman

を実行するとインストール可能なチャンネルが出てきます。

GitHubからのインストール

$ git clone https://github.com/pykalman/pykalman.git
$ cd pykalman
$ python setup.py install

とすればインストールできます。

コードの修正とデータセットの追加

今のところ、一箇所だけバグがあったので修正しました。

PyKalmanをインストールしたPythonディレクトリを

C:\python27

とします。 PyKalmanは次の場所にインストールされています。

C:\python27\lib\site-packages\pykalman

GitHubからインストールした方以外の場合

GitHubからクローンを取ってきて直接インストールした場合以外では、なぜか

pykalman/datasets/data
pykalman/datasets/descr

が存在しませんでした。 これをGitHubから取ってきて追加しましょう。

GitHub - pykalman/pykalman: Kalman Filter, Smoother, and EM Algorithm for Python

上記のGitHubをダウンロードして、その中身には

pykalman/datasets/data
pykalman/datasets/descr

がありますので、これをディレクトリごとコピーして、pykalmanをインストールしている場所の中の

C:\python27\lib\site-packages\pykalman\datasets

の中にコピーしてしまいましょう。 この結果の正しいディレクトリ構成は次のようになります。

    ./pykalman
    ┃
    ┗ /datasets
       ┃
       ┣ /data
       ┃ ┗ robot.mat
       ┣ /descr
       ┃ ┗ robot.rst
       ┣ __init__.py
       ┗ base.py

コードの修正

色々といじくっていたらバグがありました。とは言ってもそこまで主要な部分に影響を及ぼさないので気にならない方はそのままでいいと思います。以下の修正部分を示します。

C:\python27\lib\site-packages\pykalman\standard.py

をエディタで開きます。 その中の一番最後の部分、1529行目にある_parse_observations(self, obs)という関数の内容を変更します。

# 1529行目
    def _parse_observations(self, obs):
        """Safely convert observations to their expected format"""
        obs = np.ma.atleast_2d(obs)
        if obs.shape[0] == 1 and obs.shape[1] > 1:
            obs = obs.T
        return obs

となっているはずです。これを以下のように修正しましょう。

# 1529行目
    def _parse_observations(self, obs):
        """Safely convert observations to their expected format"""
        # obs = np.ma.atleast_2d(obs)
        obs = np.atleast_2d(obs)
        if obs.shape[0] == 1 and obs.shape[1] > 1:
            obs = obs.T
        return obs

これで保存して終了です。

これでどういうバグが発生していたかと言うと、loglikelihoodという関数を使用する際に、引数にNumPyのArrayを代入します。この際に上記の_parse_observations(self, obs)に渡したArrayが代入され、MaskedArrayという形式に変更させられていたわけです。

しかしloglikelihood関数の内部ではSciPy.linalgのtriangular_solve関数が用いられます。triangular_solveは内部でMaskedArrayを拒否する設定になっているので_parse_observations(self, obs)MaskedArrayに変換されるとエラーを起こすわけです。これがバグの原因でした。

_parse_observations(self, obs)のコメントに書いてあるように

"""Safely convert observations to their expected format"""

つまり「他の関数がちゃんと動作するために引数のArrayを安全な形式に変換する」と書かれています。

np.atleast_2dは引数のArrayを最小2次元Arrayに変換しますが、
np.ma.atleast_2dは、引数のArrayを最小2次元MaskedArrayに変換します。

ここがダメだったので普通のnp.atleast_2dに変更したわけです。