Python3でヒストグラムとplotの重ね合わせ

指数分布に従う乱数を生成するnumpy.random.exponential()関数の確認のため、同関数で発生させた乱数群のヒストグラムと、指数分布の確率密度関数のグラフを重ねて比較してみた。

コードは以下の通りで、ヒストグラムのrangeと関数計算のrangeを合わせている。

実行結果は以下の通り。

python-matplot-pyplot-exponential-random

 

Python3 – numpy.random – 乱数

ライブラリ

乱数を扱うには、numpy.randomライブラリが必要。

seed~乱数系列の指定

乱数の系列を固定したいときはseed()関数でシードを設定する。この設定をしないかシードにNoneを設定した場合は、実行ごとに乱数系列が変わる。

並べ替え

shuffle()

引数で与えた配列の要素をシャッフルする。元の配列を書き換え、戻り値はNoneとなる。

permutation()

引数で与えた配列の要素をシャッフルした結果の配列を返す。元の配列は書き換えられない。

permutation(n)の引数nに整数を指定すると、permutation(np.arange(n))と同じ効果を持つ。

確率分布

一様分布~[0, 1)

rand()

引数なしのrand()関数は[0, 1)の一様分布に従う乱数を1つ発生させる(random()関数でも同じ)。

引数を1つ指定すると、その個数の乱数を要素に持つ配列を返す(random()関数でも同じ)。

引数を2つ指定すると、その行数・列数の2次元配列の乱数を、引数がn1、n2、n3、・・・の場合、n1×n2×n3×・・・の多次元配列を返す。

random_sample()/random()

random_sample()は、引数が1つの場合はrand()と同じだが。配列の場合はリストやタプルで次数を与える。

random()はrandom_sample()と同じ。

一様整数乱数~任意の範囲の整数

randint()

1~3個の引数をとり、終値未満の整数乱数を返す。終値を含まないため、配列からランダムに要素を取り出したい時に便利。

  • 引数が1つ(n)の場合、[0, n)の範囲の整数乱数を1つ返す
  • 引数が2つ(m, n)の場合、[m, n)の範囲の整数乱数を1つ返す
  • 引数が3つ(m, n, s)の場合[m, n)の範囲の整数乱数s個を要素とする配列を返す

サイズをリストやタプルで指定した場合、それに対応した次元・要素数の多次元配列で乱数列を返す。

random_integers()

引数の構成はrandint()と同じだが、

  • 上限値を含む、[start, end]の範囲の整数乱数
  • 引数の意味はrandint()と同じ

正規分布

randn()~標準正規分布

平均が0、標準偏差が1の標準正規分布に従う乱数を発生させる。配列で結果を得たいときはrand()と同じように直接次数を指定する。

normal()~正規分布

normal(loc=0.0, scale=1.0, size=None)

locを平均、scaleを標準偏差とする正規分布に従う乱数を返す。

sizeに整数を指定すると、その個数の乱数を配列で返す。

sizeにリスト・タプルを指定すると、その形状の配列で乱数を返す。

locscaleに同じ次数の配列を指定すると、それらがブロードキャストされた結果に従う乱数が配列で返される。

exponential()~指数分布

指数分布。

exponential(lmd) – 指数分布
lmdは平均の逆数で、ポアソン過程でいう到着率、サービス率にあたる。

Tips

整数の乱数配列を生成する

整数の乱数配列を生成する方法はこちら

 

 

matplotlib.pyplot.bar – 棒グラフ

基本形

pyplot.bar()に2つの引数を与えるのが基本形。

  • 第1引数は横軸のリスト
  • 第2引数は横軸リストの要素に対応した値

python-matplot-pyplot-bar01

bar(x, y)の横軸xの要素はfloatでなければならないが、これを文字表記に変更する。

python-matplot-pyplot-bar02

ただし項目名が左寄せになっているので、これらをセンタリングする。

なおxticksを指定せず数値のままでセンタリングすると、xで与えた数値が中央に来るよう調整される。

python-matplot-pyplot-bar03

棒の位置や幅のコントロール

デフォルトでは棒の位置はxで与えた数値に左寄せされる。またwidth=で棒の幅を指定することができる。

以下のように指定することで、ヒストグラムのような図を描くこともできる。

python-matplot-pyplot-bar04

