とらりもんHOME  Index  Search  Changes  Login

python入門

筑波大学生物資源学類 奈佐原顕郎

  • 注: Ubuntu Linux 16.04での実行を前提とします。
  • 注: あえて細かい解説は載せていません。必要に応じてネットで検索したりして自分で調べよう!

なぜpythonなのか?

問1-1. 「プログラミング言語 ランキング」で検索してみよ。人気が高いのはどういうプログラミング言語か?

問1-2. 「人工知能 プログラミング言語」で検索してみよ。どういうプログラミング言語が最もたくさん出てくるか?

問1-3. pythonの公式ホームページを探して, 覗いてみよう。

pythonをさわってみよう(1)

問2-1. 以下の手順で, pythonの実行環境(pythonの言葉で計算機を操作できる環境)に入ってみよう:

  • Ubuntu Linuxで, ターミナルを起動せよ(CTRL + ALT + T)。
  • その後, ターミナルで以下のコマンドを実行せよ。ただし$はプロンプトなので打つ必要なし。また, 打ち終わったらEnterキーを押そうな。
$ python3
  • → その結果, 以下のような表示が出るはず(多少違っても気にしない! すんごい違ってたら何かおかしい)
Python 3.6.1 |Continuum Analytics, Inc.| (default, May 11 2017, 13:09:58)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
  • この>>>がpythonのプロンプトである。

問2-2. 問2-1の結果の, >>>のすぐ右に続けて以下のように打ってみよう:

>>> 3+4
  • → その結果, 7と表示されて, その下にまた>>>と出てくるはず。このように, >>>というプロンプトに続けて, 何か打てばpythonは何かやってくれる。これがpythonの基本的な使い方である!

問2-3. 問2-2の結果に続いて, CTRL + Dを打ってみよう(CTRLキーを押しながらDキーを押す)。

  • → Linuxシェルのコマンドプロンプト$に戻ったはず。

pythonをさわってみよう(2)

問3-1. Ubuntuのターミナルから, 以下のコマンドを打ってみよ:

$ ipython3
  • さきほどやった問2-1とどう違うか? たぶんこっちの方が便利なので, 以後, こっちを使う。

問3-2. pythonで以下を試してみよ。これらは何の計算だろうか?

2**5
2**3**4

pythonは, 指数関数や三角関数などの数学関数を標準では持っていない。それらを使うには, 以下のように「インポート」が必要である。

問3-3. pythonで以下を試してみよ。

import math
math.exp(1)
math.pi
math.sin(math.pi/4)

mathというのは数学関数を提供する「モジュール」である。このように, pythonは, 必要な機能を持った「モジュール」を「インポート」して使う!

問3-4. pythonで, 以下の値を計算してみよ。

  1. √2
  2. tan 10度

問3-5. pythonで以下の命令をやってみよ。意味を考えよ。

x=2e3
x
x=2e-3
x

問3-6. pythonで以下の2つの命令をやってみよ。違うならば, 何がどう違うのか?

100**10
100.0**10

このように, 数値はeという字を使って位どりを使って表すことができる。これは非常に大きな数や, 非常に小さな(0にちかい)数を表すのに便利である。

pythonで繰り返しをやってみよう

例(やってみよう!)

for i in range(0,10):
   print("I am happy!")

上の例のように, 同じような処理を繰り返し行うには, for文というものを使う。これはpythonに限らず, 多くの計算機言語に共通の機能である(文法はそれぞれの言語で違うが)。

例(やってみよう!)

for i in ["happy!", "lucky!", "sleepy!", "hungry!"]:
   print("I am "+i)

例(やってみよう!)

for i in range(0,10):
   print(i)

問4-1. 上の例を参考にして, 3から15までの数字を表示してみよ。

問4-2. 上の例を参考にして, 20から0までの数字を, 2きざみで漸減的に表示してみよ。20, 18, 16,...というふうに。ヒント: python rangeで検索してみよ。

例(やってみよう!)

x=0
for i in range(0,5):
   x=x+i
   print(i, x)

この例で, x=x+iというのに戸惑った人がいるだろう。この=は数学的な「等号」を意味するのでなく, 「右辺の計算結果を左辺に代入せよ」という記号である。pythonだけでなく, 多くのプログラミング言語ではそうなっているので覚えておこう!

問4-3. 上の例を少し変えて, 0から10までの整数を足してみよ。

問4-4. 上の例を少し変えて, 1から10までの整数を掛けてみよ(10の階乗)。

