空飛ぶチンアナゴの統計解析日記

統計解析を嗜むチンアナゴのメモ帳です

本当に初心者が学んでほしいコードの話 〜その3 関数の話1〜

プログラミングおいて関数というのは「何かの仕事をしてくれるコード」と定義すればいいのでしょうか?
「一連のコードを抽象化したもの」という表現もありますが、それもなかなかイメージがつかみにくいので本稿では「何かの仕事をしてくれるコード」として定義します。

関数がどうして必要か?

例えば

list_a = [1, 5, 3, 22, 55, 3, 8]

というようなリストがあり、このリストの平均を求めたいとします。
この程度の短いリストであれば手計算も容易ですので手計算をしてみると

mean_list_a = (1+5+3+22+55+3+8)/7
print(mean_list_a)
# print関数を入れないと結果を表示してくれないので

と計算できます。
では

list_b = [1, 5, 3, 22,(間になんか数字がいっぱいある) ,55, 3, 8]

の平均を計算したいというときはどうしたらいいでしょうか?
手計算するにはとてもしんどいリストです。
ループ処理をつかって計算してみましょう。

list_b1 = [1, 5, 3, 22,44, 55, 6, 8, 90, 53, 66, 22, 55, 3, 8]
# プログラムを動かすためにとりあえず数字を入れた

sum_list_b1 = 0
num_item_list_b1 = 0

for i in list_b1:
   sum_list_b1 = sum_list_b1 + i
   num_item_list_b1 = num_item_list_b1 + 1

mean_list_b1 = sum_list_b1 / num_item_list_b1

print(mean_list_b1)

とコードを書けば、リストの中身が数字型のデータである限りは、リストの中身の数に関わらず平均値が計算できるようになりました。
では、このコードをコピペして少し改変して

list_c = [3, 5, 6, 22, 44, 2, 1, 777]

の平均やlist_d、list_eの平均値を求めようとした場合何が起きるのでしょうか。

  1. 同じようなコードの繰り返しになり単純に見にくい
  2. その結果、だいたいコピペを途中のどこかでミスる

といったミスが起きますし、実際に起こしたこともあります。

やってることは実質同じなのだからなるべく一つのコードで済ませたい

リストの平均値であれば「リストの中身を合計してリストの中身の数で割る」以外のことをしていないのですから、「リストの中身を合計してリストの中身の数で割る」というコードをなるべく使いまわしたいわけです。
これを「コードの抽象化」と呼んだりします。なるべく使いまわしたいものを一つの「関数」としてまとめることで、コピペミスによるエラーを防いだり、またコードを読みやすくしたりしたいわけです。
もちろん必要に迫られて計算過程を変更する必要があった場合でも、すべてのコードが関数によって書かれていないいわゆる「ベタ打ち」だった場合、計算の回数だけ修正する必要があります。これもコピペと同様に途中で忘れたり、抜けたり、タイポしたりとバグの原因となります。関数で書かれていれば関数一つ直すだけですべての計算過程を自動的に直してくれるので修正箇所は少なく済みます。
工数が増えれば増えるほどエラーは増えるので、なるべく工数は常に減らしたい。だからこそ、なるべく「関数化」して工数を減らしたいと考えるわけです。

関数は「黒い箱」

科学計算に限って言えば、大抵計算に必要な関数は特に入門者や初心者が使うものであれば一通り揃っています。なのでまずはどうやって関数を使うかというところから始めていけばいいと思います。
関数については下の図を最初にイメージすると良いでしょう

f:id:flying-spotted-garden-eel:20210823111036p:plain

関数のイメージ

最初の段階で覚えなくてはいけないものは
1)関数の用途
2)関数に突っ込む変数(引数)
3)関数から返ってくる値(戻り値)
の3つです。
例えばpythonの標準ライブラリーであるstatisticsライブラリーのstatistics.mean()*1関数を例にすると、
1)関数の用途:データの算術平均を求める
2)関数に突っ込む変数(引数):数字型のみのデータを含むリスト型のデータ
3)関数から返ってくる値(戻り値):平均値
となります。
この際、関数から返ってきた値はメモリーに保存されません。
従って、結果を保存したい場合は結果を保存するための変数を用意する必要があります。

実際に関数を使って平均を求めてみる。

では、statistics.mean()関数を使って先ほどのlist_aの平均値を求めてみましょう。

# statisticsモジュールをインポートする
# よく分からなければ、そのまま「import statistics」の部分をShellにコピペする。
import statistics

# 平均値を求めたいデータをリスト型で宣言する
list_a = [1, 5, 3, 22, 55, 3, 8]

# list_aの平均値をmean()関数で求め、変数mean_aに格納する
mean_list_a = statistics.mean(list_a)

# mean_list_aを画面に表示する
print(mean_list_a)

list_aだけでは関数化したメリットを感じにくいかもしれませんが、list_bやlist_cといったリストの平均値も続いて算出する場合、シンプルで読みやすいコードとして書くことができると思います。

まとめ

  1. 関数とは「何かの仕事をしてくれるコード」のこと
  2. 関数を使うことでコピペのミスによるコードのエラーを防いだり、コードを読みやすくしたりすることができる
  3. 関数を使うときは1)関数の用途、2)関数に突っ込む変数、3)関数から返ってくる値を把握してから使うこと
  4. 関数の結果は保存するには、結果を保存するための保存先の変数を作ってそこに保存すること

以上です。
最後まで読んでいただきありがとうございました。