トップページに戻る

1日目スライド

Pythonの基礎

  • 型(int, float, ...)
  • if文による分岐
  • forループ
  • 関数の定義
  • モジュール

Pythonの型 (1)

Pythonは動的型付け言語
型宣言などはなく、型を自動で判別してくれる

  • (任意長)整数 int: 2
  • (倍精度)実数 float: 2.0
  • (倍精度)複素数 complex: 2+0j

演算子: +, -, *, /, //(整数部), %(余り), **(べき乗)

In [1]:
a = 2       # 整数
b = 5.0     # 実数
c = -0.5+5j # 複素数

print(a)
print(type(a))
2
<class 'int'>
In [2]:
a = 3
b = 2

print(a**2)
print(a/b) # Python 3.xでは1.5、2.xでは1
9
1.5

Pythonの型 (2)

  • 論理型: True, False

Pythonでは大文字と小文字を区別する

比較演算子: ==, >, <, >=, <=, !=
論理演算子: and, or, not

In [3]:
a = (3 > 2)  # True
b = (3 == 2) # False

print(a)
print(a and b)
print(a and (not b))
True
False
True

Pythonの型 (3)

  • リスト list: [1, 2, 3]
  • タプル tuple: (1, 2, 3)
  • 文字列 str: "abc123"

リストやタプルの配列要素はなんでもよい... 数、文字列、リスト
配列要素のインデックスは、原則0からN-1まで(Nが配列要素数)
ただし、-Nから-1までをインデックスに取ることもできる

len(配列)は配列要素数を返す

In [4]:
a = [1,3,5,7,9] # a[0], a[1], a[2], a[3], a[4]
print(a[0])
print(a[1])
print(a[-1]) # a[-1]=a[4]
print(len(a))
1
3
9
5

配列のスライス(部分配列)

部分配列は、

a[start:stop]
a[start:stop:step]

などの形で得られる。部分配列にa[stop]は含まれないことに注意!
startを省略すると最初から、stopを省略すると最後まで

In [5]:
a = [1,3,5,7,9]
print(a[1:3]) # [a[1], a[2]]
print(a[::2])
print(a[::-1])
[3, 5]
[1, 5, 9]
[9, 7, 5, 3, 1]

Pythonの型(4)

  • 辞書 dictionary: {"coffee":100, "tea":120}

リストなどが0からN-1までの数字をインデックスとしていたのに対し、文字列でインデクシング

In [6]:
price = {"coffee":100, "tea":120}
print(price["tea"])
120

Pythonの型 (5)

  • ユーザー定義型

オブジェクト指向型言語であるPythonでは、ユーザーが新たな型(クラス)を定義できる
データ構造だけでなく、演算規則やさまざまなメソッドも

その中でもNumPy ndarrayが特に重要... 高機能な配列計算を提供

メソッド: 型(クラス)に固有の関数

オブジェクト名.メソッド名(引数)

の形をとる

In [7]:
# 文字列型のメソッド例
a = "I like tomatoes"
b = "12"

print(a.split())
print(a.upper())
print(b.zfill(4))
['I', 'like', 'tomatoes']
I LIKE TOMATOES
0012

型変換

Fortranなどと同様に、型の名前の関数を作用させることで型変換できる

In [8]:
a = 100.0
b = str(a) # 実数 -> 文字列

if文による条件分岐

if [論理型]:
    [処理]
elif [論理型]:
    [処理]
else:
    [処理]

[論理型]がTrueならば[処理]を行う
elifはelse ifのこと。ifのみ、if-else、if-elif-elif-...などももちろん可

end ifにあたるものはなく、インデントによってブロックを判別している
インデントは通常スペース4つ

In [9]:
x = 100

if x%2 == 0:
    print("x is even")
else:
    print("x is odd")
x is even

forループ

for i in [配列的なもの]:
    [処理]

ダミー変数iは、[配列的なもの]の要素を順に取る

In [10]:
x = "ABC"
for i in x:
    shout = i + "!" # 文字列の「足し算」は結合
    print(shout)
A!
B!
C!

rangeを使う

Fortranのdo i = start, stop, stepにあたるループを回したいときは、

