情報地球科学演習 (2024年前学期) 第02回

前回の補足

よい「手抜き」のススメ

普段の学業においては「手抜き」は非難の対象であるが、この演習中は以下のような「手抜き」を有効活用することを勧める。 なぜならこれらは、無用なタイプミスを防いでくれる などの効果が大きいからである。

Fortran 90 の文法や機能が気になって仕方がない人へ

既に気付いているとは思うが、この演習で示しているサンプルプログラムの中には、これまでにまだ習っていない (はずの) Fortran 90 の文法や機能が (けっこう多く) 使われている。 そのような機能はこれから先に少しずつ説明を加えていく予定であるので、当面は「そういうもんだ」と思っていてほしい。 外国語を勉強する場合と同様に、プログラミング言語を勉強する時にもまずは 「習うより慣れろ」 という心掛けが大事なのだ (という経験をしてきたので、なおさらそう思う)。

ただし、どうしても気になる人向けに、参考書としてシラバスにも掲載している「Fortran 90 プログラミング」という本の web 版を ここ からたどれるようにしている。 必要に応じて利用されたし (ただし、どうせなら本を買ったほうがいいと思うけれど)。

今日のテーマ: 平均・分散・標準偏差 (その1)

最初の目標として、「各年の平均気温を求め、それを表示させる」ことを考える。 そのためにはまず、何はなくとも 各月の平均気温の総和をとる ための方法を考えてやる必要がある。

なお本来は、各月に含まれる日の数 (1月なら31日分、4月なら30日分とか) に応じた「重み」をつけて平均を計算してやる (これを 「重みつき平均」 という) 必要があるのだが、ここでは (面倒なので)、各月の平均気温の総和を12で割る ことで年平均気温が求まるものとする。

方法その1: ベタベタなやり方

準備として、前回 作成した enshu01.f90 からスタートし、「各年の 1月から4月までの気温の平均 を求めて表示する」機能を追加したプログラムの例を示す。 もとの enshu01.f90 と比べて、どこがどう違っているかに注目せよ。 なお、以下で 薄い文字で書いてある行は、新たに書き足す必要のない 行であることを示す。

program enshu02a                                        
implicitnone
integer::seireki,joutai
real,dimension(12)::kion
real::kion_nen_heikin
do
read(*,'(i4,12f5.1)',iostat=joutai)seireki,kion
if(joutai/=0)exit
kion_nen_heikin=(kion(1)+kion(2)&
+kion(3)+kion(4))/4.0
write(*,'(i4,13f6.1)')seireki,kion,kion_nen_heikin
enddo
endprogramenshu02a

このプログラムのミソは

これを参考にして、各年の気温の平均 (要するに「1月から12月までの気温の平均」) を計算する命令がどう書けるかを考えよ。 そして、enshu01.f90 にその機能を追加したプログラムを作成せよ [みほん]。 なお (当然気付いているとは思うが)、もともとの enshu01.f90 をコピーして新たなファイル (例えば enshu02a.f90) を作り、それを編集するのが簡単。 そして

$ gfortran enshu02a.f90
によりコンパイルを行い、gfortran に怒られなかったら、以下の手順によりプログラムを実行する。
$ cat matsuyama-kion.txt | ./a.out

変更後のプログラムを実行すると、各行の最後 (13番めの実数) にその年の平均気温が出力されているはずだ。 自分の作ったプログラムが平均気温を正しく計算できているか を、2023年の気温データを例にとって確認せよ。 確認には電卓 (コンピュータに付属のものでもOK) を使ってよい。 なお gfortran に怒られなかった」とか「プログラムが転ばなかった」からといって「正しく計算できた」と断定できる訳がない (当然) のだから、自分でプログラムを作る場合でも、こうした確認作業は必ず行うべき である。

なお正しく計算できていれば、プログラムの出力 (の最後の1行) は以下のようになるはずである。 各行の最後の数字 (下の例では 17.8) でその年の年平均気温が出力されたことになっている。

2023   6.5   7.6  12.7  15.9  19.8  23.1  28.0  28.9  27.3  19.4  14.8   9.3  17.8

「平均」の意味をグラフから理解してみよう

前回も少し使ってみたグラフ化ツール Gnuplot を使って、計算で求まった「平均」の意味をグラフで確認してみよう。 まずは端末で以下のように入力してみよう ($ は端末のコマンドプロンプト)。

