おっぱいそん!

pythonを数値計算に使うときのテクニックとかをまとめていきたい。

OpenCV3なのにcv2でimportする件について

OpenCV2でも3でも、importする時は

import cv2

としますが、cv2の"2"はバージョンの番号でないらしいです。
元々、OpenCVはCで実装されていて、その時のAPIを"cv"と表していたのに対して、C++で実装されたAPIを"cv2"と名付けていた経緯があるみたいです。
気になったので調べたまで。

参考:
Why do python bindings for v3 still use package name "cv2"? - OpenCV Q&A Forum
convert toの略だという説が...w

Unix系OSでの基本

Unix系のOSでの基本を自分用にメモしておく。

ホームディレクトリへの移動とか

ログインした時の場所(MACだと/Users/ゆーざーねーむ)に移動するには

cd ~/

のように~で移動できる。
なぜUnix&Linuxではホームディレクトリを「~」文字で表現するのか。 - [モ]Modern Syntax

環境変数pathやエイリアスを書く場所:~/.bashrc or ~./bash_profile

後者はログイン時のみで、前者はbashが起動する度に読み込まれる。
.bash_profile ? .bashrc ? いろいろあるけどこいつらなにもの? - Qiita
本当に正しい .bashrc と .bash_profile の使ひ分け - Qiita
例えばエイリアスを作りたい時は
alias hoge="hogehoge"みたいな感じで。
source .bashrcとかで反映させられる。
Macのターミナルでよく使うコマンドにエイリアスを作りました - Qiita

よく使うコマンド

ls, pwd, mkdir, mv, ln -s,

パッケージ管理

MAC:Homebrew
Red-Hat系:yum
Debian系(Ubuntu含む):apt-get

anacondaでインストールしたpython2とpython3をsublimeText上で使う

普段はMACでpython2.7でSublimeTextというエディターを使ってコードを書いていますが、python3を使いたいことがあったので、ptthon2と3を今の環境のまま共存できるようにしました。
(完全に自分用の忘備録で他のサイトを見たほうが分かりやすいと思うので、この記事は読まない方がいいです。)

anacondaでPython2と3を共存させる

まず、anacondaでpython3を追加でインストールするには、ターミナルで

conda create -n py3 python=3.6

conda create -n py35 python=3.5 anaconda

ちなみに、この"py3"という部分は自分でpython3に切り替える時に使う名前なので、好きな名前にできます。

[追記]
2017.1.4現在anacondaでインストールできる安定版はPython3.5(Python3の安定版はPython3.6だが、Anacondaでパッケージまで含めてインストールできるのは恐らく3.5まで)。上の"conda create -n py35 python=3.5 anaconda"の"anaconda"を書き忘れると、パッケージ類(numpyとか)がインストールされず、Pythonだけしか入らないっぽいので注意。

インストールが完了すると、以下のメッセージが出ました。

# To activate this environment, use:
# $ source activate py3
#
# To deactivate this environment, use:
# $ source deactivate

書いてある通り、何もしなければ元々入っているpython2が使われ、python3を使う際には"source activate py3"と、python2に戻るには"source deactivate"をターミナルで行います(最初、activateをactiveとタイプしていて、怒られた...)。

これでpython2とpython3を切り替えられるようになりました。実際、

import sys
print(sys.version_info)

のようなファイルを作って、ターミナルで実行してみると、

sys.version_info(major=2, minor=7, micro=11, releaselevel='final', serial=0)

sys.version_info(major=3, minor=6, micro=0, releaselevel='final', serial=0)

と確かに2と3を切り替えれられていることが確認できました。

AnacondaでインストールされているpythonとそのPATHの一覧は

conda info -e

を使って見ることができます。私の場合は、

# conda environments:
#
py3                      /Users/おっぱいそん/anaconda/envs/py3
root                  *  /Users/おっぱいそん/anaconda

で、rootの方が元々インストールされているpython2でpy3が今、インストールしたpython3です。*が付いている方が今、アクティブになっているpythonです。
参考:PENGUINITIS - Anaconda における Python 2 と Python 3 の共存

[追記]
最初、Python3しかインストールされず、パッケージが入っていなかったが、それは"conda create -n py35 python=3.5 anaconda"のanacondaを書き忘れたためっぽい。(以下は解決したので削除)

*** 必要なパッケージ−のインストール
上記だけではPython3がインストールされただけで、Numpyなどのパッケージはインストールされていません。
(Python2に対しては必要となるパッケージがインストールされるのに、追加でインストールするPython3に対してはパッケージがインストールされないのは仕様なのだろうか?)
必要なパッケージがある場合は、"source activate py3"(py3の部分は自分で付けた名前)でPython3に切り替えてから、