for i in range(start,stop,step):
    [処理]

とすればよい。range関数は、startからstopまで、step幅の等差数列を返す
stopは含まれないことに注意!

range(start,stop)なら[start, start+1, ..., stop-1]
range(stop)なら[0, 1, ..., stop-1]

In [11]:
for i in range(5): # i=0,1,2,3,4
    print(i**3) 
0
1
8
27
64

関数の定義と利用

Fortranでいうsubroutineとfunctionは、どちらもfunctionとして扱われる

def func_name(引数):
    処理
    return 戻り値

returnはなくても良い

関数を呼ぶときは、

func_name(引数)     # returnのない場合
x = func_name(引数) # 戻り値を代入
In [12]:
# 引数を3乗して返す関数
def cube(x):
    return x**3

# 引数やreturnがなくても良い
def bark():
    print("Bow-wow!")

y = cube(3) + cube(4) # 27 + 64 = 91
print(y)
bark()
91
Bow-wow!

モジュールの利用

複数のスクリプトで用いる変数や関数群をひとつの.pyファイルにまとめておき、モジュールとすることができる

# my_module.pyの中身
pi = 3.141592

def area(r):
    return pi * r * r

これを別のスクリプトで使うには、import文を用いる

In [13]:
import my_module

radius = 5.0
S = my_module.area(radius) # my_module内のarea関数

pi = 0
print(pi)                  # このスクリプトの変数pi
print(my_module.pi)        # my_module内の変数pi
0
3.141592

importいろいろ

In [14]:
import my_module as mm     # 別名をつける
S = mm.area(1.0)

from my_module import area # モジュール内の特定のオブジェクトをインポート
S = area(1.0)

NumPyとは

Pythonの外部ライブラリで、計算のためのさまざまな関数・定数が入っている

特に、NumPyの提供する多次元配列型NumPy ndarrayは、Pythonでの科学計算の中核となる機能である

NumPy ndarray

Pythonのリストやタプルは大きなデータを扱うのには向かない... 基本的に遅い!

NumPy ndarrayは、高速な多次元配列計算を提供するユーザー定義型である

In [15]:
import numpy as np               # NumPyモジュールをインポート
x = np.linspace(0., 2*np.pi,100) # 0から2piまでを100等分する1次元配列
y = np.sin(x)                    # y = sin(x)

ndarrayの生成

zeros, ones: 0または1で埋まった配列を生成

引数に整数またはタプルで配列の形を指定する

In [16]:
a = np.zeros(5)
print(a)

b = np.ones((3,3))
print(b)
[ 0.  0.  0.  0.  0.]
[[ 1.  1.  1.]
 [ 1.  1.  1.]
 [ 1.  1.  1.]]

arange, linspace: 等差数列の1次元配列を生成

c = np.arange(start, stop, step)
d = np.linspace(start, stop, num)

arangeはPython組み込みのrangeと同様
linspaceは、stepを指定する代わりに分割数numを指定

In [17]:
a = np.arange(0,30,3)
print(a)

b = np.linspace(0,30,3) # 端点を含む等分割
print(b)

c = np.linspace(0,30,3,endpoint=False) # 端点を含まない等分割
print(c)
[ 0  3  6  9 12 15 18 21 24 27]
[  0.  15.  30.]
[  0.  10.  20.]

ndarrayの基本操作

In [18]:
a = np.arange(10)
b = 2*a + 1    # ベクトル計算が可能
c = np.exp(a)  # numpy内の関数も!
In [19]:
a = np.ones((3,3)) # 3x3, 成分はすべて1
a[0,0] = 5         # (0,0)成分に5を代入
a[1,0:2] = 3       # (1,0)、(1,1)成分に3を代入  
a[2,:] = np.arange(3) # (2,:)成分に0,1,2を代入
print(a)
[[ 5.  1.  1.]
 [ 3.  3.  1.]
 [ 0.  1.  2.]]

ndarrayのメソッド

メソッド: 型(クラス)に固有の関数

オブジェクト名.メソッド名(引数)

の形をとる

ndarrayには計算をスムーズにするための様々なメソッドがある