$ gnuplot
すると Gnuplot の入力画面に入る。 そこで (gnuplot>Gnuplot のプロンプト)
gnuplot> plot "< tail -n 1 matsuyama-kion.txt | awk '{for (i=2;i<14;i++) print i-1,$i}'" with linespoint
と入力する (コピペ可) すると、去年の月平均気温 (正確には「matsuyama-kion.txt の最後の行のデータ」) から折れ線グラフを描くことができる。 さらに
gnuplot> plot "< tail -n 1 matsuyama-kion.txt | awk '{for (i=2;i<14;i++) print i-1,$i}'" with linespoint,17.8
と入力する (こちらもコピペ可) すると、去年の月平均気温のグラフに、それらの平均値が重ねて表示される。 各月の気温を表す折れ線グラフと、その平均値を表す直線の位置関係に注目することで、平均値のもつ意味を確認せよ。

ちなみにこのグラフ化の操作では、ちょっとした Gnuplot の裏技だったり、awk という別のプログラミング言語を、実にさりげなく (断りもなしに) 使っていたりする。 そのうち awk について知りたくなった人は http://www.ie.u-ryukyu.ac.jp/~e085739/awk.html なんかを見てみるといいかも。

方法その2: いろいろと融通のきくやり方

「方法その1」で使ったやり方では、扱うデータの数がものすごく増えたときに面倒で仕方がない。 そこで「方法その2」では、データの数が増えてもプログラミングの手間が増えないやり方を示す。

その準備として、「各年の 1月から4月までの気温の平均 を求めて表示する」プログラムの例を示す。 もとの enshu01.f90enshu02a.f90 と比べて、どこがどう違っているかに注目せよ。

program enshu02b                                        
implicitnone
integer::seireki,joutai
real,dimension(12)::kion
real::kion_nen_heikin,kion_nen_souwa
integer::i
do
read(*,'(i4,12f5.1)',iostat=joutai)seireki,kion
if(joutai/=0)exit
kion_nen_souwa=0.0
doi=1,4
kion_nen_souwa=kion_nen_souwa+kion(i)
enddo
kion_nen_heikin=kion_nen_souwa/4.0
write(*,'(i4,13f6.1)')seireki,kion,kion_nen_heikin
enddo
endprogramenshu02b
このプログラムのミソは、

これを参考にして、各年の気温の平均 (要するに「1月から12月までの気温の平均」) を計算する命令がどう書けるかを考えよ。 そして、enshu01.f90 にその機能を追加したプログラムを作成せよ [みほん]。 またここでももちろん、自分の作ったプログラムが平均気温を正しく計算できているかを確認せよ。 さらに本日の演習の出席確認のため、このプログラムを 末尾のフォーム 経由で提出せよ。

方法その3: Fortran 90 の「組み込み関数」を使うやり方

上のプログラムのミソである 配列の「要素」の総和を求める手順は、 Fortran 90 の機能をもっとうまく使うと、もっと簡略な書き方が可能 である。 具体的には、配列 kion の「要素」12個の総和を求める手順は、以下の1行で OK。

     kion_nen_souwa = sum(kion) 

これを参考にして、各年の気温の平均 (要するに「1月から12月までの気温の平均」) を計算する命令がどう書けるかを考えよ。 そして、enshu01.f90 にその機能を追加したプログラムを作成せよ [みほん]。 またここでももちろん、自分の作ったプログラムが平均気温を正しく計算できているかを確認せよ。

この sumFortran 90 で用意されている 組み込み関数 の1つであり、上の例では 「配列 kion の全ての要素の値の総和をとってください」 という意味になる。 こういうところからも、「配列」という ある意味をもったデータの集まり を考えることの大事さを感じてもらえるだろう。

Fortran 90 には他にも多くの「組み込み関数」が用意されている。 2年生後期の実験で出てきた「乱数を発生させる関数」 rand もその例の1つ。 他の例は ここ などを参照のこと。

なお sum のような、配列を直接操作できる組み込み関数は、古い規格の Fortran (Fortran 77 とか) ではそもそも用いることができなかった。 であるから、ものすごく歴史の古い Fortran プログラムでは、「方法その2」のような書き方が頻繁に使われている はずだ。 Fortran 90 の世界では、わざわざ「方法その2」を使う理由は必ずしもないのではあるが、こうした書き方があることを知っていて損はない (と思う) し、こうした書き方をするほうが便利なことも (場合によっては) ある。

