keisukeのブログ

***乱雑です!自分用のメモです!*** 統計や機械学習の勉強と、読み物を書く練習と、備忘録用のブログ

カーネルとは直感的に説明するとなんなのか?

2015-06-01追記:はてなの TeX のレンダリングに難があるため Qiita に移行しました
追記ここまで


How to intuitively explain what a kernel is?に対する回答がわかりやすかったので和訳


まずは質問の意図から。 質問者は、「カーネルとは直感的に説明するとなんなのか?」を聞いています。それに対する回答のひとつが、上記のリンク先です。

和訳

カーネルとはふたつのベクトル  \boldsymbol{x} \boldsymbol{y}内積を(たいていはとても高次元の)特徴空間で計算する方法であり、これがカーネル関数が時々「一般化内積」と呼ばれる理由です。

 \mathbb{R}^n 上にあるベクトルをなんらかの特徴空間  \mathbb{R}^m へ写す写像  \varphi:\mathbb{R}^n \rightarrow \mathbb{R}^m があるとします。すると、その空間での  \boldsymbol{x} \boldsymbol{y}内積 \varphi(\boldsymbol{x})^\top\varphi(\boldsymbol{y}) です。カーネルとはこの内積に対応する関数  k で、つまり  k(\boldsymbol{x}, \boldsymbol{y}) = \varphi(\boldsymbol{x})^\top\varphi(\boldsymbol{y}) です。

どうしてこれが便利なのか?カーネルは、特徴空間が何なのか、そして  \varphi が何なのかを知ることなしに、その特徴空間上で内積を計算する方法を提供します。

