numpy – 配列要素の演算

要素に対するスカラー演算

配列の要素に対するスカラー演算は、それぞれの要素に作用。

二次元配列も同じ。

なお、配列が後ろに来ても要素ごとに演算。

要素ごとの演算

同じ形状の配列同士の演算は、それぞれの要素ごとの演算。

要素ごとの比較

配列同士の比較は、要素ごとの比較結果の配列。

関数演算

numpyの関数の引数が配列の場合、要素ごとの演算結果となる。

 

numpy – ファイルの保存と読み込み

バイナリファイル

バイナリファイルとしての保存にはnp.save()、その読み込みにはnp.load()を使う。基本的なオプションは以下の通り。

numpy.save("ファイル名", 配列)
配列 = numpy.load("ファイル名")

注意点として、ファイルの拡張子は.npy固定。

  • saveのファイル名に拡張子をつけない場合、自動的に拡張子.npyが付加される
  • saveのファイル名に別の拡張子を書いても、その後ろに.npyが付加される
  • loadのファイル名の拡張子は.npyでなければならない(違う場合はFileNotFoundError)

テキストファイル

概要

テキストファイルとしての保存にはnp.savetxt()、その読み込みにはnp.loadtxt()を使う。扱える配列の次元は1次元か2次元のみ。基本的なオプションは以下の通り。

numpy.savetxt(
    fname,         # ファイル名を任意の拡張子まで指定
    X,             # 書き込む配列
    fmt='%.18e',   # 書き込む書式
    delimiter=' ', # 行内の数値の区切り
    newline='n',   # 改行文字
    header='',     # ヘッダー文字列
    footer='',     # フッター文字列
    comments='# ', # コメントの開始文字
    encoding=None  # エンコーディング
)

numpy.loadtxt(
    fname,                 # ファイル名(拡張子まで)
    dtype=<class 'float'>, # データの型
    comments='#',          # コメント開始文字
    delimiter=None,        # 区切り文字(デフォルトはスペース)
    converters=None,
    skiprows=0,            # ファイル先頭から指定した行数だけ読み飛ばす
    usecols=None,          # タプルで指定した列のみ読み込み
    unpack=False,
    ndmin=0,
    encoding='bytes'max_rows=None)

なお、numpy.ndarrayはすべての要素の型が同じでなければならず、リストやタプルのように要素の型を混在させることはできない

数値データ

数値データのみを扱う場合、整数でも自動的に実数型に変換されて読み込まれる。

実行例

このときのファイルの内容は以下のようになっている。

3次元以上の配列を書き込もうとするとエラー。

文字列

文字列データについては、書き込む場合はfmt="%s"、読み込む場合にはdtype="unicode"を指定。

このとき、text.txtファイルの中は以下のようになっている。

CSVファイルの読み込み

以下のようなCSVファイルを配列に読み込む。

numpy.arrayはすべての要素の型が同じである必要があるため、上記のように文字列と数値が混在したファイルを一つの配列に読み込もうとするとエラーになる。

都道府県名と2次元のデータを別々に読み込むことは可能。

読み込み時にUnicodeエラーが出た場合

ファイル読み込み時に以下のようなエラーが出た場合。

引数にencoding='utf8'を指定して回避。

その他のメソッド

savez()/load()
複数のファイルを非圧縮で扱う。
savez_compressed()/load()
複数のファイルを圧縮して扱う
ndarray.tofile()
配列のストレージへの書き込み。

 

ndarray – 配列の生成

リテラル

要素をリテラルで指定する。

2次元配列は行列形式できれいに表示されるが、3次元以上は1行表示になる。

リストでもタプルでも結果は同じ。

自動生成

配列形状を指定して全要素を特定の値で埋める

全要素が0、1の配列

numpy.zeros(shape, [dtype=None], [order='C'])
numpy.ones(shape, [dtype=None], [order='C'])

引数はどちらも同じで、配列形状、データタイプ、行列優先の指定。

多次元配列を生成する場合、配列のサイズをタプルとして引数に渡す。

全要素の数値を指定

numpy.full(shape, fill_value, [dtype=None], [order='C'])]

他の配列と同じ形状で特定の値を埋める

全要素が0、1の配列

numpy.zeros_like(a, [dtype=None], [order='C'])
numpy.ones_like(a, [dtype=None], [order='C'])

全要素の値を指定

