ndarray – 配列による要素指定

“Pythonではじめる機械学習”中、27番のコードで気になったので調べた結果。

Scitkit-learnを使ってk-最近傍法の予測結果を保存し、その結果を使って予測されたアヤメの種類を表示させている。

ここでpredictioniris_dataset['target_names']のいずれの型もnumpy.ndarrayであり、ndarrayの引数に整数ではなくてndarrayを使っている。

通常のリストでこれをやると、”リストのインデックスにリストを使ってはダメ”とエラーになる。

ところがndarrayの場合はその引数にndarrayを渡すことができて、結果はndarrayとして帰ってくる。

さらに、引数に渡す配列が複数の要素を持つ場合、各要素を引数とした場合に対応する元の配列の要素が配列として返される。

なお、元の配列がndarrayであれば、引数に普通のリストを渡しても同じ結果が得られる。

 

Python3 – os/os.path

主な関数

os.getcwd()
カレントディレクトリー。プログラム実行直後は実行中のディレクトリーを指している。実行ファイルのディレクトリー情報を得るには__file__を使うとよい
os.path.dirname(dir)
dirのディレクトリーのフルパス。
os.listdir(dir)
dirにあるファイル・ディレクトリーのリスト。
os.chdir(dir)
dirに移動。存在しない場合は’NotADirectoryError’をスローする。

実行例

実行結果

 

ファイル/ディレクトリーの判定

ファイルの判定はos.path.isfile(target)。ディレクトリーの判定はos.path.isdir(target)

実行結果

 

Python3 – sys

プログラムの停止

プログラムを停止するのはsys.exit()

 

sys.argv~コマンドライン引数

sys.argvはコマンドライン引数を配列で返す。0番目の値は実行中のパス付のスクリプト名自体。

 

Python3 – 正規表現 – group()

たとえば次のようなファイル名のテキストがあるとする。

  1. file_name-10.txt
  2. file_name-1.txt

ファイル名本体の末尾にある番号を2桁に統一したいようなとき、1つ目にはマッチせず、2つ目にはマッチさせたい。

この場合、以下のような正規表現でマッチングできる。

ただしこれだけでは、該当するファイル名はわかるが、0の挿入といった部分的な操作ができない。

そのような場合は、正規表現を()で区切り、group()メソッドで部分列を取り出すことができる。

パターン設定で()で区切った部分ごとにグルーピングされ、その各部分を後から再利用できる。なお、group(0)はマッチした部分全体になる。

 

Python3 – enumerateでリストのインデックスが得られる

通常、リストの要素を順番に操作するときにはforループを使う。

enumerate()関数を使うと、リストの要素とそのインデックスを同時に得ることができる。

このインデックスにformat()を使うと書式を設定でき、ファイル名のrenameなどに便利。

 

Python3 – 正規表現の操作

主なreモジュール関数

まず、reモジュール関数の操作をまとめる。以下の文字列をターゲットにする。

re.match()はパターンが先頭でマッチするかどうか。

re.search()はパターンが含まれるかどうか。最初に現れたパターンにのみマッチする。

re.findall()は一致するパターン全てのリストを返す。

re.finditer()は一致するパターンのイテレータを返す。

re.sub()は一致するパターンを置き換え。

re.subn()は一致するパターンを置き換え、その結果と置換回数のタプルを返す。

コンパイル

パターン文字列をコンパイルしパターンオブジェクト化することで、再利用・高速化が可能。この場合、reモジュール関数と同じ名前のメソッドが使える。

マッチオブジェクトの利用

上記のうちmatch()、search()、findall()はマッチオブジェクトを返す。マッチオブジェクトの主なメソッドには、マッチした開始点を返すstart()、終了点(+1)を返すend()、それらをタプルで範囲として返すspan()、マッチした文字列を返すgroup()がある。

複数のマッチした文字列を処理するには、finditer()で順次マッチオブジェクトを取り出すとよい。

 

Python3 – 正規表現~貪欲と非貪欲

以下のようにタグで囲まれた文字からタグを取り出そうとすると、先頭の'<‘と最後尾の’>’に対して文字列全体がマッチしてしまう。

これは正規表現のマッチングができるだけ長い文字列でヒットさせようとする貪欲な(greedy)マッチングのため。

これを非貪欲(non-greeding)なマッチングにするためには**?とする。この場合、できるだけ短くマッチするようになり、個々のタグが分解される。

タグの間に1文字以上入っていることを意図して以下のようにしても、やはり貪欲にマッチする。

これを非貪欲にマッチさせようとすると、以下のように最初のタグのの'>'ではなく、その次の'>'にマッチする。最初のタグの'<'に対して、その後複数の文字を経て到達するのが2つ目のタグの'>'のため。

以下のように、意図する文字構成をできるだけ詳しく記述する方がよい。

 

Python3 – 文字列の判定~数値か文字か