例えば、 \boldsymbol{x}, \boldsymbol{y}\in\mathbb{R}^2 について、単純な多項式カーネル [tex: k(\boldsymbol{x}, \boldsymbol{y}) = (1 + \boldsymbol{x}^\top \boldsymbol{y})2] を考えます。これはどんな写像  \varphi にも対応しているようには見えず、単に実数を返す関数です。  \boldsymbol{x} = (x_1, x_2), \boldsymbol{y} = (y_1, y_2) とおいて、上の式を展開してみます: [tex:{ \displaystyle k(\boldsymbol{x}, \boldsymbol{y}) = (1+\boldsymbol{x}^\top\boldsymbol{y})2 = (1+x_1 y_1 +x_2 y_2 )2 = 1+x_12 y_12 +x_22 y_22 +2x_1 y_1 +2x_2 y_2 +2x_1 x_2 y_1 y_2 }] これは次のふたつのベクトルの内積以外の何者でもないことに注意してください: [tex: (1, x{1}^2, x{2}^2, \sqrt(2)x{1}, \sqrt(2)x{2}, \sqrt(2)x{1}x{2}] と [tex: (1, y_12, y_22, \sqrt(2)y_1, \sqrt(2)y_2, \sqrt(2)y_1y_2] 、そして [tex: \varphi(\boldsymbol{x}) = \varphi(x_1, x_2) = (1, x_12, x_22, \sqrt(2)x_1, \sqrt(2)x_2, \sqrt(2)x_1x_2) 。だから、カーネル [tex: k(\boldsymbol{x}, \boldsymbol{y}) = (1+\boldsymbol{x}^\top\boldsymbol{y})2 = \varphi(\boldsymbol{x})^\top\varphi(\boldsymbol{y})] は、6次元空間での内積を計算していることになります。明示的にその空間を訪れずに。

もうひとつの例はガウシアンカーネル  k(\boldsymbol{x}, \boldsymbol{y}) = \exp(-\gamma||\boldsymbol{x}-\boldsymbol{y}||^2) です。この関数をテイラー展開すると、これが無限次元への写像  \varphi に対応することがわかるでしょう。

最後に、カーネルに基づいた手法のよい導入として、Yaser Abu-Mostafa教授のオンライン講義"Learing from Data"をおすすめします。特に、"Support Vector Machines", "Kernel Methods", "Radial Basis Functions"カーネルについてのレクチャーとなっています。

eralchemyをWindows環境にインストール

手間取ったのでメモ。

前提

eralchemy は 現在 Python2でしか動かない

依存ライブラリ

  • sqlalchemy
    • 例のごとく pip install sqlalchemy
  • graphviz
  • pygraphviz
    • 例のごとくWindows環境ではビルド失敗なので*1、いつもお世話になっている ここから ダウンロードして pip install

eralchemyのインストール

pip install eralchemy
これで、

import eralchemy

してエラー吐かなかったらOK (.__version__プロパティはなかった)。

使い方

まずは適当にテーブル作る

参考:SQLite Foreign Key Support

import sqlite3
conn = sqlite3.connect('my.db')
query = """
CREATE TABLE artist(
  artistid    INTEGER PRIMARY KEY, 
  artistname  TEXT
);
"""
conn.execute(query)
query = """
CREATE TABLE track(
  trackid     INTEGER PRIMARY KEY, 
  trackname   TEXT, 
  artistid INTEGER,
  albumid     INTEGER,
  FOREIGN KEY(artistid) REFERENCES artist(artistid),
  FOREIGN KEY(albumid) REFERENCES album(albumid)
);
"""
conn.execute(query)
query = """
CREATE TABLE album(
  albumid     INTEGER PRIMARY KEY,
  albumname   TEXT,
  artistid    INTEGER,
  genreid     INTEGER,
  FOREIGN KEY(artistid) REFERENCES artist(artistid),
  FOREIGN KEY(genreid) REFERENCES genre(genreid)
);
"""
conn.execute(query)
query = """
CREATE TABLE genre(
  genreid     INTEGER PRIMARY KEY,
  genrename   TEXT
);
"""
conn.execute(query)
conn.commit()
conn.close()

eralchemyしてみる

import eralchemy
eralchemy.render_er("sqlite:///my.db", "myer.png")

f:id:kaisk:20150524170726p:plain

イイネ!

*1:いつものことだが、Windowsでソースからビルドは苦行なので一刻も早く思考を放棄してバイナリを手に入れる手段を探したほうが良い

pandasとSQL

参考:pandasでRDBの読み書きをする

Pandasは、R言語のdata.frameと呼ばれるデータ構造をPythonに移植したもので、 データ解析によく使われるライブラリ。 データ解析にはデータベースが切っても切れない関係であるため、 PandasはSQLと密に連携できるようになっている。 SQLには色々な方言があるのだが、Pythonでそれらの方言を統一的に扱おうとしているのがSQLAlchemyというライブラリ。

そこで、PandasからSQLAlchemyを使ってデータベースから読んだデータをDataFrameに変換するには:

import sqlalchemy
import pandas as pd

# この例ではsqliteを使うが、
engine = sqlalchemy.create_engine('sqlite:///example.db')

# 例えば、PostgreSQLをかわりに使いたければ(ただしpsycopg2というライブラリに内部で依存):
# engine = sqlalchemy.create_engine("postgresql://username:password@host/dbname")

query = 'select * from hoge'
df = pd.io.sql.read_sql(query, engine)

これだけ。簡単!

ちなみに、参考リンクではwith pg.connect(...) as conn:となっているが、上の例のようにPandas最新版では、SQLAlchemyのengineを直接pandas.io.sql.read_sql()に渡すことが可能。こっちのほうが短いしわかりやすいので最新版の機能を使おう。

IPython Notebookのfontやフォントサイズを変える

IPython Notebookの入力欄(code cell)はデフォルトだとmonospaceなフォントが使われているので、それを自分好みに変えるには %username%\.ipython\profile_default\static\custom\にある、custom.cssに次を追加:

.CodeMirror {font-family: "Migu 1M";
             font-size: 16px;}

線形代数

線形代数の基礎を復習したので簡単にまとめ。


 n 次のベクトル  \boldsymbol{v}, \boldsymbol{u} と、 n n 列の行列 $$ \boldsymbol{A} = (\boldsymbol{a_1}, \boldsymbol{a_2}, \dots, \boldsymbol{a_n}) $$ を考える。 ただし  \boldsymbol{v} \boldsymbol{u} は横ベクトル、 \boldsymbol{a_i} は縦ベクトル。

行列  \boldsymbol{A} によって変換がおこなわれる( \boldsymbol{u} = \boldsymbol{Av})時、各  \boldsymbol{a_i} は、 i 番目の基底ベクトルの変換後の位置を表す。
つまり、 \boldsymbol{A} の各列に並んでいる縦ベクトル  \boldsymbol{a} は、それぞれ  (1,0,\dots,0)^\top,  (0,1,\dots,0)^\top, ...,  (0,0,\dots,1)^\top の変換先を表す。

この基底ベクトルの変換によって作られる図形  \boldsymbol{a_1}, \boldsymbol{a_2}, \dots, \boldsymbol{a_n} の大きさ(二次元なら面積、三次元なら体積)が、 \boldsymbol{A}行列式である。
行列式が0になる、つまり図形の大きさが0になるのは、 \boldsymbol{a_i} が一次従属であるとき。 なぜなら、一次従属のとき、変換先の次元がつぶれてしまうから。二次元の場合だったら、 \boldsymbol{a} が同じ方向を向いているとき、変換先は直線上に全て乗ってしまい、図形の大きさは0になる。 このように次元がひとつでもつぶれると、つまり行列式が0だと、もう変換を元に戻すことができないので、逆行列が存在しなくなる。

行列  \boldsymbol{A}固有ベクトルとは、その行列による変換によって向きが変わらないベクトルのこと。
固有ベクトルは互いに直交しているわけでもないし、必ず存在するわけでもない。 特に、固有ベクトルの大きさを1に揃えた時、その固有ベクトルが変換によってどれだけ伸び縮みするかその割合を固有値と呼ぶ。

 \boldsymbol{A} の各固有ベクトル  \boldsymbol{q_1}, \boldsymbol{q_2}, \dots, \boldsymbol{q_n} を並べた行列を  \boldsymbol{Q} とすると、 まず固有値の定義から  \boldsymbol{Aq_i} = \lambda_i\boldsymbol{q_i}
これを行列形式に直せば、  \boldsymbol{AQ} = \boldsymbol{Q\Lambda} となって、結局  \boldsymbol{A} = \boldsymbol{Q\Lambda Q^{-1}} となる。

特に、  \boldsymbol{A} が対称行列であるとき、固有値は全て実数であり、その各固有ベクトルはそれぞれ直交する。つまり、  \boldsymbol{Q} が直交行列になるわけだから、  \boldsymbol{Q}^\top = \boldsymbol{Q}^{-1} が成立!

対称行列  \boldsymbol{A} に対して、任意のベクトル  \boldsymbol{z} 全てにおいて  \boldsymbol{z^\top Az} > 0 が成立する時、  \boldsymbol{A}正定値行列と呼ぶ*1 \boldsymbol{z^\top Az} \geq 0 の場合は半正定値行列
正定値行列であることと、全ての固有値が正であることは必要十分条件である。同様に、半正定値行列であることと、全ての固有値がゼロ以上であることは必要十分条件である。
これは、対称行列の固有ベクトルを並べた行列  \boldsymbol{Q} が直交行列になることを使って、 $$ \boldsymbol{z}^\top \boldsymbol{A} \boldsymbol{z} = \boldsymbol{z}^\top \boldsymbol{Q} \boldsymbol{\Lambda} \boldsymbol{Q}^{-1} \boldsymbol{z} = ( \boldsymbol{Q}^{-1} \boldsymbol{z})^\top \boldsymbol{\Lambda} (\boldsymbol{Q}^{-1} \boldsymbol{z}) $$ となることから、 (\boldsymbol{Q}^{-1} \boldsymbol{z}) が任意のベクトルであること、 \boldsymbol{\Lambda} が対角行列であることから導ける。


ベクトル空間(線型空間)とは、線形性を持つ元(ベクトル)からなる空間。ベクトルの単位元、逆元、分配則などが存在する。

ノルム空間とは、ノルムの定義されたベクトル空間。ノルムとは、ベクトルの長さのようなもの。つまり、長さを測れるベクトルからなる空間のこと。

内積空間とは、内積の定義されたベクトル空間。内積0となるベクトルの組は直交している。また、自分自身との内積はノルムとなるので、内積空間はノルム空間でもある。

バナッハ空間とは、完備なノルム空間。ここでいう完備とは、任意のコーシー列が空間内の元に収束することであるが、もっとわかりやすく言えば、「穴の開いていない」空間のこと。例えば、有理数の集合からなる空間では、 \sqrt{2} に収束するような有理数からなるコーシー列を作れるのに、 \sqrt{2}有理数の集合からはみ出ている。つまり  \sqrt{2} の部分で穴が空いているため、完備ではない。逆に、実数の集合からなる空間は完備である。

ヒルベルト空間とは完備な内積空間。内積空間はノルム空間なので、自動的にヒルベルト空間はバナッハ空間でもある。

*1:定値性は、ふつう、対称行列にのみ定義される

scipy.stats のパラメータ loc と scale について

scipy.stats の各種オブジェクトには locおよびscale というパラメータがあります.

これらは結構混乱のもとなので,(自分向けに)まとめてみました.

任意の標準的な分布  P があるとき,
パラメータ loc=mu, scale=sigma と指定することで,
 \frac{x-\mu}{\sigma} P にしたがうようになる.

具体的には,例えば正規分布なら,scipy.stats.norm(loc=mu, scale=sigma) とすると, 確率変数  \frac{x-\mu}{\sigma}標準正規分布にしたがう. よって,もとの  x がどうなるかというと,計算してみるとこの場合  \text{N}(\mu, \sigma^{2}) となる. つまり平均  \mu,分散  \sigma^{2} なる正規分布である.

 \chi^{2}分布なら,scipy.stats.chi2(df=n, loc=mu, scale=sigma)とすると, 確率変数  \frac{x-\mu}{\sigma} が自由度nの \chi^{2}分布に従う. よって,もとの  x がどうなるかというと,自由度nの \chi^{2}分布に従う確率変数を  \sigma 倍して  \mu を足したものとなる.