hist()関数の戻り値を使って、以下のように書けるが、時にグラフの両側に空きができてしまうので、さらに検討が必要。

 

ヒストグラム

pyplotで簡単にヒストグラムが描ける。デフォルトでは縦軸は度数。

python-matplot-pyplot-histgram-normed-false

縦軸を頻度にしたい場合は、normed=TRUEオプションをつける。

縦軸が小数になっていて、各階級の頻度が1/10bins→0.1程度になっていることに注意。

python-matplot-pyplot-histgram-normed-true

頻度分布について

上の例ではうまく頻度分布が表示されているが、以下のようにうまくいかない場合がある。

python-matplot-pyplot-histgram-normed-trouble

ヒストグラムとplotの重ね合わせ

ヒストグラムのrankの範囲とplotのx軸の範囲を同じにすれば、こちらの例のように重ねて描くことができる。

ヒストグラムの戻り値

hist()は3つの戻り値を返す。

bin_count
各ビンの度数。
bin_position
ビン数とrangeに応じたビンの位置。
patches
各ビンのオブジェクトの配列。ビンごとに色を変えるなどの操作ができる。

Python3 – ライブラリのインストールとアップグレード

 

pipでライブラリをインストールしたときの記録。

numpy

pipのアップグレード

最初にnumpyをインストールした直後にメッセージが出た。

matplotlib

scipy

エラー発生

20191023、O’REILLYの”Pythonではじめる機械学習”の勉強のため、scipyのインストールに再挑戦。

パッケージのリストを表示させるとpipが最新バージョンではないというWARNING。

pipをアップグレード。

scipyを無事インストール。

そのまま調子に乗って、ipython、scikit-learn、pandas、pillowもインストール。

20191027、mglearnをインストール。

 

Python3 – __iter()__によるイテレーターの実装

標準形

Pythonの特殊メソッド__iter____next__を使ってオブジェクトのイテレーターをつくることができる。ジェネレーターがyield文によって任意の値を生成するのに対して、イテレーターはコレクションの要素を順次取り出すときなどに有用。

__iter____next__の2つのメソッドを持ったオブジェクトがfor文で参照されるたびに、以下のように動作する。

  1. forを始める前に__iter__メソッドが実行される
  2. forブロックのループのたびに__next__メソッドが実行される

2つのメソッドの書き方は以下の通り。

__iter__
戻り値としてオブジェクト自身(self)を返す。
__next__
イテレートされるべきプロパティを変更し、戻り値として現在値を返す。もし終了条件に合致しいている場合、イテレート終了の例外を発する。

次の例では、1から初めて最初に設定した値まで1ずつ増える数列のイテレーターをつくっている。

最初の__init__メソッドでは引数から数列の最大値をプロパティにセット。

__iter__メソッドはカウンタになるプロパティに初期値をセットして、selfを返す。

__next__メソッドはそれが呼ばれるたびに次のことを行う。

  • カウンタ値が最大値を超えていたらforブロックから抜け出るよう例外を返す
  • 現在のカウンタ値を返す
  • カウンタ値をインクリメントする

forブロックから抜け出るための例外はStopIterationが準備されていて、forブロックがこの例外を受け取ると、エラーを発生させることなくforブロックの次の処理に移る。

インスタンス変数のイテレーターの取得

たとえばあるクラス内にリストがあって、リストそのものの構造は安全に守ったまま、その要素にアクセスする方法を考えてみた。

インスタンス変数のリストそのものやgetterなどで取得したリストへの参照をメソッドで返すと、リストそのものの操作までできてしまうが、それを防ぎたい。

そこで、インスタンス変数のイテレーターを生成するクラスを元のクラスのインナークラスとして準備して、外部へはイテレーターのインスタンスを渡すようにしてみた。

インナークラスでなくてもできるが、元のクラスのインスタンス変数の構造と密接に関連しているなら、インナークラスでまとめた方が明快だと思う。

 

 

 

Python3 – ネストクラス

クラスを入れ子にして、インナークラスを定義することができる。

次の例では、MainClassの中でInnerClassを定義して、それぞれのクラスのプロパティにアクセスしている。

留意点として、アウタークラスからインナークラスを参照する際に、[アウタークラス名].[インナークラス名]とすること。インナークラス名だけで定義しようとすると「そんなクラスはないよ」と怒られる。