ndarray.sum(axis)

axis(整数またはタプル)で指定した軸に沿って和をとる
指定しなければ全体の和を取る
mean(平均)、max(最大)、min(最小)、var(分散)、std(標準偏差)なども同様

In [20]:
a = np.arange(9).reshape((3,3))
print(a)
print(a.sum(0))
print(a.sum()) # a.sum((0,1))と同じ
print(a.max(0))
[[0 1 2]
 [3 4 5]
 [6 7 8]]
[ 9 12 15]
36
[6 7 8]

ndarray.reshape(shape)

ndarrayをC形式で(後ろのインデックスから順に)平らにした後、shapeのタプルの形に整列する

In [21]:
a = np.arange(12)
print(a)

b = a.reshape((3,4))
print(b)

c = b.reshape((2,6))
print(c)
[ 0  1  2  3  4  5  6  7  8  9 10 11]
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]

ndarray.T

転置をとる

ndarray.ravel()

多次元配列を(デフォルトではC形式で)1次元にする

ndarray.shape

配列の形(各次元の要素数)をタプルで返す

NumPyその他

関数(ndarrayに作用させられる!)

sin, cos, exp, sqrt, floor, ceil, ...

pi, e, inf, nan, ...

In [22]:
x = np.linspace(0., 2*np.pi, 100) # 0から2piまでを100等分
y = np.sin(x)

サブモジュール

  • random 乱数の生成に関するモジュール
  • fft 高速フーリエ変換
  • linalg 線形代数
  • interp 補間

各モジュールともSciPyにより高機能なものが入っているが、こちらで十分なこともしばしば

In [23]:
x = np.random.rand(8) # [0.0,1.0)の一様乱数
print(x)

fx = np.fft.rfft(x)
print(fx)
[ 0.25416692  0.32500636  0.68071801  0.36391927  0.59905223  0.0540401
  0.41626943  0.77837525]
[ 3.47154758+0.j          0.13978141-0.16298603j -0.24376830+0.76324806j
 -0.82955202+0.36591113j  0.42886560+0.j        ]

forループを使ってはいけない!

ほかの多くのスクリプト言語と同様、Pythonのループは遅い
NumPyのベクトル演算機能を活かし、forループをできるだけ無くそう

In [24]:
%%time
x = np.linspace(0,2*np.pi,100000)
y = np.sin(x)
CPU times: user 8 ms, sys: 4 ms, total: 12 ms
Wall time: 13.3 ms
In [25]:
%%time
x = np.linspace(0,2*np.pi,100000)
y = np.zeros(100000)
for i in range(100000):
    y[i] = np.sin(x[i])
CPU times: user 256 ms, sys: 0 ns, total: 256 ms
Wall time: 255 ms

Matplotlibによる可視化

サブモジュールmatplotlib.pyplotによって、Matlab風のスクリプトで可視化できる

In [26]:
import matplotlib.pyplot as plt
x = np.linspace(0, 2*np.pi, 20)
y = np.sin(x)

plt.plot(x, y)
plt.show()

plt.plot(x, y)

前の例のように、xyはNumPy ndarrayでもよい

オプション変数としては、

  • color: "b", "blue", "#0000FF", ...
  • linestyle: "-", "--", ".", "o", "o-", ...
  • linewidth: 実数
  • label: 凡例用文字列

などなど

plt.contour(X, Y, Z, NまたはV), plt.contourf

コンター図(contourfは塗ってくれる)
X,Yはプロットする配列Zの定義点のx座標およびy座標

X,Y = np.meshgrid(x,y,indexing='ij')

で生成できる

N(整数)を入れると、N段階でいい感じに線を引いてくれる
V(ndarrayなど)を入れると、線を引くところを自分で指定できる

カラーバーは

plt.colorbar()

の1行!

In [27]:
x = np.linspace(0, 4*np.pi, 60)
y = np.linspace(-2*np.pi, 0, 30)
X,Y = np.meshgrid(x, y, indexing="ij") # (Nx, Ny)型の配列をプロットする場合はindexing="ij"をつける 

u = np.cos(x.reshape(60,1))*np.exp(y.reshape((1,30))) # broadcastを使って60x30のndarrayを生成

