MORIKOOH自由帳

勉強の記録です

(書評)「基礎からわかる時系列分析 -Rで実践するカルマンフィルタ・MCMC・粒子フィルタ-」

きっかけのツイート

いい本なのにAmazonのレビューないやん!と思ったので書きます。

書籍サイト: gihyo.jp

サポートページ: github.com

目次

こういう本だと思います

内容

  • Rによる実践的なデータサイエンスの本
  • 「時系列分析とは何か」「状態空間モデルとは何か」の解説と実装
  • カルマンフィルタ・MCMC・粒子フィルタの解説と実装
  • dlmやStanなどのライブラリを用いた実装

印象

  • 式変形の際には一言以上解説が入る*1
  • 図表・コードが非常に豊富かつ見やすい構成をしている
  • ライブラリを活用して簡易に実装している
  • 手法の分類が非常に整理されていて、学習時の立ち位置が分かりやすい
  • 実装例が単なる「実装してみた」ではなく、実際のデータを分析している
  • 本文中の補足や付録による補足が充実している
  • 参考文献が豊富

こういう本ではないです

まとめ

Rによる実装の参考にも、時系列分析の手法の解説書としても、応用への橋渡しとしても勧められる良い本だと思います。

書籍サイト(再掲): gihyo.jp

*1:追記: 計算に強い方からすると冗長に感じるかもしれないです

*2:素直に加藤「機械学習のエッセンス」や斎藤「ゼロから作るDeep Learning」などを買いましょう

*3:私は副題のカルマンフィルタに飛びついてRを使うことも確認せず(!!)購入しましたが、後悔していません

ABC122の結果(コードはまだ無い)

 2018.3.25に開催されたAtCoder Beginners Contest 122はAとBを解いて2完でした.苦手意識を持っていた文字列の問題でしたが,取りあえずB問題でACを出すという目標はクリアすることができました.しかし問題文を勘違いしてWAを出し過ぎた印象です.レートは 3 → 18 と思っていたよりも伸びませんでした.

f:id:MORIKOOH:20190325073720p:plain
6倍ではある

反省点

A問題の制約と入力例をよく見ていなかった

 Aが入力されたらTCが入力されたらGを出力する問題だと勘違いし,三項演算子で解けると早合点してしまった.

  • 制約にAGCTの4文字があること
  • 入力例2でGが入力されていること

に気づけば防げたミスだと思われる.「A問題は5分以内に解く」と意気込んでいたが功を焦った.

ちょっと擁護できないWAを出した

 標準入力欄をコピーして提出したり,A問題の提出欄にB問題のコードを提出してしまった.緊張していたとはいえ,提出には一呼吸おいて注意を払うべきだった.

B・C問題の演習が足りなかった

 B問題・C問題をスムーズに解けるようになるにはまだまだ演習が足りないと感じた.ABCのA問題は埋めきったので,これからは避けずに演習を重ねていきたい.

よかった点

B問題でACを出せたこと

 密かに目標にしていた(うれしい).  

少しだけC・D問題に噛みつけるようになったこと

 Cは発想は近かったがもう一歩,という感覚だった.Dはコードにこそ落とせなかったが「これはおそらく動的計画法だな」とピンときた点が良かった.

おわりに

 反省点は多いが,「ABCのB問題まではできるようになった」という自信がついた.今後は AtCoder Problems で時間をかけてでもBとCを埋めていこうと思う.次回のABCでは「C問題を解くこと」を目標に精進する.

f:id:MORIKOOH:20190325081604p:plain
ABCのA問題は3.25に埋めきった

ABC106-BをC++で解く

atcoder.jp

問題の要約

105は奇数だが約数が8個もある.1以上 N以下の奇数のうち,正の約数をちょうど8個持つようなものの個数を求めよ.

要点

  • 約数がちょうど8個との問題文からすぐにif(divisor == 8)の条件をイメージできたのは良かった.

  • forの条件式で初期値を1として2ずつ増やせば奇数を順に調べることができることに気付かなかった(if(X % 2 != 0) としようとしてドツボにハマった).

手順

  1. 1,3,5,7, ... ,と奇数を順に増やすforループを作る
  2. ループ毎に(つまり奇数ごとに)約数であるかを判定し(if(i % j == 0)),約数であれば約数の個数のカウンターdivisorsを1増加させる.
  3. divisorsがちょうど8個となったときに条件を満たす数の個数のカウンターansを1増加させる.

コード

# include <bits/stdc++.h>
using namespace std;

int main() {
    int N;
    cin >> N;
    int ans = 0;
    for (int i = 1; i <= N; i += 2) { // <- 1.
        int divisors = 0;
        for (int j = 1; j <= i; j++) {
            if (i % j == 0) { // <- 2.
                divisors++;
            }
        }
        if (divisors == 8) { // <- 3.
            ans++;
        }
    }
    cout << ans << endl;
    return 0;
}

また,以下の記事を参考に約数を求めるコードをC++で作成し,約数の確認をした.

