データ処理の基本:成績の集計(3), ライフゲーム(1)


前回の補足


前回の感想,質問より

Q.
教科書や,配布スライド,配布 Notebook の誤りを見つけました.
A.
誤りの指摘は歓迎します.演習時間等に直接伝えるか,ITC-LMSの掲示板等で指摘してください.なお,すでに修正済の場合もあるので,教科書の誤りの場合は「Pythonによるプログラミング入門 東京大学教養学部テキスト アルゴリズムと情報科学の基礎を学ぶ」サポートページ をみて,配布スライド,配布 Notebookについてはダウンロードし直してみて,最新版にも残っている誤りかどうかを確認してもらえると助かります.
Q.
教科書のプログラムを入力するのに時間がかかって,「実行してみるだけ」という投票にも追いつけません.
A.
受講中は「Notebook教材」にある方法で,説明している章のNotebook教材~/algo19 以下に ダウンロードして,Jupyter Notebookからopenして使うことを想定しています(Google Colaboratoryで開くのでも構いません).教科書のプログラムをすべて手入力するのは,タイピングに自信がある人だけにしておいた方が良いと思います.
Q.
関数fizzbuzz 2行目ではfizzbuzz条件をアンドを使って表現していましたが、
  if n % 15 == 0:
のほうが簡潔でいいかなと思いました。
A.
「自然数nが3でも5でも割り切れる」は「自然数nが15で割り切れる」と同値なので,たしかにそのとおりですね.
  if n % 3 == 0 and n % 5 == 0:
と書いた方が有利な例を「無理に」見つけるとすると,コンパイルをして実行する処理系では(Python言語で一般的に用いられる処理系はインタプリタなので「無理に」と書いています)
  if n % 3 == 0 and n % 5 == 0:
    print("Fizz Buzz")
  elif n % 3 == 0: # 3の倍数の場合
    print("Fizz")
  elif n % 5 == 0: # 5の倍数の場合
    print("Buzz")
  else: # いずれでもない場合
    print(n)
のように書くと,
  if n % 3 == 0:
    if n % 5 == 0:
      print("Fizz Buzz")
    else:
      print("Fizz")
  elif n % 5 == 0: # 5の倍数の場合
    print("Buzz")
  else: # いずれでもない場合
    print(n)
と同じとみなして,コンパイル時最適化する余地があるということでしょうか.こちらの方が条件分岐の最大数が減っています.さきほども書いたように,通常のPython処理系ではこのような最適化はおこなってくれないので,意味のない議論ですが.
Q.
実行速度についてですが、 もともとvariance2の方が遅いと推定しました。 なぜなら、return の所で、variance1より長いからです。 でも、実際にはvariance1, variance2 の実行速度は同じとわかった。
A.
「variance1, variance2 の実行速度は同じ」とまでは言っていません.「どちらもscoresの長さに比例する程度の時間」とだけ言っています.「実行する前に問題のサイズに対する実行時間の増え方を解析する」方法では差をみつけられなかったということであり,実際に実行してみて,どちらかが数倍速いという可能性はありますが,実行環境(処理系の違い,マシンの違い)で逆転するということもあります.
Q.
x = x + a のような計算を x += a と書ける略記について、特に a = 1 の場合他のプログラミング言語でできるように x++ と書けた方が楽で良いのにと思いました。
A.
他のプログラミング言語に慣れていると,ついつい x++ と書いてしまいがちですね.Python言語では代入を式ではなく文にするというポリシーがあり,(x = (y = 3 + 2) * 2)のように代入結果を値として参照することができないので,x++ のような表記を採用しなかったのでなないかと思われます.ただし,最近出た Python 3.8 では(x = (y := 3 + 2) * 2) のように,「=」の代わりに「:=」(Walrus operator)を使うと結果を値として参照できるようになったようですね.
Q.
for x in array という形の表記を知ったことから、例えばrange(5)の正体は[0, 1, 2, 3, 4]という配列なのではないかと考えたのですが、実際に検証しようと print(range(5)) を実行してみると range(0, 5) とほぼそのまま出力されてしまい、正体はわかりませんでした。range(5) の実体は配列 [0, 1, 2, 3, 4] であるという推測は正しいのでしょうか。
A.
実は Python の古いバージョンの Python2 では関数range(5) が配列[0, 1, 2, 3, 4]を返す仕様でした.しかし,講義で使っているPython3 ではrange(5) はrange型の「オブジェクト(すみませんが,教科書では詳しく扱っていません)」を返すようになっています.range型のオブジェクトは配列と同じように整数インデックスでのアクセスが可能になっていますが,メモリ効率の点で有利なのでこのように変更されたものと思われます.教科書の「6.4 発展 オブジェクト指向」のところで一応説明がありますが,教科書の説明だけで理解するのは難しそうですね.
  print(list(range(5)))
などを実行すると配列(リスト)に変換して表示させることができます.
Q.
分散を求めるプログラムについて、私ははじめ以下のように書いたのですが、これでは average(scores) という同じ値を len(scores) 回計算していて効率が悪いことに気がつきました。しかし、全く同じ計算ですからもし人間がやるなら当然計算結果を再利用しますよね。この場合Pythonは毎回計算し直すのでしょうか。それとも計算結果を再利用するのでしょうか。
def variance1(scores):
  return average([(x - average(scores)) ** 2 for x in scores])
A.
練習問題 4.6 と同じ意味のプログラムですね.「計算結果の再利用」はコンパイルをして実行する処理系(Python言語で一般的に用いられる処理系はインタプリタなので該当しないことが多い)では,おこなわれないことが多いと思ってください.コンパイルして実行する処理系の場合は「計算結果の再利用」は可能ですが,averageの計算が再利用できるかどうかは,(Haskellのような関数型言語でない場合は)それほど簡単ではないので実際の処理系でおこなわれるかどうかはわかりません.

前回の課題について


授業の登録方法


講義資料


講義フォルダの作成


投票システム

vote.pyをダウンロードして(「リンク先のファイルを別名で保存」で,ホームフォルダの下のalgo19を選択(なければ作る).".txt"を「追加しない」を選ぶ)保存します.ドックからターミナルを起動して,
cd ~/algo19
を済ませてから,
python vote.py 選択肢番号
のように使います.

Jupyter Notebookを使いながら(一旦終了せずに),投票システムも使うには,ターミナルのメニューバーの「シェル」->「新規タブ」を選ぶか,[Command]+[T]で別のタブを開いて(あるいは[Command]+[N]で別のウィンドウを開いて),投票システムを使うことをお勧めします.このあたりのことは,「はいぱーワークブック」15.4 ターミナルの便利な使い方に書いてあるので参考にしてください.


テキストの補足


Notebook教材

以下のNotebook教材は,~/algo19 以下に ダウンロードして,Jupyter Notebookからopenして使ったり, Google Colaboratoryを使って,クラウド実行環境でPythonプログラムを実行できます.ダウンロードする場合もGoogle Colaboratoryの使い方を参照してください.Googleアカウントへのログインを求められたときは,通常のGoogleアカウント「XXX@gmail.com」ではなく,ECCSクラウドメールのアカウント「XXX@g.ecc.u-tokyo.ac.jp」を使ってログインしてください.

今日の課題