問4-5. mathモジュールには階乗を計算する「関数」がある。それを探して利用し, 10の階乗を求めよ。

問4-6. 1/0!+1/1!+1/2!+1/3!+...+1/n!の値を, n=5までとn=10までのそれぞれについて計算してみよ。問4-5を利用してよい。

問4-7. pythonを知る人は, 「pythonではインデントが重要である」とよく言う。それはどういう意味なのだろう。ネット検索等を駆使して理解せよ。

pythonで「関数」を作ってみよう

上の問4-3 ~ 問4-6のようなことを, n=10やn=100など, 異なる「終着点」についていろいろ試したいようなときには, いちいちpythonの命令を書き直すのはめんどくさい。そういう場合は, 命令を「関数」としてまとめて定義する。以下の例は, 0からnまでの整数の和を求める関数を定義している:

例(やってみよう!)

def sum(n):
   x=0
   for i in range(0,n+1):
       x=x+i
   return(x)

この関数を使うには, 以下のようにすればよい:

sum(2)
sum(3)

問5-1. 上の例をもとに, 問4-6を, 関数を使ってやりなおしてみよ。関数の名前はnapierとせよ。つまりたとえばnapier(3)は1/0!+1/1!+1/2!+1/3!を求める。

問5-2. 上の例をもとに, 整数nから整数mまでを順に足す関数を作れ。

問5-3. こうやって自分で作った関数は, pythonを終了して再起動しても, 利用できるのだろうか? ためしてみよ。

pythonで散布図を描いてみよう

例(やってみよう!)

import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0,10,1)
y = 2*x
plt.scatter(x, y)
plt.show()

問6-1. 上の例を応用して, 関数y=x^2の, x=-3, -2, -1, 0, 1, 2, 3のそれぞれにおける点をグラフにプロットせよ。

問6-2. 上の例を応用して, 半径1の円周上の点を, 15度間隔でグラフにプロットせよ。

pythonで行列をいじってみよう。

例(やってみよう!)

import numpy as np
np.zeros([3,3])
np.ones([4,2])
np.ones([4,2]).T
np.zeros([3,3])+5
np.ones([3,3])*5
np.identity(4)
x=np.array([1,2,3,4,5])
y=np.array([1,1,1,1,1])
z=np.tensordot(x,y,0)
import matplotlib.pyplot as plt
plt.imshow(z)
plt.show()

解説: pythonでは, 数ベクトルや行列を, numpyモジュールで定義されている, ndarrayという「オブジェクト」で扱うのが一般的である。上の例で出てきた数ベクトルや行列は, 全てnumpy.ndarray「オブジェクト」の「インスタンス」である。オブジェクトって何? インスタンスって何? と思ったら, 適当にネットで検索したりして調べてみよ。すぐにはわからないかもしれないが, こういうのはなんとなく慣れていけばそのうちわかるものである!

問7-1. 上の例を応用して, 以下のような行列を作ってみよ。

      [[ 1,  2,  3,  4,  5],
      [ 2,  4,  6,  8, 10],
      [ 3,  6,  9, 12, 15],
      [ 4,  8, 12, 16, 20],
      [ 5, 10, 15, 20, 25]]

問7-2. 上の例の最後で出た図を, 横倒しにしたような図を作れ。

計算機も間違える! ... 計算誤差を体験しよう

問8-1. pythonで以下の計算を行え(それぞれ0は15個):

1000000000000000.1-1000000000000000

答はぴったり0.1になるはずなのに... !? このような現象を, 「桁落ち」という。桁落ちについて, 検索などで原因を調べてみよ。

問8-2. pythonで, for文を使って, 0.000001を100万回, 足してみよ。1に等しくなるか?

問8-3. pythonで, for文を使って, 10000000000, つまり10^10に, 0.000001を100万回, 足してみよ。正しい値, つまり10000000001.0になるか?

問8-4. pythonで, for文を使って, 1000000000000, つまり10^12に, 0.000001を100万回, 足してみよ。正しい値, つまり1000000000001.0になるか?

これらのような困った現象を, 「精度落ち」という。精度落ちについて, 検索などで原因を調べてみよ。

問8-5. pythonで以下の計算を行え:

10.0**10
10.0**100
10.0**1000

この問は, 10.0の累乗を求めているが, 10.0の100乗は平気だけど, 10.0の1000乗はエラーが出るだろう。この現象を「オーバーフロー」という(調べてみよう!)。では, 10.0の何乗までならできるだろうか? 試してみよう!!