conda install numpy
conda install scipy
conda install matplotlib

などで適宜、必要なパッケージをインストールしてください。
私の場合はMatplotlibが以下のようなエラーが出て、インストールできなかった... (とりあえず、すぐに使わないので放置する....)

UnsatisfiableError: The following specifications were found to be in conflict:
  - matplotlib
  - python 3.6*
Use "conda info <package>" to see the dependencies for each package.


SublimeTextでPython2と3を切り替える

次に、SublimeTextでpython2と3を切り替えられるようにします。
SublimeTextではSublimeRopeという統合開発環境をインストールすることで、SublimeText上でpythonを実行できる(⌘Cmd+b)ようになります。
実行する際に使うPythonのPATHは、"Preferences/Settings - User"で設定できます。

{
	"build_env":
	{
		"PATH": "/Users/おっぱいそん/anaconda/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/texbin"
	},
}

に書いてあるのがPythonのPATHなので、"/Users/おっぱいそん/anaconda/bin"を上記で調べた"/Users/おっぱいそん/anaconda/envs/py3/bin"にすることで、python3に切り替えられます。
毎回、設定を書きかえるのは結構めんどうなので、もっといいやり方がありそうですが... (もっといいやり方があったら誰か教えてくださいm(__)m)
参考:Sublime TextでPython環境を構築する話 - 酒飲みの備忘録

リストの最大値(最小値)のindexを取得する

NumpyのArrayだと、argmaxを使って、最大値のindexを取得できる。
(ただし、最大値が重複して存在する場合は、一番小さいindexを返す仕様になっている)
numpy.argmax — NumPy v1.10 Manual


PythonのListにも同じような関数が用意されているかと思ったんだけど、ないみたいなので、書き方を調べてみた。
例えば、以下のようなListがあるとする。

list_name = [2, 3, 4, 8, 3, 1, 3, 5, 7, 8, 3, 2]

最大値は8で、最大値の位置するindexは3と9である(最大値には重複がある)。


Numpyのargmaxと同様に、重複がある場合に一番小さいindexを返したい場合には、以下のような書き方がある。

print list_name.index(max(list_name))
print max(enumerate(list_name), key=lambda x: x[1])[0]
print max(xrange(len(list_name)), key=lambda i: list_name[i])
import operator
print max(enumerate(list_name), key=operator.itemgetter(1))[0]
print max(zip(list_name, range(len(list_name))))[1]

一番小さいindexの3を返してくれる。
最後のやつだけ、大きいindexを返してくるが理由は良く分からん。


一部のindexだけでなく、全てのindexを返したい場合には、

print [i for i, x in enumerate(list_name) if x == max(list_name)]
[3, 9]

とリスト内包表記を使って、全ての最大値のindexを求めることが出来る。


いろいろ書き方がありましたが、速度などは比較してないです。
Ref:
リスト内の最大値を見つける - Screaming Loud
python - How to find all positions of the maximum value in a list? - Stack Overflow
python - Pythonic way to find maximum value and its index in a list? - Stack Overflow

Octave

とある論文のsupplemental materialにあったMATLAB線形代数のパッケージを詰め込んだ有料ソフト)のコードを動かしたかったので、OctaveMATLABと互換性のある無料ソフト)をインストールして使ってみた。
MAC OSX(Yosemite)へのインストールはhttps://kiskeyix.org/articles/605を参考にした。
以下で、pythonとの比較と自分用につまづきやすいポイントのメモを。


pythonと同様にインターラクティブなモードで実行する方法と、ファイルに保存して実行する方法(拡張子は.mとする)がある。
インターラクティブな方の使い方は、pythonとほとんど同じ(terminalからpython or octaveと叩いて入る)。
ファイルに保存して実行する場合はpythonと同様に、terminalでファイルを置いているフォルダまで移動して"octave file_name.m"とする方法の他に、インターラクティブなモードでfile_nameとタイプして実行する方法がある。その際、インターラクティブなモードでcdでファイルを置いているフォルダまで移動する。


また、pythonと同様にあるファイル(pythonでいうモジュール)に保存した関数を別のファイル(スクリプトファイル)から読み込んで使うことができる。ただし、その仕様が結構違う。
pythonの場合は、あるファイルmy_module.pyに保存した関数my_func()を使うには、実行するファイルで

import my_module
my_module.my_func()

とします。
もちろん、一つのモジュールファイルの中に幾つかの関数を入れることも出来た。