numpy.full_like(a, fill_value, [dtype=None], [order='C'])]

 初期化せず配列枠だけ確保する

zeros()ones()と同じで、配列の形だけを確保するが各要素は初期化しない。

この場合も多次元配列ではサイズのタプルを引数で渡す。

配列形状を(1, 1)で指定すると、1要素の2次元配列が確保される。

配列形状を数値0で指定すると、空の配列が確保される。

配列形状で0の次元が含まれると空の配列になる。

内包表記

リストの内包表記が使える。

range()関数

普通にrange()関数も使える。

numpy.arange()~間隔を指定

numpy.arrange([start=0], stop, [step=1], [dtype=None])

numpy.arange()関数はrange()関数よりも高速な生成が可能。

range()関数と同じようにパラメータを設定。dtypeはデータ型を指定。

range()関数は整数しか引数に指定できないが、numpy.arange()関数はfloatの指定が可能。

numpy.linspace()~分割数を指定

numpy.linspace(start, stop, [num=50], [endpoint=True], [retstep=False], [dtype=None])

初期値と終了値を指定して、その間を等分割したリストを返す。分割数を指定しないとデフォルトで50分割。基本の型はfloat。

この分割数は区間数ではなく、生成される数列の個数である点に注意。以下の例では0~1の間で10個の数値を生成させるため、区間数は9となる(植木算の考え方)。

デフォルトでは終端値を含めるが、含めないようにもできる。

生成された数列と分割幅のタプルを返すことができる。

特定の行列の生成

numpy.identity()~単位行列

numpy.identity(n)

正方行列の1辺の要素数を指定して、単位行列を生成する。

numpy.tri()~下三角行列の生成

numpy.tri(n)

左下の要素が1の下三角行列を生成する。

numpy.tril()numpy.triu()~行列の三角化

numpy.tril(matrix)
nunmpy.triu(matrix)

与えられた行列を下三角/上三角化。

numpy – 配列操作 – 抽出

概要

配列の要素や行・列の抽出などに関する操作。

準備として、以下の1次元、2次元配列を考える。

要素の参照

1次元配列の要素の参照は、リストと同じ。

2次元配列の要素は、[行, 列]で指定。行・列の値の考え方は1次元配列の要素と同じ。

行・列の参照

単一の行・列の参照

2次元配列の行の参照は、行番号を指定。

2次元配列の列の参照はややこしくて、[:,列番号]で指定。1つ目の:は行番号のプレースホルダーみたいなものか。

ただし、列を取り出した結果でも、1次元の配列になる。

直接列ベクトルで取り出したい場合は、[:,列番号:列番号+1]で可能。

なお、1次元の配列にndarray.Tを作用させても、1次元配列のままで列ベクトルにはならない。

範囲を指定した行・列の参照

行の範囲を指定して、複数行の行列を返す。

列の範囲を指定する場合。

複数の行・列を指定した参照

連続しない複数の行を取り出した行列をつくるには、[行番号, 行番号, …]とする。

複数列を取り出す場合。

参照であることの注意

以上の操作で取り出された配列は、元の配列への参照を保っているため、その要素を変更すると元の配列の要素も変更される。

元の配列に影響させたくない場合は、copy.copy()、copy.deepcopy()、np.copy()でオブジェクトをコピーする必要がある。

対角要素の取り出し

np.diag()で、2次元配列の対角要素を取り出した1次元配列が得られる。

ただし、その結果は書き込みできない。

条件を指定した取り出し

配列に条件式を適用して、各要素が要件に合致していればTrue、合致していなければFalseを要素とする配列を返す。

上で得られた配列を要素とすることで、条件に合致した要素のみを取り出した1次元配列を得る。

 

Python3 – numpyのインストール

numpyのインストールは、コマンドラインからpipで。numpyのインストール後にpipのアップグレードを推奨されたので、これも実行。

 

クイックソート

概要

クイックソートは、特定の値(ピボット)を基準にして、データの先頭と最後尾から1つずつ中央に近づけていきながら、ピボットより小さなデータが前に、大きなデータが後ろに配置されるように交換し、その処理を再帰的に行っていく。

考え方

以下2段階に分けて、与えられたデータ列をピボット以上・未満に振り分ける操作と、それらを再帰的に実行していく操作を示す。

ピボットの取り方にはいろいろあるようだが、ここでは与えられたデータの先頭と最後尾の値の平均値とする。

部分列に対する操作

以下の図で、4,6,2,…5のデータの部分列が与えられたとする。その際の操作は以下の通り。

  • ⓪ 部分列の先頭と最後尾のデータの平均を計算し、それをピボットとして設定(4.5)
  • ① 左からピボット以上のデータを探索(6≥4.5)、右からピボット未満のデータを探索(1<4.5)
  • ② 探索した左右のデータを交換
  • ③ さらに左からピボット以上のデータを探索(7≥4.5)、右からピボット未満のデータを探索(0<4.5)
  • ④ 探索した左右のデータを交換
  • ⑤ さらに探索を進めた結果、左右のポインターが交差
    • このとき、境界より左にピボット未満、境界より右にピボット以上のデータが格納されている
    • 3を境界とし、境界を含む左側とそれより右側の部分列に分けて、再帰的に探索を行う

再帰処理

部分列の操作を踏まえたうえで、それらの再帰的な処理の様子を下図に示す。図中、それぞれの線種や背景色の意味は以下の通り

  • 二重枠囲みはピボットの値
  • 赤はピボット以上のデータ
  • 青はピボット未満のデータ
  • 黄色は境界値
  • 緑色は位置が確定したデータ

各段階の処理は以下の通り。

  • ① 元の列からピボット以上/未満のデータを振り分け
  • ② 左側の部分列に対する再帰1段目、ピボットによる振り分け
  • ③ 左側の部分列に対する再帰2段目、ピボットによる振り分け
  • ④ 左側の部分列に対する再帰3段目、ピボットによる振り分け
  • ⑤⑥ 左側・右側の再帰終了、0と1の位置確定
  • ⑦ 右側の部分列に対する再帰3段目
  • ⑧⑨ 左側・右側の再帰終了、2と3の位置確定
  • ⑩ 右側の再帰終了、4の位置確定(ここで再帰1段目の左側終了)
  • ⑪ 右側の部分列に対する再帰1段目、ピボットによる振り分け
  • ⑫ 左側の再帰終了、5の位置確定
  • ⑬ 右側の再帰2段目、ピボットによる振り分け
  • ⑭⑮ 左側・右側の再帰終了、6と7の位置確定

コード

以下はPythonによる実装。全体のデータ列に対して位置を指定して並べ替えを実行する再帰関数quick_sort_core()を定義し、全体列に対してこれを呼び出す入口の関数quick_sort()を定義。

例示したデータに対して実行。

要素がすべて同じで、要素数が偶数・奇数の場合も正常に動作。

同じ要素が複数含まれる場合も正常に動作。

動作状況の確認

並べ替えの動作中の状況を以下のコードで確認。各所にprint()関数をちりばめてみる。

動作結果は以下の通りで、再帰的に実行されているのがわかる。

 

Python3 – random/乱数

概要

randomモジュールには、疑似乱数を発生させる関数や、コレクションからランダムな要素を選んだり、コレクションをシャッフルしてくれる関数が用意されている。

なお、numpy.randomモジュールにも便利な乱数生成関数が準備されている。

乱数系列/seed()

random.seed()関数は、引数を指定して乱数系列を固定する。

疑似乱数/random()

random()関数は、0≤r<1の範囲の一様乱数を浮動小数点で返す。

一様乱数/uniform()

uniform(a, b)は、a≤r<bの範囲の一様乱数を浮動小数点で返す。

整数乱数/randint(), randrange()

randint(a, b)a≤r≤bの範囲の乱数を整数で返す。第2引数のbも生成されることに注意。

randrange(start, end, step)start≤r<stopの範囲でstep間隔の乱数を整数で返す。第2引数のstopは生成されないことに注意。stepを省略した場合は1となる。

ランダム選択/choise()

choise(c)はコレクションcからランダムな要素を一つ選んで返す。

引数に文字列を指定すると、その中から任意の位置の文字を一つ返す。

シャッフル/shuffle()

shuffle(c)はコレクションの内容をシャッフルする。イミュータブルな文字列を指定するとTypeErrorになる。

 

Python3 – オブジェクトへの参照

概要

Pythonで関数の受け渡しが参照渡しとされているが、改めて変数とオブジェクトの関係を含めて確認してみた。