pythonスクリプトを作ってみよう

ここまでは, pythonの命令を, 逐次, 画面に打ち込んでいたが, そろそろ同じようなことを何回も打つことに疲れてきたのではないだろうか。関数を使えば省力化できるが, python環境を閉じると消えてしまうのが難点である。そこで, pythonのコマンド(の集まり)を, どこか別のファイルにまとめて, 編集・保存しておき, 必要に応じてそれを呼び出す, というふうにするのが便利である。そのようなファイルのことを「スクリプト」という。

問9-1 Linuxの端末(コンソール)を新たに立ち上げ, ipython3を走らせているのと同じディレクトリで, test.pyというファイル名で以下の内容のテキストファイルを作れ:

for i in range(0,10):
   print(i)

その後, pythonの中で(ipython3のコマンドラインで), 次のように打ってみよ:

run test.py

0から9までの数がばらばらっと並んだら成功。

問9-2 以前やった, 問6-1を, parabola.pyというファイル名のスクリプトにして, ipythonの中から実行してみよ。

pythonスクリプトは, ipythonの外でも, つまりLinuxのシェルからでも実行できる。

問9-3 以下のコマンドを, Linuxシェルで実行してみよ($は打ちこむ必要なし):

$ python3 test.py
$ python3 parabola.py

pythonで変な図形を描いてみよう

例(やってみよう!)螺旋

import numpy as np
import matplotlib.pyplot as plt
t=np.arange(0,100,0.1)
plt.plot(np.cos(t)*np.exp(-t/10), np.sin(t)*np.exp(-t/10))
plt.show()

問10-1 上の例で, らせんが中心に落ちていくのをもっとゆるやかにするにはどうすればよいか? 考えてやってみよ。

例(やってみよう!)

t=np.arange(0,100,0.005)
plt.plot(np.cos(3*t)*np.exp(-t/30), np.sin(4*t)*np.exp(-t/30))
plt.show()

問10-2 上の例をいろいろ変えて, もっとカッコよくて変な図形を描いてみよ。

例(やってみよう!)

L=500
i=np.arange(-L/2,L/2)
j=np.zeros(L)+1
x=np.tensordot(j,i,0)
y=np.tensordot(i[::-1],j,0)
plt.imshow(x*y)
plt.show()

問10-3 上の例に続いて(というか, いったんグラフのウィンドウを閉じて), 以下をためしてみよ:

plt.imshow(x*y%100)
plt.show()

出てきたグラフのウィンドウを, マウスで拡大したり縮小したりしてみよ。何かパターンが変わって見えないか? それはなぜなのだろうか? (この変な現象を「エイリアシング」という)

問10-4 上の問に続いて(というか, いったんグラフのウィンドウを閉じて), 以下をためしてみよ:

plt.imshow((x%y)%100)
plt.show()

簡単な関数や計算の組み合わせで, 思いもかけないようなおもしろくてきれいな図形が描けることがわかるだろう。これは数学の美しさや豊かさの一種ではないだろうか?

pythonでモンテカルロ・シミュレーション

例 (やってみよう!) 1次元のランダムウォーク

def suiho(n):
   x=[0]
   for i in range(0, n):
       x += [x[-1]+np.random.rand()-0.5]
   plt.plot(x); plt.show()

suiho(10)
suiho(100)
suiho(1000)

解説: 酔歩(ランダムウォーク)のシミュレーションである。横軸が時間(ステップ数), 縦軸が出発点からの変位である。

問11-1 10000ステップのシミュレーションをやってみよ。

例 (やってみよう!) 2次元のランダムウォーク

def suiho2(n):
   x=[0]
   y=[0]
   for i in range(0, n):
       x += [x[-1]+np.random.rand()-0.5]
       y += [y[-1]+np.random.rand()-0.5]
   plt.plot(x, y); plt.show()

suiho2(10)
suiho2(100)
suiho2(1000)

解説: 2次元版の酔歩(ランダムウォーク)のシミュレーションである。

問11-2 10000ステップのシミュレーションをやってみよ。

pythonで微分方程式を解こう

例(やってみよう!) ロトカ・ヴォルテラ方程式

def LV(n, a, b, c, d, dt):
  x=[1]
  y=[0.2]
  dt=0.1
  for i in range(0, n):
      nx = x[-1]+ (a*x[-1]+b*x[-1]*y[-1])*dt
      ny = y[-1]+ (c*y[-1]+d*x[-1]*y[-1])*dt
      x += [nx]
      y += [ny]
  plt.plot(x); plt.plot(y); plt.show()

