ケモインフォマティクス入門講座初級編

Python基礎 2017年9月30日

講師:久保 竜一(株式会社DeNAライフサイエンス)

WHO ARE YOU??

一般的には

会社では

ケモインフォマティクスの世界では

  • RDKit日本ユーザー会を主催
  • 創薬ちゃんの化合物描画機能の実装

Pythonのすごい人なの?

  • そんなことないです!
  • Python歴は3年弱
  • それまではPerlとRを1年
  • そのまた前は植物育種をしていました

今日やること

  • Pythonの紹介
  • Jupyterノートブックの使い方
  • Pythonの基本文法の確認
  • Numpy, Pandasの使い方

Pythonというプログラミング言語について

  • 1991年、グイド・ヴァンロッサムによって作られた、動的型付け言語
  • 書きやすさと読みやすさから主に海外で人気が高く、Googleでは社内のメイン開発言語として採用されていることが有名
  • 最近ではディープラーニングに用いられることが多い

ヴァンロッサムのウェブサイト https://gvanrossum.github.io/

Pythonの採用例

  • Pythonが使われているいろいろなもの
    • Dropbox(クラウドストレージサービス)
    • Tensorflow(深層学習フレームワーク)
    • Instagram(写真投稿SNS)

Pythonの元ネタ

  • Pythonの元ネタはイギリスのコメディグループ「モンティ・パイソン」。
  • 「死んだオウム」

本講座ではPython3を使います!

  • Pythonのメジャーバージョンはいま2と3が混在している
  • 最新の3を使えば問題はないが、一部、2系でしか使えないモジュールがあるため、目的に応じて2系を使う必要のある場面もある
  • 例えば、バイオ系だがChIP-seq用の解析ソフトであるMACSは2系にしか対応していない

Python基礎ハンズオン

ここからPythonの基礎文法などをハンズオンで駆け抜けていきます

💡受講のポイント💡

  • Jupyter notebook の 使い方をはじめに解説しますので良く確認しておいてください
  • わからないことは積極的にTA・講師に聞いてください
  • #chemo_wakate タグを付けてのSNS発信を推奨します!!(特にTwitter)
  • Google検索の積極的活用を推奨します!!コピペOK!!楽しましょう!!
  • TA・講師の言っていることが必ずしも正しいとは限りません
  • 基本的には解説とサンプルコードがセットになっているのでセルを選択して実行(Ctrl + Enter)していくだけで流れを追うことができます

Jupyter notebook を起動しよう

git clone した chemo-wakate/tutorial-6th ディレクトリで以下のコマンドを実行して起動

-v で、起動するDockerコンテナにホストマシンのディレクトリをマウントすることができます。

-v マウントしたいホストマシンのディレクトリ:Dockerコンテナ内のマウントしたい位置

💡TRY!!💡

docker run --rm -it -p 8888:8888 \
    -v ~/chemo-wakate/tutorial-6th/:/home/jovyan/chemo \
    chemo-wakate/tutorial-6th

ヘルプを確認してみよう

💡TRY!!💡

h を入力して、ヘルプメッセージを確認しましょう。
うまく表示されない場合は Escを入力してから再度h を入力してみてください。

重要な操作方法のまとめ

  • h: ヘルプを表示する
  • Esc: コマンドモードに移行する(セルの枠が青)
  • Enter: 編集モードに移行する(セルの枠が緑)
  • コマンドモードで、a: ひとつに空のセルを挿入
  • コマンドモードで、b: ひとつに空のセルを挿入
  • コマンドモードで、j or k: セルを上下に移動
  • コマンドモードで、dd: セルを削除
  • Ctrl+Enter: セルの内容を実行

Zen of Python

  • Pythonの禅を知る
  • Pythonを書く覚悟を決めるべし

💡TRY!!💡

新しいセルを作成して、 import this と入力して実行しよう

変数

  • 動的型付け
  • 変数名はスネークケース(snake_case)
  • 宣言不要
  • 破壊的に代入される

代入

  • = 演算子で変数に値を代入
  • = の前後には半角スペースを入れる

In [ ]:
a = 1
a

破壊的代入

  • 既に代入済みの変数に再代入すると新しい値に置き換わる(破壊的代入)

In [ ]:
a = 1
a = 5
a

演算子

算法 記号
除算 /
除算(小数点以下切り捨て) //
加算 +
減算 -
乗算 *
べき乗 **
剰余 %

除算


In [ ]:
2296 / 3

除算(小数点以下切り捨て)


In [ ]:
2296 // 3

加算


In [ ]:
123 + 223

減算


In [ ]:
33 - 4

乗算


In [ ]:
2 * 8

べき乗


In [ ]:
2 ** 8

剰余


In [ ]:
14444 % 32

Pythonには複数の型が存在しますが、標準的なものを紹介する
これ以外のものは公式ドキュメントが詳しい

  • 数値型|int
  • 文字列(テキストシーケンス)型|Str
  • シーケンス型|tuple, list
  • マッピング型|dict
  • 型を調べるには type() を使用する

数値型|int

  • 整数は int()
  • 整数値はそのまま int として扱われる
  • 他にfloat() complex() もある

In [ ]:
## 数値
type(123)

文字列(テキストシーケンス)型|Str

  • シングルクォート ' もしくはダブルクォート " で囲うと文字列になる
  • 慣例的にシングルクォートを使用することが多い

In [ ]:
## 文字列
type('123')

シーケンス型|tuple

パーレン () で囲うとタプルとなる

  • タプルの中身は変更することができない
  • 要素には添字(0始まり!)でアクセス

In [ ]:
nums = (1, 2, 3)
nums

In [ ]:
nums[0]

In [ ]:
## 0番目の要素を変更してみるけどエラーになる
nums[0] = 5

シーケンス型|list

ブラケット [] で囲うとリストとなる

  • リストの中身は変更可能
  • 要素には添字(0始まり!)でアクセス

In [ ]:
elements = ['H', 'C', 'O']
elements

In [ ]:
elements[0]

In [ ]:
## 中身を変更
elements[0] = 'N'
elements

listを使いこなす

型に組み込まれた関数 = メソッド

  • .append() で要素を追加
  • .pop() で要素を後ろから取り出す

In [ ]:
elements.append('Na')
elements

In [ ]:
elements.pop()

In [ ]:
elements

マッピング型|dict

ブレース {} で囲い、keyvalue を指定すると辞書となる


In [ ]:
element_d = {'H': 1, 'C': 15, 'O': 16}
element_d

In [ ]:
## key(キー)でvalue(値)にアクセス
element_d['C']

In [ ]:
## 値を変更
element_d['C'] = 12
element_d['C']

In [ ]:
## 存在しないキーを指定して代入すると項目を追加できる
element_d['N'] = 14
element_d

In [ ]:
## キーにタプルを使用可能
element_d[('C', 'C')] = 24
element_d

In [ ]:
## キーにリストは使えない(リストは値の中身を入れ替えられるので確実にキーと値を紐付けられず安全じゃない)
element_d[['C', 'C']] = 24
element_d

dictを使いこなす

  • .keys() でキーのリストを取得
  • .values() で値のリストを取得
  • .items() でキーと値のタプルのリストを取得

In [ ]:
element_d.keys()

In [ ]:
element_d.values()

In [ ]:
element_d.items()

組み込み関数

組み込み関数はそんなに多くない上によく使うのが print() ぐらい

2. 組み込み関数 — Python 3.5.3 ドキュメント

print()

文字列をコマンドライン上に出力する関数


In [ ]:
print('Hello World!!')

In [ ]:
## print関数の中で演算もできる
greeting = 'Hello World!!'
print(greeting*1000)

ここまでのまとめ

  • 演算子は数学記号とほとんど同じ
  • 変数に値を代入できる
  • タプル; (1, 2, 3)
  • リスト; [1, 2, 3]
  • 辞書; {'first': 1, 'second': 2, 'third': 3}
  • print()

様々なプログラムの制御方法

  • if : 条件分岐
  • while : 繰り返し処理
  • for : 繰り返し処理

if文

  • Perlなどと異なり、if文の節が {} に囲まれていないことに注目
  • そのかわり、インデントを揃えることでif文のブロック(インデントブロック)を明示している
  • Pythonにおいてインデントブロックは、読みやすくするだけではなく、プログラミング上で意味のあるものとなっていることに注目
  • インデントの方法は様々だがPythonにおいては 半角スペース4文字 が推奨されている
    • Jupyter notebookではTABによって半角スペース4つが挿入される
    • Shift+TABでde-indent

In [ ]:
v = 100
if v > 10:
    print(v,  'is greater than 10')

In [ ]:
v = 5
if v > 10:
    print(v,  'is greater than 10')
else:
    print(v,  'is less than 10')

In [ ]:
v = 10
if v == 10:
    print(v,  'is equal to 10')
elif v > 10:
    print(v,  'is greater than 10')
else:
    print(v,  'is less than 10')

while文

  • 指定した条件文が真(True)である限り処理を繰り返す

In [ ]:
## 100以下のフィボナッチ数列を計算してみる
a, b = 0, 1
while b < 100:
    print(b)
    a, b = b, a+b

for文

  • 指定した回数処理を繰り返す

In [ ]:
## リストに保存された文字列の長さを出力してみる
##     - len() は要素の数を返す関数
##     - 文字列型は一文字が一つの要素として扱われるので、文字数が返ってくる
words = ['cat', 'window', 'defenestrate']
for word in words:
    print(word, len(word))

In [ ]:
## リストに保存された文字列の長さを出力してみる(index番号もほしい!)
##     - len() は要素の数を返す関数
##     - 文字列型は一文字が一つの要素として扱われるので、文字数が返ってくる
##     - enumerate()を使うと添字も取得できます
words = ['cat', 'window', 'defenestrate']
for index, word in enumerate(words):
    print(index, word, len(word))

In [ ]:
## PythonではC言語風の書き方は存在しないのでこの処理をn回繰り返すといったときはこう書く
for i in range(5):
    print(i)

In [ ]:
## 途中で処理を止める | break
for i in range(10):
    print(i)
    if i >= 5:
        break

In [ ]:
## (ループの先頭に戻って)処理を続ける | continue
for i in range(20):
    print(i)
    if i >= 5:
        continue
    print('\n5未満だけ実行される\n')

PythonでFizzBuzz

  • 1から100の数字を順に出力
  • 3の倍数のときは数字ではなく Fizz と出力
  • 5の倍数のときは数字ではなく Buzz と出力
  • 3と5の公倍数のときは数字ではなく FizzBuzz と出力

In [ ]:
for i in range(1, 101):
    if i % 15 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)

関数定義

  • 機能単位で関数化してしまうと読みやすく、再利用の際も便利
  • 関数名はスネークケース( _ でつなぐ)を推奨

In [ ]:
## 足し算をする関数
def add_num(a, b):
    return a + b

# 実行してみる
add_num(32, 40)

💡TRY!!💡 関数を作ってみる(5 min.)

要件定義

  • 関数の名前は、 is_fizzbuzz()
  • 数値を1つ引数に指定可能
  • 引数で与えられた数値に対してFizzBuzzを判定して判定結果の文字列(Fizz or Buzz or FizzBuzz)を返す
    • いずれにも当てはまらない値の場合は False を返す

モジュールの使用

  • Pythonを科学技術計算で使用するメリットのひとつは計算用ライブラリが豊富な点
  • (Pythonスクリプトではなく) pip コマンドでモジュールをインストール(今回はDocker環境を使っているので実行しない)
  • import ${module_name} でモジュールを読み込む
  • 冒頭でやった import this も同じ

作業ディレクトリのパスを取得する|OSモジュール


In [ ]:
import os

In [ ]:
os.getcwd()

numpyを使ってみる

  • 行列計算のためのライブラリ
  • for文などによる繰り返し処理は実行時間がかかるので、行列計算でうまく処理すると大幅な効率改善につながる
  • Quickstart tutorial — NumPy v1.13 Manual

