今日のテーマ: 移動平均 (その1)
次のテーマは、データの「平滑化」の一種である「移動平均」。 今回は移動平均の計算だけでなく、その準備となる
- データを「1次元配列」に並べ替え
- 簡単な時系列グラフを描く
「2次元」データの「1次元」への並べ替え (その1)
もともとのデータは
- ある1年のデータが「行ごと」に
- ある月のデータが「列ごと」に
- 2023年2月の「1つ左」に2023年1月のデータがあるが、
- 2023年1月の「1つ左」に2022年12月のデータはない
こういった面倒さを避ける簡単な方法は、いったんデータを「古い順番に一列に」なるように並べ直すことである。 そのためには以下のような プログラム を用いればよい。 このプログラムを (例えば) enshu06a.f90 という名前で保存し、例の如く gfortran enshu06a.f90 とした後に、
$ cat matsuyama-kion.txt | ./a.outと実行せよ。 またこのプログラムが正しく動作しているかどうかを、以下の手順により確認せよ。
- 出力データの先頭3行はどうなっているか?
$ cat matsuyama-kion.txt | ./a.out | head -n 3
($ はコマンドプロンプト) としたときの出力は以下のようになっているはずである。1 189001 4.8 2 189002 7.5 3 189003 8.8
- 出力データの末尾3行はどうなっているか?
$ cat matsuyama-kion.txt | ./a.out | tail -n 3
としたときの出力は以下のようになっているはずである。1606 202310 19.4 1607 202311 14.8 1608 202312 9.3
p | r | o | g | r | a | m | e | n | s | h | u | 0 | 6 | a | |||||||||||||||||||||||||||||||||||||||||||
i | m | p | l | i | c | i | t | n | o | n | e | ||||||||||||||||||||||||||||||||||||||||||||||
i | n | t | e | g | e | r | : | : | s | e | i | r | e | k | i | , | t | s | u | k | i | , | j | o | u | t | a | i | , | b | a | n | g | o | u | ||||||||||||||||||||||
r | e | a | l | , | d | i | m | e | n | s | i | o | n | ( | 1 | 2 | ) | : | : | k | i | o | n | ||||||||||||||||||||||||||||||||||
b | a | n | g | o | u | = | 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||
d | o | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
r | e | a | d | ( | * | , | ' | ( | i | 4 | , | 1 | 2 | f | 5 | . | 1 | ) | ' | , | i | o | s | t | a | t | = | j | o | u | t | a | i | ) | s | e | i | r | e | k | i | , | k | i | o | n | |||||||||||
i | f | ( | j | o | u | t | a | i | / | = | 0 | ) | e | x | i | t | |||||||||||||||||||||||||||||||||||||||||
d | o | t | s | u | k | i | = | 1 | , | 1 | 2 | ||||||||||||||||||||||||||||||||||||||||||||||
w | r | i | t | e | ( | * | , | ' | ( | 2 | i | 5 | , | i | 2 | . | 2 | , | f | 6 | . | 1 | ) | ' | ) | b | a | n | g | o | u | , | s | e | i | r | e | k | i | , | t | s | u | k | i | , | & | ||||||||||
k | i | o | n | ( | t | s | u | k | i | ) | |||||||||||||||||||||||||||||||||||||||||||||||
b | a | n | g | o | u | = | b | a | n | g | o | u | + | 1 | |||||||||||||||||||||||||||||||||||||||||||
e | n | d | d | o | |||||||||||||||||||||||||||||||||||||||||||||||||||||
e | n | d | d | o | |||||||||||||||||||||||||||||||||||||||||||||||||||||
e | n | d | p | r | o | g | r | a | m | e | n | s | h | u | 0 | 6 | a |
なお、このプログラムのミソは (あえて言うなら)、
-
何番めのデータを書き出そうとしているか? を管理する変数 として bangou という名前の器を使うことを宣言する。 この変数を正しく使うための要点は以下の2点。
- ループに入る前に bangou = 1 と初期化 しておく。 なぜなら、一番最初に書き出すデータを1番目にしたいからである。
- ループ中で1つデータを書き終えたら bangou に 1 を加える。 なぜなら、次に書くはずのデータは1つ大きな番号をもつはずだからである。
$ cat matsuyama-kion.txt | ./a.out > matsuyama-kion2.txtと実行してみよ。 ここで「>」は出力をリダイレクト (redirect; 向け直す) する命令である。 この操作により、計算結果は画面に出力されることなく、matsuyama-kion2.txt というファイルの中に書き出される。 なおこの操作では、既にあるファイルの中身を上書き してしまうので、リダイレクトする先のファイル名の指定に注意せよ。
既に気付いていると思うが、このプログラムは 第1回で作ったデータの読み書きプログラム を基にして、書き出しの形式を変更しただけのものである。 これによって生成された matsuyama-kion2.txt と、もともとのデータである matsuyama-kion.txt の中身の違いを確認せよ。
「2次元」データの「1次元」への並べ替え (その2)
次は matsuyama-kion2.txt から、一列に並べ直されたデータを読み込むプログラムを作ってみよう。 そのためには以下のような プログラム を用いればよい。 このプログラムを (例えば) enshu06b.f90 という名前で保存し、例の如く gfortran enshu06b.f90 とした後に、
$ cat matsuyama-kion2.txt | ./a.outと実行してみよ。
p | r | o | g | r | a | m | e | n | s | h | u | 0 | 6 | b | |||||||||||||||||||||||||||||||||||||||||||||||||||||
i | m | p | l | i | c | i | t | n | o | n | e | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
i | n | t | e | g | e | r | : | : | s | e | i | r | e | k | i | , | t | s | u | k | i | , | j | o | u | t | a | i | , | b | a | n | g | o | u | , | k | o | s | u | u | ||||||||||||||||||||||||||
r | e | a | l | , | d | i | m | e | n | s | i | o | n | ( | 1 | 8 | 0 | 0 | ) | : | : | k | i | o | n | 1 | r | e | t | s | u | ||||||||||||||||||||||||||||||||||||
k | o | s | u | u | = | 0 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
d | o | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
r | e | a | d | ( | * | , | ' | ( | 2 | i | 5 | , | i | 2 | . | 2 | , | f | 6 | . | 1 | ) | ' | , | i | o | s | t | a | t | = | j | o | u | t | a | i | ) | b | a | n | g | o | u | , | s | e | i | r | e | k | i | , | t | s | u | k | i | , | & | |||||||
k | i | o | n | 1 | r | e | t | s | u | ( | b | a | n | g | o | u | ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
i | f | ( | j | o | u | t | a | i | / | = | 0 | ) | e | x | i | t | |||||||||||||||||||||||||||||||||||||||||||||||||||
k | o | s | u | u | = | k | o | s | u | u | + | 1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
e | n | d | d | o | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
d | o | b | a | n | g | o | u | = | 1 | , | k | o | s | u | u | ||||||||||||||||||||||||||||||||||||||||||||||||||||
w | r | i | t | e | ( | * | , | ' | ( | i | 4 | , | f | 6 | . | 1 | ) | ' | ) | b | a | n | g | o | u | , | k | i | o | n | 1 | r | e | t | s | u | ( | b | a | n | g | o | u | ) | |||||||||||||||||||||||
e | n | d | d | o | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
e | n | d | p | r | o | g | r | a | m | e | n | s | h | u | 0 | 6 | b |
なお、このプログラムのミソは以下の通り。
「平均気温データの全部」を入れるために、kion1retsu という名前の器を使うことを宣言する。 ただし、「入れられるデータの数」については必要分よりも多め にとってある (ここでは 1800/12=150年分)。 この理由は、この入れ物の数が足りなくなったら困る けれど、余る分には何も困らない からである。 言い換えればこのプログラムは、余った入れ物は使わなければいいだけ、という「割り切った」考えに立って作られている。
ちなみにこうした「割り切り」とか「開き直り」は、読むべきデータの 個数があらかじめ分かっていない場合 とか、あるいは (異なるデータを読ませる可能性があるなど) 個数が一定していない場合 を扱うプログラムを作る上で便利な考え方である。 (ということで、このプログラムは数年前の演習からそっくりそのまま使い回されているし、しかもあと 16 年間は使い回しがきく。)
-
いくつのデータを読み込んだか? を数えるための変数として、kosuu という名前の器を使うことを宣言する。 この変数の正しい使い方は既に習った通り (前回までに出てきた nensuu と同じ) だが、大事な点は 最初の do ループを抜けた時点で、kosuu には読み込んだデータの総数が入っている ということである。 これにより、実際に読み込んだデータの個数と同じ数だけ、その次の do ループを回す ような指定 (要するに kion1retsu の余った分を参照しない設定) ができている。
-
kion1retsu という器の何番めのデータを読み書きするか? を管理する変数として bangou という名前の器を使うことを宣言する。
またこのプログラムでは、データを読み込む部分と、データを処理する部分とが完全に分離されている。 そのため、実際に移動平均を計算するための改造をする場合には、最初に データの読み込みに使っている do ループの内部には一切手を加える必要がない ようになっている。
移動平均をとる (その1)
さていよいよ実際に移動平均を計算する方法を考えてみよう。 最初の練習として、先に並べ替えた各月の平均気温データを用いて、「自分自身とその前後1つずつ」を使った移動平均 をとってみよう。 必要な手順 (の要点だけ) を以下に示す。
「平均気温データの移動平均」を入れるために、kion1retsu_lowpass1 という名前の器を使うことを宣言する。 ただし kion1retsu という器の宣言のときと同様に、「入れられるデータの数」については必要分よりも多め にとってある (ここでは 1800/12=150年分)。
r e a l , d i m e n s i o n ( 1 8 0 0 ) : : k i o n 1 r e t s u _ l o w p a s s 1 全てのデータの移動平均をとるにあたっては、慎重な場合分けが必要 である。 下の例では、if 〜 else if 〜 else 〜 end if という構造で場合分け (条件分岐) を行っている。 この場合分けの構造の仕組みを注意して眺めることにより、
- 場合によって行われる操作が、具体的にどう違っているのか、また
- なぜこのような場合分けをする必要があるのか
また下の例で、やたらと細かく「改行」しているのは、たびたび登場する kion1retsu や bangou という文字の出てくる場所をきれいに揃えておきたい、という亀山の思惑の結果である。 こうした「見た目」の調整は、プログラム本体の「見やすさ」を向上させてくれるし、ひいては「バグの少ないプログラム作り」にもつながってくる。 余力のある人 (あるいは将来プログラミングを「バリバリに」やるつもりの人) は、こうした「見た目」にも気を配っておくことをおススメする。
最後に、移動平均の計算値を出力する。 ここでは bangou 番めの月の気温の値 kion1retsu(bangou) と移動平均をとった値 kion1retsu_lowpass1(bangou) を小数点以下2桁まで表示するようにしてある。
d o b a n g o u = 1 , k o s u u i f ( b a n g o u = = 1 ) t h e n k i o n 1 r e t s u _ l o w p a s s 1 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u ) & + k i o n 1 r e t s u ( b a n g o u + 1 ) ) / 2 . 0 e l s e i f ( b a n g o u = = k o s u u ) t h e n k i o n 1 r e t s u _ l o w p a s s 1 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u - 1 ) & + k i o n 1 r e t s u ( b a n g o u ) ) / 2 . 0 e l s e k i o n 1 r e t s u _ l o w p a s s 1 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u - 1 ) & + k i o n 1 r e t s u ( b a n g o u ) & + k i o n 1 r e t s u ( b a n g o u + 1 ) ) / 3 . 0 e n d i f w r i t e ( * , ' ( i 4 , 2 f 6 . 2 ) ' ) b a n g o u , k i o n 1 r e t s u ( b a n g o u ) , & k i o n 1 r e t s u _ l o w p a s s 1 ( b a n g o u ) e n d d o
これらを参考にして、先に作ったプログラム enshu06b.f90 に、各月の気温の移動平均を計算する機能を追加したプログラムを作成せよ [みほん]。 そのプログラムを用いて (例の如く gfortran enshu06c.f90 などとして a.out を新たに作った後に)
$ cat matsuyama-kion2.txt | ./a.outと実行せよ。 また、移動平均の計算が正しくできているかどうかを、以下の手順により確認せよ。
- 出力データの先頭3行はどうなっているか?
$ cat matsuyama-kion2.txt | ./a.out | head -n 3
($ はコマンドプロンプト) としたときの出力は以下のようになっているはずである。1 4.80 6.15 2 7.50 7.03 3 8.80 10.30
- 出力データの末尾3行はどうなっているか?
$ cat matsuyama-kion2.txt | ./a.out | tail -n 3
としたときの出力は以下のようになっているはずである。1606 19.40 20.50 1607 14.80 14.50 1608 9.30 12.05
正しい出力が得られていることが確認できたら、
$ cat matsuyama-kion2.txt | ./a.out > matsuyama-kion3.txtと実行することにより、出力を matsuyama-kion3.txt という名前のファイルに書き出させておくこと。 また、本日の演習の出席確認のため、このプログラムを 末尾のフォーム 経由で提出せよ。
移動平均のグラフを描く (その1)
次は Gnuplot を使って、移動平均をとった結果を目で見てみよう。
まずは端末から Gnuplot を起動し、以下のように入力してみよう (gnuplot>は Gnuplot のプロンプト)。
gnuplot> plot "matsuyama-kion3.txt" using 1:2 with linesこれにより、134年(=1608ヶ月) 分の毎月の平均気温が折れ線グラフで表示される。 当然ながら、季節変化に対応する「ギザギザ」がよく見えているはずだ。 なおこの命令は、matsuyama-kion3.txt の1列目 (要するに、「最初から何か月めか」の番号) を横軸に、2列目 (要するに「その月の平均気温」) を縦軸にしたグラフを描け、というものである。 また、
gnuplot> plot [1488:1608] "matsuyama-kion3.txt" using 1:2 with linesとすると、横軸の範囲が 1488 から 1608 の間 (要するに最近の120ヶ月=10年) 分のみになったグラフが表示されるはずだ。 この手順にならって、横軸の範囲をとり直したグラフをいくつか描かせてみよ。
これに加えて今度は、計算した移動平均の値も同時に表示させてみよう。
gnuplot> plot [1488:1608] "matsuyama-kion3.txt" using 1:2 with lines, "matsuyama-kion3.txt" using 1:3 with linesとして表示されるグラフをよく観察してみよ。 もともとの平均気温のグラフと、移動平均のグラフとをよく見比べることにより、両者の間にはどのような違いがあるかを考えよ。
先のグラフでみたように、移動平均をとることによって 「ギザギザ」がなまる という効果が得られる。 これは専門用語でいうところの ローパスフィルター (low-pass filter) に通したことに相当する。 ローパスフィルターとは、データに含まれる時間変動のうち、速く変動する (高周波) 成分を弱め、ゆっくり変動する (低周波) 成分をとり出す 性質、あるいは (同じことだが) 短い周期で変動する成分を弱め、長い周期で変動する成分をとり出す 性質を持っている。 今回の例では、真夏や真冬に対応する1ヶ月単位の鋭い「ギザギザ」が (ほんの少しだけだが) なまり、「トゲ」が小さくなるとともに「幅」が広がっていることが分かる。
ここで念のため、移動平均をとることによって取り除かれた成分がどんなものか、グラフで確認してみよう。
gnuplot> plot [1488:1608] "matsuyama-kion3.txt" using 1:($2-$3) with linesこの命令は、matsuyama-kion3.txt の1列目 (要するに、「最初から何か月めか」の番号) を横軸に、縦軸に2列目と3列目の差をとったグラフを描け、というものである。 ではこのグラフに示されているものは具体的には何だろうか?
もともとのデータから、移動平均された値を引き算してやると、移動平均によってなまらされた「ギザギザ」の成分を取り出すことができる。 この操作の意味をもう少し「学問的」に言えば、データに含まれる時間変動のうち、長い周期で変動する成分を弱め、短い周期で変動する成分をとり出す、あるいは (同じことだが) ゆっくり変動する (低周波) 成分を弱め、速く変動する (高周波) 成分をとり出す という性質を持っている。 このような性質をもったフィルターを専門用語では ハイパスフィルター (high-pass filter) という。
移動平均をとる (その2)
次は、移動平均をとる際に使う点の数を変えることで、「ギザギザ」のなまり方がどう変わるかを調べてみよう。 これまでに作った「自分自身とその前後1つずつを使った移動平均」をとるプログラムを改造し、「自分自身とその前後2つずつを使った移動平均」を計算する機能を追加 してみよう。 必要な手順 (の要点だけ) を以下に示す。
「自分自身とその前後2つずつをとった移動平均」を入れるために、kion1retsu_lowpass2 という名前の器を使うことを宣言する。 ただし kion1retsu という器の宣言のときと同様に、「入れられるデータの数」については必要分よりも多め にとってある (ここでは 1800/12=150年分)。
r e a l , d i m e n s i o n ( 1 8 0 0 ) : : k i o n 1 r e t s u _ l o w p a s s 2 -
全てのデータを読み込んだ後に作った do ループの中で、「前後1つずつを含めた移動平均」に加えて、「前後2つずつを含めた移動平均」も計算 する。 計算結果の出力は、2列目に平均温度の「生」の値、3列目に「前後1つずつを含めた移動平均」、4列目に「前後2つずつを含めた移動平均」となるようにしている。
ただし「前後2つずつを含めた移動平均」の計算には、「前後1つずつをとった移動平均」をとる場合とは異なる新たな場合分けが必要 である。 この場合分けの意味をよく考え、おのおのの場合にあてはまる移動平均の計算式を正しく書き入れよ。 なおこの際、else の後に来る最も標準的な場合の式を最初に用意 し、その式をもとにして他の場合の式を作る ようにするのがよい。
d o b a n g o u = 1 , k o s u u i f ( b a n g o u = = 1 ) t h e n k i o n 1 r e t s u _ l o w p a s s 1 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u ) + k i o n 1 r e t s u ( b a n g o u + 1 ) ) / 2 . 0 e l s e i f ( b a n g o u = = k o s u u ) t h e n k i o n 1 r e t s u _ l o w p a s s 1 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u - 1 ) + k i o n 1 r e t s u ( b a n g o u ) ) / 2 . 0 e l s e k i o n 1 r e t s u _ l o w p a s s 1 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u - 1 ) + k i o n 1 r e t s u ( b a n g o u ) & + k i o n 1 r e t s u ( b a n g o u + 1 ) ) / 3 . 0 e n d i f i f ( b a n g o u = = 1 ) t h e n k i o n 1 r e t s u _ l o w p a s s 2 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u ) & + k i o n 1 r e t s u ( b a n g o u + 1 ) & + k i o n 1 r e t s u ( b a n g o u + 2 ) ) / 3 . 0 e l s e i f ( b a n g o u = = 2 ) t h e n k i o n 1 r e t s u _ l o w p a s s 2 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u - 1 ) & + k i o n 1 r e t s u ( b a n g o u ) & + k i o n 1 r e t s u ( b a n g o u + 1 ) & + k i o n 1 r e t s u ( b a n g o u + 2 ) ) / 4 . 0 e l s e i f ( b a n g o u = = k o s u u - 1 ) t h e n k i o n 1 r e t s u _ l o w p a s s 2 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u - 2 ) & + k i o n 1 r e t s u ( b a n g o u - 1 ) & + k i o n 1 r e t s u ( b a n g o u ) & + k i o n 1 r e t s u ( b a n g o u + 1 ) ) / 4 . 0 e l s e i f ( b a n g o u = = k o s u u ) t h e n k i o n 1 r e t s u _ l o w p a s s 2 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u - 2 ) & + k i o n 1 r e t s u ( b a n g o u - 1 ) & + k i o n 1 r e t s u ( b a n g o u ) ) / 3 . 0 e l s e k i o n 1 r e t s u _ l o w p a s s 2 ( b a n g o u ) = & ( k i o n 1 r e t s u ( b a n g o u - 2 ) & + k i o n 1 r e t s u ( b a n g o u - 1 ) & + k i o n 1 r e t s u ( b a n g o u ) & + k i o n 1 r e t s u ( b a n g o u + 1 ) & + k i o n 1 r e t s u ( b a n g o u + 2 ) ) / 5 . 0 e n d i f w r i t e ( * , ' ( i 4 , 3 f 6 . 2 ) ' ) b a n g o u , k i o n 1 r e t s u ( b a n g o u ) , & k i o n 1 r e t s u _ l o w p a s s 1 ( b a n g o u ) , k i o n 1 r e t s u _ l o w p a s s 2 ( b a n g o u ) e n d d o
これらを参考にして、各月の気温の移動平均を計算する機能を追加したプログラムを作成せよ [みほん]。 そのプログラムを用いて (例の如く gfortran enshu06d.f90 などとして a.out を新たに作った後に)
$ cat matsuyama-kion2.txt | ./a.outと実行し、正しい (言い換えれば「自分の意図した通りの」) 出力が得られているかどうかを確認せよ。 なお、正しく計算できていれば、出力の先頭5行と末尾5行はそれぞれ以下のようになっているはずである。
1 4.80 6.15 7.03 2 7.50 7.03 8.93 3 8.80 10.30 10.58 4 14.60 13.53 13.94 5 17.20 17.80 17.44
1604 28.90 28.07 25.34 1605 27.30 25.20 23.68 1606 19.40 20.50 19.94 1607 14.80 14.50 17.70 1608 9.30 12.05 14.50
正しい出力が得られていることが確認できたら、
$ cat matsuyama-kion2.txt | ./a.out > matsuyama-kion4.txtと実行することにより、出力を matsuyama-kion4.txt という名前のファイルに書き出させておくこと。
移動平均のグラフを描く (その2)
上で計算した2種類の移動平均の違いを、Gnuplot でグラフを描かせて調べてみよう。 再び端末から Gnuplot を起動し、以下のように入力してみよう (gnuplot> は Gnuplot のプロンプト)。
gnuplot> plot [1488:1608] "matsuyama-kion4.txt" using 1:2 with lines, "matsuyama-kion4.txt" using 1:3 with lines, "matsuyama-kion4.txt" using 1:4 with linesこれにより表示されるグラフをよく観察してみよ。 もともとの平均気温のグラフと、2種類の移動平均のグラフとをよく見比べることにより、これらの間にはどのような違いがあるかを考えよ。 特に、2種類の移動平均のグラフの違いに注目し、「移動平均をとる際に含めるデータ」を多くとることによって「ギザギザ」のなまり方がどう変わっているかを検討せよ。 また、さらに
gnuplot> plot [1488:1608] "matsuyama-kion4.txt" using 1:($2-$3) with lines, "matsuyama-kion4.txt" using 1:($2-$4) with linesをとして表示される2つのグラフを比較することによって、移動平均によってなまらされた「ギザギザ」の成分の特徴がどう変わっているかについても考えてみよ。 その際、「たて軸」方向に見える「ギザギザ」の成分の大きさ の違いだけでなく、「よこ軸」方向に見える「ギザギザ」の成分の時間方向の広がりの程度 の違いにも注目してみること。
余力がある人向きのおまけ: もっと「実用的」な移動平均のプログラミング
上で作成した移動平均のプログラムからも分かるように、移動平均をとるのに用いるデータの個数が大きくなるほど、より複雑な場合分けが必要になってくる。 これだと「前後1つ」や「前後2つ」の移動平均ならまだしも、例えば「前後5個」くらいまでとった移動平均のプログラミングなんて、とてもやる気にならなくなる。 しかし、なぜ場合分けをする必要があったかに注目してやれば、もっとシンプルかつ実用的なプログラミングが可能になる。
このプログラム (コピペ可) は、場合分けを長々と書き並べなくてもよいように作った移動平均のプログラムの例である。 ここでは整数型変数の mado_haba_half の値により、自分とその前後いくつずつを使った移動平均を計算するかを指定できるようになっている。 加えて、実際に移動平均を計算する際には、別の整数型変数 bangou_hajime と bangou_owari を用いて、何番目から何番目のデータの総和をとることが可能か、また別の整数型変数 souwa_no_kosuu を用いて 何個のデータの総和をとったか をプログラム中で自動的に調べるようにしてある。 なお max や min は、カッコ内の値からそれぞれ最大値と最小値を選び出す組み込み関数である。 組み込み関数の説明は ここ を、また他の組み込み関数の例はここ を参照のこと。
余力のある人は、移動平均をとる前後のデータの個数を 2 よりも大きくした場合に、移動平均の性質がどう変化していくかを調べてみよ。 また元のデータには12ヶ月を単位とする周期的な変動があるはずだが、その周期と比べて十分大きな幅 (例えば前後6個ずつなど) で移動平均をとってみると、どんな出力が得られるかを確認してみよ。
なお既に気付いている人もいるであろうが、上で作成した移動平均のプログラムには、「移動平均をとるデータの総数が奇数」に限られているという (実はけっこう残念な) 制約があった。 まだまだ余裕のある人は、このプログラム あるは このプログラム (いずれもコピペ可) を参考にして、「移動平均をとるデータの総数が奇数でも偶数でもOK」というプログラムを作成してみよ。 また元のデータには12ヶ月を単位とする周期的な変動があるはずだが、その周期と全く同じ幅 (合計12個のデータ) あるいはその整数倍で移動平均をとってみると、どんな出力が得られるかを確認してみよ。
出席確認用プログラム提出フォーム
Moodle のコースページ 以下の 課題ファイル提出 により、各自で作成した (enshu06c.f90 に相当する) 「自分とその前後1つずつ」を使った移動平均を計算する Fortran 90 プログラムの最終版を提出せよ。