LV(500, 0.4, -0.9, -0.3, 0.5, 0.05)

解説: LV()の中の数値を変えると, いろんな設定でのシミュレーションができる。

問12-1 基礎数学IIのテキストの問538を, pythonで再現せよ。

問12-2 基礎数学IIのテキストの問544を, pythonで解き直せ。

血液型の人口動態シミュレーション

 最後に, pythonを使って現実問題のシミュレーションをやってみよう。世の中にはいろんな血液型の人がいるが, それぞれの血液型が人口の中に占める比率は, 世代と共にどう変わっていくのだろうか?

 よく知られているように, 人の血液型は, A, B, Oの3種類の遺伝子が2つ組み合わさってできる(ここではRH+/-などは考えない)。AAとAO(=OA)はA型, BBとBO(=OB)はB型, ABはAB型, OOはO型である。そのような組み合わせまで考慮すれば, 人の血液型は, AA, AB, AO, BB, BO, OOの6種類である。

 AO型とAB型のカップルからは, AA, AB, AO, BOという4種類の血液型のどれかをもつ子が生まれる(OO型やBB型は生まれない!)。そのように, 生まれる子どもの血液型は親の血液型(の組み合わせ)で決まる。

 まず練習として, AA型, AB型, BB型しかいない世界を考えよう。ある世代における, それぞれの血液型の人の割合をAA, AB, BBと書き, 次世代のそれぞれの血液型の人の割合をnAA, nAB, nBBと書こう(nはnextの意味)。カップルの相性は血液型には依存しないとし(これは後に検討する), また, 血液型の人口比は男女でかわらないとする。pythonでは, nAA, nAB, nBBは次のように求められることはわかるだろうか?

nAA = AA*AA + AA*AB/2 + AB*AA/2
nAB = AA*BB + BB*AA + AB*BB/2 + AB*AB/2 + BB*AB/2
nBB = AB*BB/2 + BB*AB/2 + BB*BB
sum=nAA+nAB+nBB
nAA=nAA/sum
nAB=nAB/sum
nBB=nBB/sum

問13-1 この考え方を基に, 以下のような関数をpythonで作れ:

  • 名前はbloodAB()
  • 引数は, ある世代のAA, AB, BB型のそれぞれの割合と, そこから計算する世代の数(n)
  • 出力は, n世代後のAA, AB, BB型のそれぞれの割合

つまり, たとえばblood(0.4,0.3,0.3,10)と打てば, AA, AB, BBのそれぞれが4割, 3割, 3割の世代から10世代後の各血液型の割合が出てくる, というかんじ。

問13-2 これが正しく動いていることを確認せよ。どうやれば確認できるだろうか? 非常にシンプルなケース(全員AA型だとか, AAとBBが半々でABが0とか)について1世代だけまわしてみて, 理論的な結果に合うかどうかを確認するのである。こういう確認法は, 計算機シミュレーション研究では常套手段である。

問13-3 これを, AA, AB, AO, BB, BO, OOの6種類に拡張せよ。

問13-4 これが正しく動いていることを確認せよ。知恵を使おう!

問13-5 現在, 日本の血液型の人口比は, AA=0.08, AB=0.10, AO=0.31, BB=0.03, BO=0.19, OO=0.29である。この比率は, 1世代後, 5世代後, 100世代後のそれぞれではどうなるか?

さて, ネットで調べると, 「A型とB型はあんまり相性が良くない」という言説が見つかった。これが本当かどうかを調べよう。すなわち, A型とB型は(他の血液型どうしの組み合わせに比べて)カップルになりにくいとして, その影響をfというパラメータであらわそう。このfは, 0から1までの値をとる。たとえばf=0.9なら, 相性が問題ない(f=1.0)場合の0.9倍の本土でしかA型とB型のカップルが成立しない, という意味である(AA*BB, AO*BB, AA*BO, AO*BOのどの場合も共通のfを使う)。fも引数として関数に組み込むこと。

問13-6 このfを組み込んでシミュレーションを行え。もしf=0.9で, 100世代まわしたら, 血液型の人口比はどうなるか? そんな遊びをたくさんやって, 血液型どうしの相性の有無について, 君なりに考察せよ。

Last modified:2018/02/15 13:03:56
Keyword(s):
References: