2014/04/23

Python Tips:スクリプトの実行時間を計測したい

Pythonで、スクリプトの実行時間を計測する方法をご紹介します。

実行時間を計測するには、そのままずばり「 timeit 」という実行時間計測用のライブラリを使う方法がシンプル、かつかんたんです。

timeit の最も基本的な使い方は次のとおりです。
$ python -m timeit "[x ** 3 for x in range(100)]"
# => 10000 loops, best of 3: 39 usec per loop

python コマンドに m オプションを渡し timeit モジュールを読み込んで、その後に計測したいコードを文字列で渡します。すると、渡されたコードの実行時間が標準出力に返ってきます。時間の単位は usec 、ということで単位時間(マイクロセカンド)のようです。

上の例では「与えられたコードを10000回繰り返す」ということを3回試行して、3回のうちのベストタイムが返されています。

渡された文字列が実行されるので、特定のスクリプト(ファイルになっているもの)の実行時間を計測したい場合は、この文字列の部分にコードを入れ込めばOKです。

たとえば、LinuxやMacなら次のようにすることで特定のスクリプトの実行時間を計測することができます。
$ python -m timeit "`cat script_to_time.py`"
# => 10000 loops, best of 3: 7.76 usec per loop
cat script_to_time.py によってスクリプトの中身を出力して、それを `` を使ってコマンドの中に埋め込んでいます。 `` の部分は $() などを使っても大丈夫です。

・・・以上です。


timeit のこの他の使い方については別の投稿にも書いていますのでよろしければご参考にしてください。
ライブラリ:timeit - Life with Python


参考
26.6. timeit — Measure execution time of small code snippets — Python公式ドキュメント

2014/04/16

Python Tips:リストの中から要素をランダムにピックアップしたい

Pythonでリストの中から要素をランダムで抽出する方法をご紹介します。

ランダムで抽出する、というとき、抽出方法は2つあるかと思います。
1つだけ抽出する
複数抽出する

以下、それぞれについて見ていきます。

1つだけ抽出する
1つだけ抽出したいときは random ライブラリの choice 関数を使います。
import random

marks = ['club', 'diamond', 'heart', 'spade']
numbers = range(1, 14)
cards = [(m, n) for m in marks for n in numbers]

random.choice(cards)  # => トランプのカードのいずれか

たとえば、52枚のカードの束から1枚取り出して、そのカードをまた元に戻して、というように繰り返す場合なんかは、 random.choice を繰り返すような形で実現できます。

複数抽出する

複数枚抽出したいときは random ライブラリの sample 関数を使います。
import random

marks = ['club', 'diamond', 'heart', 'spade']
numbers = range(1, 14)
cards = [(m, n) for m in marks for n in numbers]

random.sample(cards, 5)
# => 52枚のカードの中からランダムに5枚

sample 関数は上のように2つの引数を受け取ります。1つめにはリストを、2つめには個数を指定します。

以上です。


上記の一組のトランプを使ったやり方でかんたんなモンテカルロ法なんかもできます。次のコードでは、トランプの束から抜き出した1枚の数が偶数の確率を求めています。
# トランプの束の中からカードを1枚だけ引くのを繰り返す
chosen_cards = []
for i in range(10000):
    c = random.choice(cards)
    chosen_cards.append(c)
    
# 引いたカードのうち数値が偶数となるカードが出た確率を計算して表示
even_cards_num = 0
for card in chosen_cards:
    if card[1] % 2 == 0:
        even_cards_num += 1

print(even_cards_num/len(chosen_cards))
# => 0.45ぐらいの数値


参考
How do I randomly select an item from a list using Python? - Stack Overflow

2014/04/08

Python Tips:実行中のスクリプトの名前を取得したい

Pythonで、実行中のスクリプトの名前を取得する方法をご紹介します。

と構えるまでもなくやり方はかんたんで、組み込みの変数 __file__ を使います。
print __file__
# => 実行中のスクリプト名の絶対パス

次のようにすると、ファイル名の部分だけ切り出すことができます。
import os

print os.path.basename(__file__)
# => 実行中のスクリプト名

逆にファイル名なしのパスだけを得たい場合は dirname を使います。
print os.path.dirname(__file__)
# => 実行中のスクリプトのディレクトリ

以上です。

ちなみに、 __file__ とよく似たものに __name__ があります。こちらは

  • 実行中のスクリプト内では "__main__"
  • 他からimportされたとき 拡張子なしのファイル名(モジュール名)

という値を格納しています。


参考
Get the name of current script with Python - Stack Overflow

2014/04/02

Python Tips:2つのリストの要素同士を演算したい

Python で 2 つのリストの要素同士の演算を行う方法をご紹介します。

要素同士の演算というとき、次の 2 つの方法があるかと思います。

  1. i 番目の要素同士をかけあわせる
  2. すべての組み合わせをかけあわせる

以下、それぞれのやり方を見ていきます。

i 番目の要素同士をかけあわせる

まずは i 番目の要素同士をかけあわせる方法を。こちらは zip と内包表記または map を使う方法が便利です。
li1 = [1, 3, 5]
li2 = [2, 4, 6]

combined1 = [x * y for (x, y) in zip(li1, li2)]
# => [2, 12, 30]

こちらは map を使うやり方です。
from operator import mul
combined2 = map(mul, li1, li2)
# => [2, 12, 30]
ここで、 mul は2項演算子 * と同じ働きをする関数で、引数を2つ取ります。 map には、関数、1つめのリスト、2つめのリストの順番で渡します。

すべての組み合わせをかけあわせる

すべての組み合わせをかけあわせるのは内包表記を使うやり方がシンプルにきれいに書けます。
li1 = [1, 3, 5]
li2 = [2, 4, 6]

combined3 = [(x, y) for x in li1 for y in li2]
# => [(1, 2), (1, 4), (1, 6), (3, 2), (3, 4), (3, 6), (5, 2), (5, 4), (5, 6)]

len(combined3)  #=> 9;

「 for x in 1つめのリスト for y in 2つめのリスト」とすることで、すべての要素の組み合わせを作ることができます。

以上です。


参考
Element-wise Addition of 2 Lists in Python? - Stack Overflow