nykergoto’s blog

機械学習とpythonをメインに

pythonの自作モジュールimportで困ったこと

自作モジュールをimportしたい時

同じ階層にある時はsample.pyであれば

import sample

でやればOKです.

でもあまりファイル数が多くなってくると,一定のまとまりでフォルダに入れて管理したくなります.そういう時は適当なフォルダにスクリプトを入れて,そのフォルダ内に__init__.pyを入れておけば,python再帰的にフォルダ内部の.pyファイルを読み込んでくれるので,importができるようになります.

今回詰まったこと

フォルダ構造は以下のような感じ
f:id:dette:20161010090105p:plain

sample.py

import numpy as np

def sample(x):
    x = np.random.normal(size=100)
    print(x.mean())

begin.py

from sample import sample

sample()

これをtest_moduleの親ディレクトリにある以下のファイルからimportしようとするとエラーが起こりました.

from test_module import begin

begin.sample()
 File "/Users/NYer510/python-tutorial/test_module/begin.py", line 2, in <module>
    from sample import sample
ImportError: No module named 'sample'

解決法

結論から言うと,encodingを指定すると直りました.(# -- coding: utf-8 --とかのやつ)
理由はわかりません.謎です.

python の Xgboost を Windows で使いたい!

pythonwindowsでやるなよ、という意見はごもっともですがでもやりたい時だってあるじゃん?なのでやりましょう。

環境

  • windows10
  • 64bit

必要なものたち

  • git bash
  • MinGW-W64
  • pythonが使える何かしらの環境(Anacondaとか)

git cloneする

git bash を起動して、xgboostをgithubから手に入れます。

ここで注意するポイントが2つ

  • git cloneしたあとに submodule を綺麗にして入れ直すこと。
  • 現在の最新版(2016/06/28現在)のmasterには問題があるようなのでちょっと前の commit に戻すこと。
    コマンドとしては git checkout 9a48a40.

Error installing xgboost · Issue #1267 · dmlc/xgboost · GitHub

$ git clone --recursive https://github.com/dmlc/xgboost
$ cd xgboost
$ git checkout 9a48a40
$ git submodule init
$ git submodule update

MinGW-W64のインストール

次にMinGW-W64をインストールします。この時に architecture を x84_64 にセットしてインストールします。加えてデフォルトではC:\Program File直下にインストールすることになっていますが、空文字を避けるためにC:\mingw64とか適当にCドライブ直下に新しくフォルダを作り、そこを指定します。

Pathの設定

環境変数設定からPathを追加します。追加するのはさっきインストールしたMingw64の中にあるmingw32-make.exeが入っているフォルダです。C:\mingw64\mingw64\bin とかになるはず。

f:id:dette:20160628080829p:plain
どうでもいいけどwindows10になって環境変数の編集画面がすごく見やすくなりましたね。個人的には好きです。

コンパイル

make の設定を行ってからコンパイルします。以下のコマンドを先のgit bash 上の、xgboostをコピーした階層で行います

$ cp make/mingw64.mk config.mk
$ make -j4

なんかもにゃもにゃ出るので待ちます。

インストール

成功していれば xgboost の階層に xgboost.exe ができているはずです。python パッケージをインストールする場合には python-pakage フォルダで setup.py を実行します。

$ cd python-package
$ python setup.py install

結構長いですね。はやくconda install xgboostwindowsでも入れられるような幸せな世界になって欲しいです。

参考

stackoverflow.com

github.com

pythonによる固有値固有ベクトル計算

python固有値固有ベクトルを計算しようと思うと numpy.linalg (線形代数の便利関数のモジュール)以下にある numpy.linalg.eigs を使うことになります。

numpy.linalg.eig — NumPy v1.11 Manual

この挙動が個人的な感覚とちょっとずれていて、そこでかなり消耗してしまったのでメモとして残しておきます。

nump.linalg.eigs でハマる

numpy にはnumpy.linalg.eigsという関数が用意されています。
返り値として第一変数に固有値(eigenvalues)、第二変数に正規化された(すなわち \( \|u_i\|=1 \) )固有ベクトル(eigenvector)を返します。

X = # 適当な(n,n)のnp.array
eig_vals,eig_vec = np.linalg.eigs(X)

ここで1点注意点があります。

http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.eig.html
Returns:
w : (..., M) array The eigenvalues, each repeated according to its multiplicity. (以下略
v : (..., M, M) array The normalized (unit “length”) eigenvectors, such that the column v[:,i] is the eigenvector corresponding to the eigenvalue w[i].

重要なのは、index を i とした時に固有値 eig_vals[i] に対応する固有ベクトルeig_vec[i]ではないということ!!

正しくはeig_vec[:,i]が対応します。

この問題のやっかいな点がデバックすることが困難である点です。

なぜなら、インデックスを入れる次元を間違えて eig_val[i] としても、その配列の長さは正しい場合と同じ M になり、ベクトルの長さでは判定できません。また「固有ベクトル同士は直行する」という条件を使ってデバッグをしようとしても、間違えたベクトルに対しても成り立ってしまいます。すなわちi=jの時だけ

eig_vec[i].dot(eif_vec[j])=1

が成り立ちます。ですから間違えたindexを与えた際にも固有ベクトルの特徴である「お互いが直交する」という性質も満たしてしまっています。

したがって、計算した結果がなんだかおかしい、ということ以外でのデバッグが不可能になります。僕はこれで3時間ぐらい持って行かれました。おとなしく最初にドキュメントを読めばいいのですが。ちょっと慣れてくると適当にやってもそれっぽく出来てしまうのはダメだなと改めて感じました。ドキュメント大事。

までも普通に考えて、i番目の固有ベクトルだからeig_vec[i]でいいと思うしソッチのほうが自然な定義な気がしてならないんですが、なぜそうなっていないのか……

勾配ブースティングを実装してみた

勾配ブースティングとは

機械学習アルゴリズムはいろいろなものがありますが、その中でも木構造を使ったアンサンブル学習の一つとして勾配ブースティング法と呼ばれるものがあります。

勾配ブースティング法は学習器を一つづつ追加していく加法的モデルと呼ばれるモデルに分類されます。ざっくりとしたアルゴリズムとしては

  1. 今ある学習器の結果と目的の値との差を縮めるような学習器を作り
  2. それを今ある学習器に追加する

ということを何回も繰り返して、段々と目的の値を得られるような学習器を生成します。

勾配ブースティング法は、ブースティングの学習の時に目的関数の勾配およびヘシアン情報を使うもので

  • 学習ステップを増やしても過学習を起こしにくい
  • 非常に柔軟な予測モデルを生成できる
  • 木構造ゆえ変数の正規化が必要ない

という特徴から人気者です。実際自分で使っていても大概の問題でうまく行ってる印象があります。

高速な実装としては、xgboostなどが有名です。(内部でC++で実装されているようです

普通に使う文にはxgboost使いましょうという話なんですが思い立って実装してみました。

github.com

使い方

基本的にはreadme.mdに書いてあるのでそちらを見てほしいのですが、

の二値分類であればgbdtreeフォルダを実行ファイルと同じ階層に置いて

import gbdtree as gb

clf = gb.GradientBoostedDT()
x_train,t_train = ~~ # 適当なトレーニングデータ
clf.fit(x=x_train,t=t_train)

pred = clf.predict(x_test) # x_test の予測を出力

というような感じで学習ができます。

やってみた

連続変数に対する回帰問題をやってみます

import pandas as pd
import numpy as np
import gbdtree as gb
import matplotlib.pyplot as plt

sample_size = 100
x_train = np.linspace(-np.pi,np.pi,sample_size)
t_train = np.sin(x_train) + np.random.normal(scale=.5,size=sample_size)

# xの形は(N,feature_dim)の形に直す
x_train = x_train.reshape(sample_size,1)

regobj = gb.LeastSquare()
loss = gb.leastsquare

clf = gb.GradientBoostedDT(regobj,loss)
clf.fit(x=x_train,t=t_train,num_iter=20)

pred = clf.predict(x_train)
plt.plot(x_train,t_train,'o')
plt.plot(x_train,np.sin(x_train))
plt.plot(x_train,pred)
plt.show()

f:id:dette:20160624075124p:plain

いい感じですね。適当にclf.fitに与えるパラメータを変えて挙動がどういうふうに変わるかを見るのも面白いかもしれません。

二値分類に関しては先程のgithubの中に2つ

  • sample.pyに適当なガウス分布に対する分類問題
  • mnist.pyにMNISTの手書き文字(3と8)の二値分類問題

のサンプルが入っているのでよければどうぞ。