オブジェクトの参照に関する基本的な考え方は

  • 論理値や数値も含めて全てオブジェクト
  • 変数にはインスタンスのアドレスが格納され、参照される
  • 数値や文字列などイミュータブルなオブジェクトの場合、リテラルの表現が同じものは共通の1つのインスタンスとなる
  • リストなどミュータブルなオブジェクトは、インスタンスの内容が変更されても参照先は変わらない(逆に言えば、参照先が変わらないのに内容が変更されている可能性がある)

関数の引数の受け渡しは

  • 仮引数は、関数が呼び出し時には元のオブジェクトへの参照を指しているが、イミュータブルオブジェクトが変更された場合は参照先が変わり、呼び出し元の引数に影響を与えない
  • 引数の参照先がミュータブルオブジェクトの場合、インスタンスの内容が変更されても参照先は変わらず、呼び出し元の内容も変更される

変数からオブジェクトへの参照

数値の場合

下記のコードをまず確認する。

ある数値を変数に代入すると、その変数には数値(オブジェクト)のアドレスがセットされる。その変数の内容(アドレス)を別の変数に代入すると、新しい変数も同じアドレスをさすようになる。

次に、同じ数値を指している変数の一つに別の数値を代入すると、その変数は新しい数値オブジェクトのアドレスを指すようになる。

以下のように、同じ値の数値は1つのオブジェクトのアドレスが共有される。

数値計算の場合も、結果が同じ値なら1のオブジェクトが共有される。

変数が絡む演算でも、結果が同じ値なら同じアドレスを指す。

浮動小数点の場合、精度上少しでも異なる値は違うオブジェクトになる。

文字列の場合

数値の場合と同じで、変数は文字列オブジェクトのアドレスを指す。

異なる内容の文字列は、異なるオブジェクトとなる。

同じ内容の文字列リテラルは、異なる位置で用いられても1つのオブジェクトとして共有される。

面白いことに、文字列リテラル同士の演算結果が同じなら、これも同じオブジェクトとして共有される。

同じオブジェクトを指していても、一方に演算を施すと新たなオブジェクトが生成されるため、異なるオブジェクトを指すようになる。

なお、リテラル同士の演算で結果が同じ場合はオブジェクトが共有されたが、変数が絡む場合は、内容が同じであっても異なるオブジェクトとなる。

リストの場合

リストの場合もオブジェクトへの参照が変数に保存される。

リストの要素を変更した場合、そのリストを指している全ての変数に変更結果が反映される。

注意点。リストの場合、リテラルが同じでも異なるオブジェクトが生成される。

オブジェクトが異なるため、片方の変更は他方に反映されない。

関数の引数の参照

数値の場合

関数の引数に数値を渡す場合の流れは以下の通り。

  1. 仮引数は引数と同じオブジェクトを指す
  2. 関数内で引数が変更されると、新たなオブジェクトを指すようになる
  3. その結果、仮引数に渡した変数は変更されない

文字列の場合

文字列の場合も、関数内での変更は呼び出し元に影響を与えない。

リストの場合

リストを引数に渡した場合、関数内での変更が呼び出し元にも影響を与える。リストのようなミュータブルオブジェクトの場合、それに対する変更は元のインスタンスに対する変更であり、イミュータブルなオブジェクトのように新しいインスタンスが生成されるわけではないため。

元のインスタンスに影響を波及させたくない場合はコピー、ディープコピーを使う。

 

Python3 – キーワードと予約語

キーワード

キーワードの一覧は以下の通り。

False, None, True, and, as, assert, async, await, break, class, continue, def, del, elif, else, except, finally, for, from, global, if, import, in, is, lambda, nonlocal, not, or, pass, raise, return, try, while, with, yield

組み込み関数

このうちabs以降の一覧は以下の通り。

abs, all, any, ascii, bin, bool, breakpoint, bytearray, bytes, callable, chr, classmethod, compile, complex, copyright, credits, delattr, dict, dir, divmod, enumerate, eval, exec, exit, filter, float, format, frozenset, getattr, globals, hasattr, hash, help, hex, id, input, int, isinstance, issubclass, iter, len, license, list, locals, map, max, memoryview, min, next, object, oct, open, ord, pow, print, property, quit, range, repr, reversed, round, set, setattr, slice, sorted, staticmethod, str, sum, super, tuple, type, vars, zip

 

Python3 – 文字列とリストの相互変換

文字列からリストへの変換

リストから文字列への変換

リストから文字列に変換するときに、区切り文字を指定できる。

区切りは2文字以上でもok。