余力のある人向け: 「重みつき平均」

より正確な「年平均気温」を求めるために、各月に含まれる日の数 (1月なら31日分、4月なら30日分とか) に応じた「重み」をつけた 「重みつき平均」 で計算してみよう。

プログラム例 (その1, その2) を参考にして、重みつき平均の考え方を用いて年平均気温を求めるプログラムを作ってみよ。 なおここでは簡単のため、うるう年はない (要するに「2月は常に28日まで」で「1年は常に365日」) ものと仮定してある。 この方法で計算した年平均気温の値は、これまでのやり方で求めた年平均気温とどれくらい違っているか。

ただし実際に「重みつき平均」をプログラミングするには、「この月は何日あって....」という場合分けが結構面倒であり、エレガントな書き方をするのが (できなくはないけど) 難しい。 そのため、「方法その1」に基づいたプログラミングをするのが最もやりやすい (と思う)。

余力のある人向け: 各年の気温の分散と標準偏差を求める

次回から数回分をかけて「過去 134 年間の○月の気温の平均・分散・標準偏差を求める」ことを目標として演習を行っていくことにしている。 ここではその準備として 「各年の気温の分散・標準偏差」を求めるプログラムを作ってみよう。

1限の授業で示した通り、分散や標準偏差をプログラミングで求めるには、 「平均」に加えて「2乗の平均」も求めておく 必要があった。 ということで具体的には、これまでに作った「平均」を求めるプログラムに「2乗の平均」を求める機能をまず追加し、その後に分散や標準偏差を求める機能をさらに付け加えてやればよいことになる。

余力のある人は下のプログラム例を参考にして、各年の気温の平均を求めるプログラムに、分散・標準偏差を全て計算する機能を追加したプログラムを作ってみよ。 このプログラム例は、「方法その2」に基づいた方法で、各年の気温の平均に加えて分散・標準偏差も計算して表示するものである。 以下これまでと同様に、薄い文字で書いてある行は、新たに書き足す必要のない 行であることを示す。

このプログラムのミソは、

program enshu02e                                                
implicitnone
integer::seireki,joutai
real,dimension(12)::kion
real::kion_nen_heikin,kion_nen_souwa
real::kion_nen_bunsan,kion_nen_hensa
real::kion2_nen_souwa,kion2_nen_heikin
integer::i
do
read(*,'(i4,12f5.1)',iostat=joutai)seireki,kion
if(joutai/=0)exit
kion_nen_souwa=0.0
kion2_nen_souwa=0.0
doi=1,12
kion_nen_souwa=kion_nen_souwa+kion(i)
kion2_nen_souwa=kion2_nen_souwa+kion(i)**2
enddo
kion_nen_heikin=kion_nen_souwa/12.0
kion2_nen_heikin=kion2_nen_souwa/12.0
kion_nen_bunsan=kion2_nen_heikin-kion_nen_heikin**2
kion_nen_hensa=sqrt(kion_nen_bunsan)
write(*,'(i4,13f6.1,2f6.2)')seireki,kion,kion_nen_heikin&
,kion_nen_bunsan,kion_nen_hensa
enddo
endprogramenshu02e

正しく計算できていれば、プログラムの出力 (の最後の1行) は以下のようになるはずである。

2023   6.5   7.6  12.7  15.9  19.8  23.1  28.0  28.9  27.3  19.4  14.8   9.3  17.8 57.90  7.61
                                                                               ↑   ↑     ↑
西暦   1月   2月   3月   4月   5月   6月   7月   8月   9月  10月  11月  12月  平均  分散  標準偏差
また再び gnuplot を起動し、(gnuplot>Gnuplot のプロンプト)
gnuplot> plot "< tail -n 1 matsuyama-kion.txt | awk '{for (i=2;i<14;i++) print i-1,$i}'" with points,17.8,17.8+7.61,17.8-7.61
として表示されるグラフに基づいて、平均や標準偏差の意味を確認してみよ。

出席確認用プログラム提出フォーム

Moodle のコースページ 以下の 課題ファイル提出 により、各自で作成した (enshu02b.f90 に相当する) 各年の気温の平均を計算する Fortran 90 プログラムの最終版を提出せよ。