plt.contourf(X, Y, u, 40, cmap="bwr")
plt.colorbar()
plt.show()

plt.quiver(X,Y, U, V)

矢印図
X,Yはプロットするベクトル(U,V)の定義点のx座標およびy座標

plt.hist(x)

ヒストグラム

plt.semilogx(x,y), semilogy, loglog

片対数・両対数版のplt.plot

In [28]:
x = np.linspace(0, 2*np.pi, 60)
ys = np.sin(x)
yc = np.cos(x)

fig = plt.figure()
ax = plt.subplot()
ax.plot(x, ys, "b-", lw=2, label="sin")
ax.plot(x, yc, "g-", lw=2, label="cos")
ax.legend(loc="upper right", fontsize=15)
ax.set_xlim(0,2*np.pi)
ax.set_xticks(np.pi * np.linspace(0,2,5))
ax.set_xlabel("$x$", size=18)
ax.set_ylim(-1.1,1.1)
ax.set_ylabel(r"$\int_0^{2\pi}\alpha dx$", size=18)
ax.tick_params(labelsize=15)
fig.tight_layout()
plt.show()

実用編1: NetCDFの読み込み

必要なライブラリ: NetCDF4, HDF4

In [29]:
from netCDF4 import Dataset

data = Dataset("../../../python/hs_2016010100.nc", "r", format="NETCDF4")
print(data.variables.keys()) 
# data.variablesにはdictionary形式でデータが格納されている。
# .keys()はdictionaryのメソッドで、dictionaryのインデックスを返してくれる
odict_keys(['longitude', 'latitude', 'time', 'swh'])
In [30]:
lon = data.variables["longitude"][:] # 最後の[:]をつけるとnumpy array形式で変数が得られる
lat = data.variables["latitude"][:]
Hs = data.variables["swh"][:]

実用編2: 地図を描く

必要なライブラリ: Basemap (Matplotlib toolkits)

In [31]:
from mpl_toolkits.basemap import Basemap

plt.figure(figsize=(8,6))
bm = Basemap(projection="cyl", # Equidistant Cylindrical projection
            llcrnrlon=0, llcrnrlat=-70,
            urcrnrlon=360, urcrnrlat=70)

bm.drawcoastlines(linewidth=0.25) # 海岸線
bm.drawmeridians(np.arange(0, 360, 30)) # 経線
bm.drawparallels(np.arange(-90, 90, 30)) # 緯線
Out[31]:
{-60: ([<matplotlib.lines.Line2D at 0x7f0962ed31d0>], []),
 -30: ([<matplotlib.lines.Line2D at 0x7f0962ed3978>], []),
 0: ([<matplotlib.lines.Line2D at 0x7f0962ed9198>], []),
 30: ([<matplotlib.lines.Line2D at 0x7f0962ed9978>], []),
 60: ([<matplotlib.lines.Line2D at 0x7f0962ee2198>], [])}
In [ ]:
# ここからはmatplotlibの「丁寧な」描き方とほぼ同じ

X, Y = np.meshgrid(lon,lat)
x, y = bm(X, Y) # X, Yはdegree単位だが、basemapで使えるように変換してくれる

# Hsの図を描く
lev = np.linspace(0, 8, 20)
bm.contourf(x, y, Hs[0,:,:], lev)
plt.show()

まとめ - 本日の内容

  • Pythonの基礎
    • Pythonの型
    • 基本文法: 分岐、ループ、関数、モジュール
  • NumPyの基礎
    • NumPy ndarrayの生成、操作
    • NumPyの関数、モジュール
  • Matplotlibの基礎
    • 簡単な作図: plot, contour
  • 実用例
    • NetCDFの読み込み、Basemapによる地図の描画

参考資料

NumPy: "numpy (やりたいこと)"などでググると結構出てきます。SciPyも同様。公式ドキュメントがわかりやすいです
Matplotlib: 公式ドキュメントがわかりにくいですが、ギャラリーは充実しており、それぞれの図についてソースコードを見られるため、描きたい図に近いものを見つけて勉強できます

基礎編

応用編