文字列を構成する文字がすべて数値か、数値以外の文字かといった判定をするメソッド群。

isdecimal()
全ての文字が十進数字ならTrue
isdigit()
全ての文字が数字ならTrue
isnumeric()
全ての文字が数を表す文字ならTrue
isalpha()
全ての文字が数字以外の文字ならTrue
isalnum()
全ての文字が十進数字ならTrue

以下のコードで確認。

半角英字、半角数字の判定結果は想定通り。

半角記号は文字、数字、数を表す文字のいずれでもないと判定。

特殊数字は十進数字ではないが数字と判定。

漢数字は十進数字や数字ではないが、数を表す文字と判定。

全角の記号は文字、数字、数を表す文字のいずれでもないと判定。

 

Python – コマンドライン引数

コマンドライン引数の取得

以下のような仕様

  • sysパッケージをインポート
  • sys.argvに引数のリストが格納されている
  • 引数の1つ目(ゼロ番目)は常にコマンド自身

以下のスクリプトを実行してみる。

引数リストの先頭はコマンド自身(Windowsの\はエスケープされている)。

引数は入力したままの形。

引数がない場合の処理と、数値・文字別の処理を組み込んだ例。

実行結果。

 

numpy – 連立方程式

導入

以下のように行列表示された連立方程式を考える。

     \begin{equation*} \left( \begin{array}{ccc} 1 & 2 & -3 \\ 2 & -1 & 3 \\ -3 & 2 & 1 \end{array} \right) \left( \begin{array}{c} x \\ y \\ z \end{array} \right) = \left( \begin{array}{c} 5 \\ 4 \\ 1 \end{array} \right) \end{equation*}

この方程式の解は、(x, y, z) = (2, 3, 1)

逆行列による方法

係数行列、未知数ベクトル、定数ベクトルをそれぞれ\boldsymbol{A},\boldsymbol{x}, \boldsymbol{b}と表す。

     \begin{equation*} \boldsymbol{A} \boldsymbol{x} = \boldsymbol{b} \end{equation*}

このとき係数行列に逆行列が存在するなら、未知数ベクトルは以下で解ける。

     \begin{gather*} \boldsymbol{A}^{-1} \boldsymbol{A} \boldsymbol{x} = \boldsymbol{A}^{-1} \boldsymbol{b} \\ \boldsymbol{x} = \boldsymbol{A}^{-1} \boldsymbol{b} \\ \end{gather*}

これをnumpy.linalgパッケージの行列操作で解いてみる。

行列にベクトルを掛けるのに、reshape()で行ベクトルから列ベクトルに変換している点に注意。

numpy.linalg.solve()による方法

solve(A, b)関数は、第1引数に係数行列、第2引数に定数ベクトルを与えて、連立方程式の解のベクトルを得ることができる。

非正則行列の場合

以下のような、明らかな非正則行列の場合(連立方程式が不定の場合)、逆行列を計算しようとする時点でsingular matrixのエラーになる。

このようなケースでは、linalg.solve()関数でも同様のエラーとなる。

以下のようなケースはややこしい。同じ係数行列と定数ベクトルに対して、逆行列による解とsolve()による解の値が異なっている。

行列Aの行列式は理論上はゼロであることが確認できる。

 \begin{eqnarray*} \left| \begin{array}{ccc} 1 & 2 &3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{array} \right| &=& 1 \cdot (5 \cdot  9 - 6 \cdot 8) - 2 \cdot (4 \cdot 9 - 6 \cdot 7) + 3 \cdot(4 \cdot 8 - 5 \cdot 7) \\ &=& 45 - 48 -2(36 - 42) + 3(32 - 35) \\ &=& -3 +12 + 9 = 0 \end{eqnaray*}

この方程式を掃き出し法で解いていくと以下の通り。

     \begin{equation*} \left( \begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{array} \right) \left( \begin{array}{c} x \\ y \\ z \end{array} \right) = \left( \begin{array}{c} 1 \\ 2 \\ 3 \end{array} \right) \end{equation*}

     \begin{equation*} \left( \begin{array}{ccc} 1 & 2 & 3 \\0 & -3 & -6 \\ 0 & -6 & -12 \end{array} \right) \left( \begin{array}{c} x \\ y \\ z \end{array} \right) = \left( \begin{array}{c} 1 & -2 & -4 \end{array} \right) \end{equation*}

     \begin{equation*} \left( \begin{array}{ccc} 1 & 2 & 3 \\0 & -3 & -6 \\ 0 & 0 & 0 \end{array} \right) \left( \begin{array}{c} x \\ y \\ z \end{array} \right) = \left( \begin{array}{c} 1 & -2 & 0 \end{array} \right) \end{equation*}

途中省略するが、ここでzを消去すると、y = -2xとなり、先の計算結果と符合するが、zは0である必要はない。

不定連立方程式において、逆行列やsolve()関数を使って解く場合には注意が必要。