webkaru.net

入力例1

105

出力例1

1

1以上105以下の整数の中で「奇数かつ約数が8個を満たす数」は105のみ.

  • 105の約数は「1 3 5 7 15 21 35 105」の8つ

入力例2

200

出力例1

5

1以上200以下の整数の中で「奇数かつ約数が8個」を満たす数は「105,135,165,189,195」の5つ.

  • 135の約数は「1 3 5 9 15 27 45 135」の8つ
  • 165の約数は「1 3 5 11 15 33 55 165」の8つ
  • 189の約数は「1 3 7 9 21 27 63 189」の8つ
  • 195の約数は「1 3 5 13 15 39 65 195」の8つ

おまけ 約数を求めるコード(C++)

# include <bits/stdc++.h>
using namespace std;

int main() {
    int N;
    cin >> N;
    
    for(int i = 1; i <= N; i++){
        if(N % i == 0){
            cout << i << " ";
        }
    }
    return 0;
}

ABC120-BをC++で解く

分からなかった問題を細かく記録することにした(タグはC++,競プロ,ABC).

atcoder.jp

問題の要約

整数A,Bが与えられる.AもBも割り切る正整数のうちK番目に大きいものを出力する.

解説からの抜粋

正整数 i A Bも割り切るなら, 1 \leq i \leq \min(A,B)を満たす.したがって, M =\min(A,B)とすると i = M, M-1, M-2, ... , 1と順に i A,Bを共に割り切るか調べていき, K番目に見つけた数を出力する.

分からなかったポイント

  •  K番目を取り出すという考えに囚われて,配列vector.at()でなんとかするのかと思っていた

手順

  1. A,Bのうち小さいほうを初期値として for ループを回す( int i = min(A,B) ).
  2. AとBの両方が割り切れたとき( A%i==0 && B%i==0 )にKを1減算する( K-- ).
  3. Kが0になるまでループさせると,その番号KはK番目に大きいことを示す.

以上のことをコードにすると次のようになる.

コード

# include < bits / stdc ++. h >
using namespace std ;

int main () {
  int A , B , K;
  cin >> A >> B >> K ;

  for ( int i = min (A , B ); i >= 1; --i ) { // <- 1.
    if ( A % i == 0 && B % i == 0) { // <- 2.
    K-- ;
    if ( K == 0) { // <- 3.
      cout << i << endl ;
      return 0;
    }
  }
}

競プロの記録

※ ただの記録

AtCoderでABC121に参加したのが2019.3.9なので,8日経ったことになる.

AGC031はまだ解ける自信が無く参加しなかったので,Ratingに変化はなし.

f:id:MORIKOOH:20190317092441j:plain
伸びしろがすごい

AtCoder Problems でとにかくABCのA問題を121から順に遡って埋めていく方針にして,現在の状況は以下の通り.

f:id:MORIKOOH:20190317085458p:plain
A問題を結構やった

このくらいまでやって,「A問題は1~5分くらいで解けるようになった」と感じた.具体的には,

・問題を見て入出力( std::cin , std::cout )をコードにするまで20~30秒程度

・数式に落とし込む問題は+1~2分程度

・文字列を扱う問題は+1~5分程度

程度のレベルに達したように感じる.

しかしまだB問題を解こうとすると手が止まる.まだ自力でACを出した問題が1問しかない程度のレベル.

そこで今後は「B問題ができるようになるまでA問題を解く」から少し方針を変え,「B問題やC問題をときどき時間をかけてでも解き,傾向を掴む」ことにしてみる.

次のABC/ARCには絶対に参加するので,灰色を脱することを目指す.

C++の多次元配列についての備忘録

配列の使い勝手がMATLABやCと違ったので,「APG4b T - 2.03.多次元配列」を参考にして要点を記録する.

・APG4b T - 2.03.多次元配列 (ページ下部に図解が大量にあってわかりやすい)

atcoder.jp

不正確だったり勘違いしている部分も多いと思われるので追記する予定.

前提としてC++14の環境で,

  #include <bits/stdc++.h>
  using namespace std;

  int main( ) {
  /* この部分 */
  }

を書いていると思ってください.

目次

多次元配列は配列の宣言を入れ子にする

1次元配列は vector<型> 配列変数名; を基本にして次のように宣言するのだった.

・APG4b N - 1.13.配列

atcoder.jp

  vector<int> vec; // 空の1次元配列

  vector<int> vec(3); // 要素が3個の1次元配列(3個とも0)

  vector<int> vec = {1,2,3}; // 要素を指定して初期化した1次元配列

2次元配列は次のようにvector<vector<int>>のように入れ子にして宣言する.

  vector<vector<int>> vvec; // 空の2次元配列

  vector<vector<int>> vvec = {
  {1, 2, 3},
  {4, 5, 6},
  {7, 8, 9},
  }; // 要素を指定して初期化した2次元配列(3x3 行列)

  vector<vector<int>> vvec(4, vector<int> (3, 0)); // (4x3 行列)

3つ目の記法vector<vector<要素の型>> 配列変数名(要素数1, vector<要素の型>(要素数2, 初期値))を特に忘れる.

直感的には「3列のゼロベクトルを4行並べた行列」のようなイメージだろうか.

[2019/3/11 追記] 初期値の扱い

初期値は省略することができる.省略した場合は要素の型に対応するゼロ値で初期化される.

  • int ならば数値の 0
  • string ならば空文字列の ""

[2019/3/11 追記ここまで]

要素へのアクセスは1次元配列を拡張したような形になる

1次元配列vec i番目の要素にアクセスするには,vec.at(i) を使うのだった.

cpprefjp.github.io

2次元配列vvec i j列目の要素にアクセスするには次のようにする.

  vvec.at(i).at(j);

例(2次元配列の要素へのアクセス)

適当な3×3行列を用意し,行列の要素に順にアクセスして二重forループで順に出力すると以下のようになる.

  vector<vector<int>> vvec = {
  {1, 2, 3},
  {4, 5, 6},
  {7, 8, 9},
  };

  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      cout << vvec.at(i).at(j);
    }
  }