一方、Octaveでは、スクリプトファイルはpythonとほとんど同じだが、呼び出す関数を保存しておくファイルは関数mファイルと呼ばれ、以下のような制約がある(どちらも拡張子は.m)。
関数名とファイル名は同じでないとダメで、その中身は関数の定義から始める。
関数名とファイル名の名前が一致していないと、

warning: function name 'func_name' does not agree with function file name '/Users/uesr_name/Desktop/test/file_name.m'

とエラーがでる。
また、関数mファイルを実行することはできない(pythonの場合は.pyファイルは実行されれば、スクリプトファイルとして扱われ、importされればモジュールとして扱われていた)。
関数mファイルなのか、スクリプトmファイルなのかは、ファイルの中身が関数の定義で始まるのか、そうでないのかによって決まる。
すなわち、

function y = func_name(x)
    y = x + 1;
end

みたいな感じで、functionで始まるかどうかで決まる。
従って、スクリプトファイルの中で関数を定義するのに、ファイルの一行目から関数を定義しようとすると、関数mファイルとみなされてしまって、実行する際にエラーがでる(僕はここでつまづいた)。
例えば、上のコードをfunc_name.mというファイルの保存して実行しようとすると、

error: 'x' undefined near line 2 column 13

とエラーがでる。

スクリプトmファイルから関数mファイルを呼び出すには、例えば、上の関数だと、

a = 1;
b = func_name(a);
disp(b);

とする。
ここで、どのファイルから関数を呼ぶか指定していないが、上に書いたように、関数名と関数mファイルの名前は一致させているので、スクリプトファイルと同じフォルダに関数mファイルをおいておけば自動的に探してくれる。

Ref:
http://www.arc.hokkai-s-u.ac.jp/~kusiyama/Inf1_Matlab/Grammar_4.htm
データ解析ツールoctaveを語ろう Part 2


Octaveスクリプトmファイルと関数mファイルの仕様は、pythonの使用を知っていると、不便に感じてしまう(一つの関数mファイルに複数の関数を定義できないのと、同じ.mファイルでスクリプトmファイルと関数mファイルの両方の機能をもたせられない)。

行列のランクと固有値の関係

行列のrankとnonzeroの固有値の関係について、すぐに忘れるのでメモしておく。
結論から先に書くと、一般の正方行列Aについて、

rank A ≧ Aの(重複度も含めた)nonzeroの固有値の数

が成り立つ。
特に、対角化可能な行列の場合には

rank = nonzeroの固有値の数

が成り立つ。
以下で、証明を書いておく。

続きを読む

pythonでフィッティングをする

pythonでfittingをする方法。

例えば、
{ \displaystyle
f(x) = a + b x + c x^2
}
という{\displaystyle a,b,c }をパラメータとする関数でデータ点{\displaystyle \{ x_i, y_i \}_{i=1,2,...N} }
{ \displaystyle
 \sum_{i=1}^{N} ( y_i - f(x_i) )^2
}
が最小になるようにfittingしたいとする(最小二乗法)。
scipy.optimizeのcurve_fitを使うのが楽(scipy.optimizeにはleastsqという関数もあり、こちらでも同じことができるが、curve_fitの方が分かりやすい)。

import numpy as np
import scipy.optimize
import matplotlib.pylab as plt

# data which you want to fit
xdata = np.array([0.0,1.0,2.0,3.0,4.0,5.0,6.0])
ydata = np.array([0.1,0.9,2.2,2.8,4.2,5.9,7.4])
# initial guess for the parameters
parameter_initial = np.array([0.0, 0.0, 0.0]) #a, b, c
# function to fit
def func(x, a, b, c):
    return a + b*x + c*x*x

paramater_optimal, covariance = scipy.optimize.curve_fit(func, xdata, ydata, p0=parameter_initial)
print "paramater =", paramater_optimal

y = func(xdata,paramater_optimal[0],paramater_optimal[1],paramater_optimal[2])
plt.plot(xdata, ydata, 'o')
plt.plot(xdata, y, '-')
plt.show()

xdata, ydataはfittingしたいデータ点(上の例では手で作ってるが、普通は実験などで得られる)。
parameter_initialはパラメータの初期値(なくてもいい)。
funcがfittingする関数で、第一引数がxで、第二引数以降がパラメータ。返り値はy。
paramater_optimalがfittingで最適化されたパラメータで、covarianceは共分散。

結果は

paramater = [ 0.14761905  0.70357143  0.08452381]

f:id:nohzen:20150928224255p:plain

続きを読む