なお、インナークラスの定義位置は、必ずしもアウタークラスの冒頭でなくてもよい。

 

 

Python3 – switch/caseはない

とても残念なことに、Pythonにはswitch/case構文がない(もちろん予約語でさえない)。

一般的には、この機能を実現するのにif~elif~elseを使えばよいということになっている。

いくつかの(いや多くの)素敵なサイトでdictionaryを使えばいいよ、と教えてくれるのに出会った。

「構文」として定まっていはいないが、かなり見やすいように思う。

 

 

 

Python3 – 条件分岐

if

標準形

他の言語とほぼ同じだが、else ifはelifと書く。

ブロックの実行内容が1行の場合は、if文などの後ろに続けて1行で書ききれる。

後置形(三項演算子)

この形は「文」ではなくて「式」で、[真の時の値] if [条件] else [偽の時の値]と書く。

switch/caseはない

Pythonにはswitch/case文は存在しない。

if-elif-elseで書くか、以下のように辞書を利用する。

 

 

 

 

Python3 – 繰り返し~ループ

for

標準形

for [変数] in [オブジェクト]:の形で変数がオブジェクトの要素を1つずつ取り出して実行する。

range関数とfor文

for文でrange関数を使うと、多数回のループを簡易に書ける。このとき、rangeの終了値は指定した値-1になることに注意。

enumerateによるインデックスの取得

Pythonのforループでは、リストなどの要素を直接取り出せるので表現が簡潔だが、逆に引数の値(配列の順序値など)が欲しいときがある。そのような場合は、enumerateを使ってインデックスを取得することができる。

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

zipによる複数リストの並行処理

複数のリストの要素を同時に並行して取り出したいとき、zip()関数を使うとよい。

zipによる複数リストの並行ループ

enumerateとzipの複合処理

zipで複数のコレクションの要素を取り出しつつ、enumerateで全体の番号も取得したいとき。zipで取得する要素をタプルにする。

forループの最初と最後だけ処理を変える

forループでは各ループごとに同じ処理内容が繰り返されるが、これを最初と最後だけ変更したい場合の処理を考えてみる。

forループの最初と最後だけ処理を変えたい

while

while [条件式]:で条件式が真である間ループが実行される。

else~終了時の処理

else:ブロックを書くと、forやwhileのループ終了時にその内容が実行される。ループの後に実行文を書くのと動作は変わらないが、終了時処理をより明確にできる。

 continue

continue文は、それ以降の処理を飛ばしてループの先頭に飛ぶ。

次の例では、iが偶数の時はそれ以降のprint文を実行せずに次のステップに移る。

break

break文は、そのbreak文が含まれている一番内側のループから抜け出す。

次の例では、内側のループでjが3を超えるたびにループを終了し、外側の次のステップへ移る。外側のループはiが1を超えたときにそれ以降の処理をせずループを終了する。

 

 

R – rbindについて

rbind()で困った点

データフレームにrbindでアイテムを追加する場合、紹介されている例ではみな、データをベクトルで与えている(注:文字列型が勝手にFactor型にされてしまうのを4行目で回避している)。

一見するとうまくいっているが、実は問題がある。ageの項目が数字のはずだと内容を参照したり計算しようとすると・・・

となってしまう。

これはRのベクトルの仕様で、1つのベクトルの要素の型がすべて同じでなければならず、文字列型と数値型が混在した場合は数値が文字列に変換されてしまうため。

これを回避するために幾つかの方法があるが、たとえばここではas.numeric()を用いてみる。

うむ、うまくいっている、と思って、これに新たなデータを追加すると・・・

またしても怒られた。これはデータ追加のたびにベクトルの段階で文字列への変換が行われてしまうためらしく、上の9~10行目で前に数値型にしたはずのデータまで文字列に変換されてしまっている。

ベクトルではなくリストを使う

そこで、rbindでデータ群を与えるのに、ベクトルではなくリストを使ってみた。

見た目はベクトルの時と同じく、うまくいっているように見える。そこで各要素をチェックしてみると・・・

ちゃんと数値として扱われている。それでは新たにデータを追加しても大丈夫か。

問題なし。

よって、文字列と数値が混在する場合は、rbindの引数にはリストを使うべき。