結果:

123456789

(0,0),(0,1),(0,2),(1,0),...,(2,1),(2,2)と順にアクセスしていることが確認できる.

多次元配列の大きさの取得方法

  • 縦の大きさは配列変数名.size()で取得
  • 横の大きさは配列変数名.at(0).size()で取得

[2019/3/11 追記] すべての要素数を取得する時は「縦の要素数 * 横の要素数」で求める

2次元配列をvvecとすると,全要素数

number = vvec.size() * vvec.at(0).size();

とすると取得できる. [2019/3/11 追記ここまで]

例(2次元配列の大きさの取得)

適当な5×7行列を用意し,サイズを取得してみる.

  // int型の5x7要素の2次元配列の宣言
  vector<vector<int>> vvec(5, vector<int>(7));

  cout << vvec.size() << endl; // 縦の大きさ(要素数)
  cout << vvec.at(0).size() << endl; // 横の大きさ

結果:

5
7

おわりに

2019/03/11現在まででC++の配列について知ったことは以上の通りでした.

ブログを始めた

MORIKOOH (もりこう) です.ブログを始めます.内容は以下のようになる予定です.

  • 勉強して躓いた点の記録

  • 競技プログラミングの解法の記録

  • 論文を読んだ記録

  • 後で読む資料のリンクの記録

  • 本のレビュー

自己紹介

  • 所属:大学院生.専攻は制御工学.

  • 興味:航空宇宙工学,数学,物理,最近はプログラミング.

  • 使用言語:C/C++PythonMATLAB,極稀にScilab

  • 趣味:料理,ネットサーフィン,ダンス(見る専).

  • やってみたいこと:画像処理×機械学習Railsチュートリアル,Web上で動く制御工学の教材の制作,etc.

目次

記法テスト(Markdown)

箇条書き

半角アスタリスク「*」の後に半角スペース

引用

不等号「>」の後に半角スペース

吾輩は猫である。名前はまだ無い。

脚注

半角括弧2個ずつで挟む

吾輩は猫である。名前はまだ無い。*1

リンク(3種)

選択範囲

リンク部分を大括弧1個ずつで挟み,大括弧外でカッコ内にURLを貼る.

夏目漱石,坊っちゃん

文中であまり重要でないが載せたいときに使いそう.

埋め込み

上記の(.htmlの後に「:embed:cite」を追加)

夏目漱石坊っちゃん www.aozora.gr.jp

本の表紙等も表示されるためAmazonのリンクとかに使いそう.

URL

大カッコでURLを挟むだけ

夏目漱石坊っちゃん https://www.aozora.gr.jp/cards/000148/files/789_14547.html

脚注に書くにはタイトル+URLで書くのが良さそう.

ソースコードの貼り付け

シングルクォーテーション「`」3個でソースコードを挟む.

#include <iostream.h>
using namespace std;

int main(){
    cout << "Hello, cpp << endl;
    return 0;
}

シンタックスハイライトは文頭のクォーテーションの次に言語名を入れる( ソースコードを色付けして表示する(シンタックスハイライト) - はてなブログ ヘルプ).

#include <iostream.h>
using namespace std;

int main(){
    cout << "Hello, Cpp!!" << endl;
    return 0;
}

ソースコードに言語名を表示したり行番号を付けたりするには以下のページが参考になりそう.

kurokinomizuiwa.hatenablog.com

そのうちやる.

TeX in はてなブログ

指数を書くときにはハット( ^ )の後に半角スペースを入れる必要がある.

  • (正) 半角スペースを入れた場合: x^ 2
  • (誤) 入れない場合:[tex: x2]

I2 Cのように規格に指数を入れる場合以外は使わないかも.

複雑な式はTeXclipでPNGにして貼るのが無難だと思う.

f:id:MORIKOOH:20190310225551p:plain
TeXclipは便利だなぁ

texclip.marutank.net

以上.