In [ ]:
import numpy as np  # 慣例的に as np として省略した名前でimportすることが多い
a = np.array([1, 2, 3])  # numpyアレイを作成
a

In [ ]:
a.dtype

In [ ]:
b = np.array([1.2, 3.5, 5.1])
b

In [ ]:
b.dtype

様々な行列


In [ ]:
np.arange(6)   # 1次元

In [ ]:
np.arange(12).reshape(4, 3)  # 2次元

In [ ]:
np.arange(24).reshape(2, 3, 4)  # 3次元

In [ ]:
np.random.rand(10, 10)  # 10x10 の乱数行列

行列の計算


In [ ]:
## 引き算
a = np.array([20, 30, 40, 50])
b = np.arange(4)
a - b

In [ ]:
a * b  # 掛け算

行列へのアクセス

1次元の場合


In [ ]:
a = np.random.rand(20) 
a

In [ ]:
# 2番目の要素を取り出す
a[1]

In [ ]:
# 4番目から8番目の要素を取り出す
a[4:9]

In [ ]:
# 逆順で取り出す
a[::-1]

2次元の場合


In [ ]:
a = np.random.rand(10, 3)
a

In [ ]:
a[0][0]  # 1番目の配列の1番目の要素

In [ ]:
a[0, 0]  # 1番目の配列の1番目の要素(書き方違い)

In [ ]:
a[0:5, 0]  # 1番目から5番目の配列の1番目の要素

numpy ほんとに速いの?


In [ ]:
def prod_2d(n=100):
    a = np.random.rand(n, n)
    b = np.random.rand(n, n)
    c = np.zeros((n, n))  # zero 行列
    for i in range(n):
        for j in range(n):
            for k in range(n):
                c[i][] = a[i][k] * b[k][j]
    return c

In [ ]:
def prod_2d_np(n=100):
    a = np.random.rand(n, n)
    b = np.random.rand(n, n)
    return np.dot(a, b)

In [ ]:
# numpy使わずに計算した場合
%timeit result = prod_2d(n=150)

In [ ]:
# numpyを使って計算した場合
%timeit result = prod_2d_np(n=150)

💡TRY!!💡Jupyter notebook上で関数のヘルプを見る

  • np.zeros() って言う知らない関数が出てきたんだけど
  • 新しいセルで ?np.zeros() を実行してみる

さいごに

  • わからないことはGoogleで検索!!
  • スモールステップで動作確認
  • ヘルプを活用!!

💡TRY!!💡 more

もっとPythonで楽しみたい方はトライしてみてください

リスト内包表記で書き換えて高速化

入力したリストの数値をそれぞれ2乗して返してくれる関数 square() を定義しました。
この関数を リスト内包表記 でもっと高速に処理するよう書き換えてみてください。
→ リスト内包表記はネット検索!!

まずはセルをコピーして、実行方法は変えずに関数の中身だけ変えてみてください


In [ ]:
import numpy as np  # 乱数の生成に使用
np.random.seed(123)  # 毎回同じ乱数が生成されるようにシード値を固定

In [ ]:
def square(nums):
    results = []
    for num in nums:
        results.append(num ** 2)
    return results

%timeit square(np.random.rand(1000000))

スクリプトファイルに保存してPythonを実行してみる

今回のようにJupyter notebookを使用せず、スクリプトファイルとして実行したい場合、テキストファイルとして保存してターミナル上で実行することになる。実はJupyter notebookでもターミナルを実行することができるのでかんたんなスクリプトを書いてみよう。

  1. New メニューから Text file を選択
  2. タイトル(ファイル名)の拡張子を .py に変更し、スクリプトを書く。この時 Language タブからPythonを選んでおくとシンタックスハイライトが有効になる
  3. もう一度メニューから Terminal を選択し、ターミナルを起動する(ブラウザ経由でターミナルを操作できます)
  4. chemo/beginner へ移動し、 python sample.py を実行する

おすすめPython本