矮小

井の中の蛙

D言語でdubを叩いてMySQLに接続する

D言語でもMySQLしたい!

Rubyで書いたプログラムが結構非現実的な時間を返してきたのでD言語にポートしてみました(結果だけ言うとDのほうが遅くて悲しい気持ちになりました(コードの書き方が悪かったのかもしれないけど)).

当然MySQLライブラリを使う必要がありますが,D言語にはDUBというRubyで言うbundlerのような便利ツールがあるのでそれを使ってみました.DUBのHPはここ

Find, Use and Share DUB Packages - DUB - The D package registry

Macの場合はHomebrewにdubが入っているので brew install dub で入ります.そうでなくてもOSごとにprecompiled binaryが用意されています.優しい世界.入れたら,リポジトリディレクトリを作りたいディレクトリに移動して dub init [リポジトリ名] します.

$ dub init hoge
Successfully created an empty project in '/home/nagoyan/Documents/hoge'.
$ cd hoge
$ ls -a
.  ..  .gitignore  dub.json  source

.gitignore には既に .dub*.o*.obj などバージョン管理から除外すべきファイルが入力されています.dub.jsonリポジトリの情報や依存パッケージをJSONで入力します.今回はdubのサイトでmysqlでヒットした3件のうち一番単純に使えそうな Package mysql-d version 0.3.1 - DUB - The D package registry を使うことにするので,dub.json

{
    ...
    "dependencies": {
        "mysql-d": "~>0.3.1"
    }
}

と入力します.サイトに載っている例では特定のバージョンを持ってくるようにしていますが,常に最新のものが欲しければ,バージョンに当たる部分に ~master と書けば最新のコードが降ってきます.

source/app.d に,エントリポイントである main 関数を書きます.これはinitした時に既に以下の様な内容で作成されています:

import std.stdio;

void main()
{
    writeln("Edit source/app.d to start your project.");
}

dub build で,リポジトリ内のソースコードをビルドしてくれます.依存パッケージはこの時ダウンロードします.が,この時なぜかdubがldconfigのキャッシュを無視して /usr/lib64/mysql を見てくれなかったので,dub.json のトップレベルに "lflags": ["L/usr/lib64/mysql"] を追加します(実はこの作業はもともとCentOS上でやっていました).

$ dub build
Target mysql-d 0.3.1 is up to date. Use --force to rebuild.
Building hoge ~master configuration "application", build type debug.
Compiling using dmd...
Linking...
$ dub
> $ dub
Target mysql-d 0.3.1 is up to date. Use --force to rebuild.
Target hoge ~master is up to date. Use --force to rebuild.
Running ./hoge
Edit source/app.d to start your project.

最後のメッセージは app.d の中の writeln に書かれているやつです.あとは app.d をゴニョゴニョするだけ.mysql-dのページのREADMEに使用例が書かれているのでそれを真似するだけ.インスタンスを1個作って,query 関数の引数にSQLを書く.可変長引数でSQL? を使ったバインディング機構にも対応しています.SELECT などの結果が返ってくるタイプのクエリではMysqlResultというクラスのインスタンスが返ってきます(そうでないCRUD操作でも返ってくると思いますが).このクラスはforeach range要件を満たしているので,foreachに渡すことでMysqlRowというクラスのインスタンスを1個ずつ渡してくれます.MysqlRowは文字列として出力してやるとただの文字列配列のように見えますが,内部でカラム名と値の位置をマッピングしているため,数値の添字だけでなくカラム名でも要素にアクセスできます.

MySQLサーバとの接続を終了する時に .close とかしなくていいの? と思って調べてみたのですが, https://github.com/Paxa/mysql.d/blob/master/source/mysql/mysql.d#L122-L124 を見るとデストラクタの中でやってくれているようなので書かなくても大丈夫そうです(安易にこういうこと書くと刺されそうですが).

参考

Problem linking mysqlclient when compiling mysql-d - RejectedSoftware Forums

備考:LDFLAGSを追加しないと……

以下のような結果が返ってきます.これを解決するのに一番時間がかかった.

$ dub build
Target mysql-d 0.3.1 is up to date. Use --force to rebuild.
Building hoge ~master configuration "application", build type debug.
Compiling using dmd...
Linking...
/usr/bin/ld: cannot find -lmysqlclient
collect2: ld はステータス 1 で終了しました
--- errorlevel 1
FAIL .dub/build/application-debug-linux.posix-x86_64-dmd_2067-D139BA4168D82F8FB70F3EB71271D775/ hoge executable
Error executing command build:
dmd failed with exit code 1.

PRML 演習問題2.4 分散

何も考えずに微分して式変形。

その前に、分散=2乗の平均−平均の2乗を導いておく。

 \begin{align}
\textrm{var}[m] &= \sum_{m=0}^N (m - \mathbb{E}[m])^2 \textrm{Bin}(m|N,\mu) \\
&= \sum_{m=0}^N (m^2 - 2m\mathbb{E}[m] + \mathbb{E}[m]^2) \textrm{Bin}(m|N,\mu) \\
&= \sum_{m=0}^N m^2 \textrm{Bin}(m|N,\mu) - 2\mathbb{E}[m] \sum_{m=0}^N m \textrm{Bin}(m|N,\mu) + \mathbb{E}[m]^2 \sum_{m=0}^N \textrm{Bin}(m|N,\mu) \\
&= \mathbb{E}[m^2] - 2 \mathbb{E}[m]^2 + \mathbb{E}[m]^2 \\
&= \mathbb{E}[m^2] - \mathbb{E}[m]^2
\end{align}

 \sum_{m=0}^N m \textrm{Bin}(m|N,\mu) = \mathbb{E}[m] \sum_{m=0}^N \textrm{Bin}(m|N,\mu) = 1 であることに注意。これで、 \mathbb{E}[m^2] - \mathbb{E}[m]^2 = N\mu(1-\mu) を示せばよくなった。

先に示した平均の式は、正規化条件の1階微分を式変形しただけのものであるため、平均の式を更に微分すれば、正規化条件の2階微分になる。

 \begin{align}
\frac{\partial}{\partial \mu} \sum_{m=0}^N m \binom Nm \mu^m (1-\mu)^{N-m} &= \frac{\partial}{\partial \mu} N\mu \\
\sum_{m=0}^N m \binom Nm \left\{ m \mu^{m-1} (1-\mu)^{N-m} + \mu^m (N-m)(1-\mu)^{N-m-1}(-1) \right\} &= N \\
\sum_{m=0}^N m^2 \binom Nm \mu^{m-1} (1-\mu)^{N-m} - \sum_{m=0}^N m \binom Nm \mu^m (N-m)(1-\mu)^{N-m-1} &= N \\
\sum_{m=0}^N m^2 \binom Nm \mu^{m-1} (1-\mu)^{N-m} - N \sum_{m=0}^N m \binom Nm \mu^m (1-\mu)^{N-m-1} +\\
\sum_{m=0}^N m^2 \binom Nm \mu^m (1-\mu)^{N-m-1} &= N\\
\frac{1}{\mu} \sum_{m=0}^N m^2 \binom Nm \mu^m (1-\mu)^{N-m} - \frac{N}{1-\mu} \sum_{m=0}^N m \binom Nm \mu^m (1-\mu)^{N-m} +\\
\frac{1}{1-\mu} \sum_{m=0}^N m^2 \binom Nm \mu^m (1-\mu)^{N-m} &= N \\
(1-\mu) \sum_{m=0}^N m^2 \textrm{Bin}(m|N,\mu) - N\mu \sum_{m=0}^N m \textrm{Bin}(m|N,\mu) + \mu \sum_{m=0}^N m^2 \textrm{Bin}(m|N,\mu) &= N\mu(1-\mu) \\
\sum_{m=0}^N m^2 \textrm{Bin}(m|N,\mu) - \left\{ \sum_{m=0}^N m \textrm{Bin}(m|N,\mu) \right\}^2 &= N\mu(1-\mu) \\
\mathbb{E}[m^2] - \mathbb{E}[m]^2 &= N\mu(1-\mu)
\end{align}

6→7行目は、平均の式より  \sum_{m=0}^N m \textrm{Bin}(m|N,\mu) = N\mu だったことを使う。

第2章、これ以上解けそうな問題がない……。

PRML 演習問題2.4 平均

微分のやり方間違えてた。ようやく解けた。

\displaystyle
\mathbb{E}[m] \equiv \sum_{m=0}^{N} m \mathrm{Bin}(m|N,\mu) = N\mu

を証明する。指示通り、二項定理の正規化条件の両辺を  \mu微分して変形することによりこの形を導く。

 \begin{align}
\sum_{m=0}^N \binom{N}{m}\mu^m(1-\mu)^{N-m} &= 1 \\
\frac{\partial}{\partial \mu} \sum_{m=0}^N \binom{N}{m}\mu^m(1-\mu)^{N-m} &= \frac{\partial}{\partial \mu}1 \\
\sum_{m=0}^N \binom{N}{m} \left\{ m \mu^{m-1}(1-\mu)^{N-m} + \mu^m(N-m)(1-\mu)^{N-m-1}(-1) \right\} &= 0 \\
\sum_{m=0}^N \binom{N}{m} m \mu^{m-1}(1-\mu)^{N-m} - \sum_{m=0}^N \binom{N}{m} \mu^m(N-m)(1-\mu)^{N-m-1} &= 0 \\
\sum_{m=0}^N \binom{N}{m} m \mu^{m-1}(1-\mu)^{N-m} \\-
\sum_{m=0}^N \binom{N}{m} \left\{ N \mu^m(1-\mu)^{N-m-1} - m \mu^m(1-\mu)^{N-m-1} \right\} &= 0 \\
\sum_{m=0}^N m \binom{N}{m} \mu^{m-1}(1-\mu)^{N-m} \\- N \sum_{m=0}^N \binom{N}{m} \mu^m(1-\mu)^{N-m-1} +
\sum_{m=0}^N m \binom{N}{m} \mu^m(1-\mu)^{N-m-1} &= 0 \\
\frac{1}{\mu} \sum_{m=0}^N m \binom{N}{m} \mu^{m}(1-\mu)^{N-m} \\- \frac{N}{1-\mu} \sum_{m=0}^N \binom{N}{m} \mu^m(1-\mu)^{N-m} +
\frac{1}{1-\mu} \sum_{m=0}^N m \binom{N}{m} \mu^m(1-\mu)^{N-m} &= 0 \\
\left( \frac{1}{\mu} + \frac{1}{1-\mu} \right) \sum_{m=0}^N m \binom{N}{m} \mu^{m}(1-\mu)^{N-m} &= \frac{N}{1-\mu} \\
\frac{1}{\mu(1-\mu)} \sum_{m=0}^N m \binom{N}{m} \mu^{m}(1-\mu)^{N-m} &= \frac{N}{1-\mu} \\
\sum_{m=0}^N m \binom{N}{m} \mu^{m}(1-\mu)^{N-m} &= N \mu
\end{align}

  • 2→3行目:積の微分公式は  \{f(x)g(x)\}' = f'(x)g(x)+f(x)g'(x) g(x) に当たる  (1-\mu)^{N-m} が合成関数であることに注意
  • 6→7行目:第1項、第2項、第3項にそれぞれ  \frac{\mu}{\mu},\frac{1-\mu}{1-\mu},\frac{1-\mu}{1-\mu} を掛け、それぞれの分子を  \sum の中に繰り込む
  • 7→8行目:第1項と第3項は  \sum の中身が同じなので係数をまとめられる。第2項は正規化条件より  \sum の部分は1だった
  • 9→10行目:両辺に  \mu(1-\mu) を掛ける

指数を調整するために上手く1を掛けたりするところが受験数学チックで懐かしかった。正規化条件で1になるところとかスッキリしましたね。このあと分散の方も解きます。

PRML 演習問題2.3

WWWと付いてるので著者HPに解答が載ってはいるんですが式変形が急激すぎてビビる。詳細解をメモ。式変形の説明も。

2.262

 \begin{align}
\binom Nm + \binom {N}{m - 1} &= \frac{N!}{(N-m)!m!} + \frac{N!}{(N-m+1)!(m-1)!} \\
&= \frac{N!(N-m+1)}{(N-m+1)!m!} + \frac{N!m}{(N-m+1)!m!} \\
&= \frac{N!(N-m+1) + N!m}{(N-m+1)!m!} \\
&= \frac{N!(N-m+1+m)}{(N-m+1)!m!} \\
&= \frac{N!(N+1)}{(N-m+1)!m!} \\
&= \frac{(N+1)!}{(N+1-m)!m!} \\
&= \binom {N+1}m
\end{align}

 (N-m)! (N-m+1) を掛けると  (N-m+1)! (m-1)! m を掛けると  m! になる。これを使うと1行目から2行目のように通分できる。

2.263

 N = 1 のとき、 (1 + x)^1 = 1 + x \displaystyle \sum_{m=0}^1 \binom 1m x^m = \binom 10 x^0 + \binom 11 x^1 = 1 + x だから、(左辺)=(右辺)。
 N = k \in \mathbb{N} のとき、 \displaystyle (1 + x)^k = \sum_{m=0}^N \binom Nm x^m が正しいとして、 N = k + 1 のとき、

 \begin{align}
(1 + x)^{k + 1} &= (1 + x)(1 + x)^k \\
&= (1 + x)^k + x(1 + x)^k \\
&= \sum_{m=0}^k \binom km x^m + x \sum_{m=0}^k \binom km x^m \\
&= \sum_{m=0}^k \binom km x^m + \sum_{m=0}^k \binom km x^{m+1} \\
&= \sum_{m=0}^k \binom km x^m + \sum_{m=1}^{k+1} \binom k {m-1} x^m \\
&= \sum_{m=0}^0 \binom km x^m + \sum_{m=1}^k \binom km x^m + \sum_{m=1}^{k} \binom k {m-1} x^m + \sum_{m=k+1}^{k+1} \binom k {m-1} x^m \\
&= 1 + \sum_{m=1}^k \binom {k+1}m x^m + x^{k+1} \\
&= \sum_{m=0}^0 \binom {k+1}m x^m + \sum_{m=1}^k \binom {k+1}m x^m + \sum_{m=k+1}^{k+1} \binom {k+1}m x^m \\
&= \sum_{m=0}^{k+1} \binom {k+1}m x^m
\end{align}

  • 1行目:指数の法則。
  • 1→2行目:分配法則。
  • 4→5行目: \sum の添字を1個進めて中身を1個戻すと結局同値。これに気付かなくて秋葉原のスタバで1時間ぐらい粘って結局分からずに帰った。
  • 5→6行目:6行目の前2項は5行目の第1項を分解したもの。後2項は5行目の第2項を分解したもの。
  • 7→8行目:別にこう書いてもいいよね!!

2.264

 \begin{align}
\sum_{m=0}^N \binom Nm \mu^m (1 - \mu)^{N-m} &= \sum_{m=0}^N \binom Nm \mu^m \frac{(1 - \mu)^N}{(1 - \mu)^m} \\
&= (1 - \mu)^N \sum_{m=0}^N \binom Nm \mu^m \frac{1}{(1 - \mu)^m} \\
&= (1 - \mu)^N \sum_{m=0}^N \binom Nm \left( \frac{\mu}{1 - \mu} \right)^m \\
&= (1 - \mu)^N \left( 1 + \frac{\mu}{1 - \mu} \right)^N \\
&= (1 - \mu)^N \left( \frac{1-\mu}{1-\mu} + \frac{\mu}{1-\mu} \right)^N \\
&= (1 - \mu)^N \left( \frac{1}{1-\mu} \right)^N \\
&= \left( \frac{1-\mu}{1-\mu} \right)^N \\
&= 1^N = 1
\end{align}

分数で二項定理するっていうのが思い付かずに答えを見てしまった。辛い。理解できればそれでええんや……。模範解答では4行目からラストにワープしててファッ!? ってなった。これぐらい自分で展開しろということなのか。まあそれはそうか。

PRML 式(2.6)から式(2.7)の導出

目的

二値確率変数の観測値の集合が与えられた時に、ベルヌーイ分布のパラメータ {\mu} を推定したい。

考え方

観測した値が出る確率を全部かける。

{ \displaystyle
p(\mathcal{D}|\mu) = \prod_{n=1}^{N} p(x_n|\mu) = \prod_{n=1}^{N} \mu^{x_n} (1-\mu)^{1-x_n}
}

これが尤度関数で、頻度主義的にはこれを最大化すれば一番 {\mathcal{D}} を観測しやすい {\mu} が得られる。
尤度関数の対数を取ったものを使ってもそれを最大化すれば同値なので、

{ \displaystyle
\ln{p(\mathcal{D}|\mu)} = \sum_{n=1}^{N} \ln{p(x_n|\mu)} = \sum_{n=1}^{N} \left\{ x_n \ln{\mu} + (1-x_n) \ln{(1-\mu)} \right\}
}

これを  \mu微分して0になる時の方程式を解けばいいって軽く書いてあるけど真面目に解いたらかなりダルかった。以下式変形を愚直に。


\begin{align}
\frac{\partial \ln{p(\mathcal{D}|\mu)}}{\partial \mu} &= \sum_{n=1}^{N} \left\{ \frac{x_n}{\mu} + (1-x_n) \frac{(1-\mu)'}{1-\mu} \right\} \\
&= \sum_{n=1}^{N} \left( \frac{x_n}{\mu} - \frac{1-x_n}{1-\mu} \right) \\
&= \sum_{n=1}^{N} \left\{ \frac{x_n(1-\mu)}{\mu(1-\mu)} - \frac{\mu(1-x_n)}{\mu(1-\mu)} \right\} \\
&= \frac{1}{\mu(1-\mu)} \sum_{n=1}^{N} \left( x_n - \mu x_n - \mu + \mu x_n \right) \\
&= \frac{1}{\mu(1-\mu)} \sum_{n=1}^{N} \left( x_n - \mu \right) \\
&= \frac{1}{\mu(1-\mu)} \left( \sum_{n=1}^{N} x_n - N \mu \right)
\end{align}

これが0になればいいので、


\begin{align}
\frac{1}{\mu(1-\mu)} \left( \sum_{n=1}^{N} x_n - N \mu \right) &= 0 \\
\sum_{n=1}^{N} x_n - N \mu &= 0 \\
N \mu &= \sum_{n=1}^{N} x_n \\
\mu &= \frac{1}{N} \sum_{n=1}^{N} x_n
\end{align}

と、無事式(2.7)になりました。なったからたぶんこれで正しいんだと思う。

ついでに、 x_n \in \{0, 1\} なので、 x_n = 1 となった回数を  m と置くと、 \displaystyle{\mu = \frac{m}{N}} なので、要は「結局試行の中で1が出た割合がベルヌーイ分布のパラメータそのものなんじゃね?」という話に帰着するのですが、そうすると同じコインを3回投げて3回とも表が出たらパラメータは1になるという「は?」って感じの結論が導かれるので、そういうのを防ぐためにベイジアンなアプローチによって事前分布を用意してから計算しようねというのが次のベータ分布以降の話なんだと思います。たぶん。

補足

数Ⅱの微積ですが。

係数: \{c \cdot f(x) \}' = c \cdot f'(x)
和の微分 \{ f(x) + g(x) \}' = f'(x) + g'(x)

合成関数の微分 g(f(x))' = \frac{dg}{df} \cdot \frac{df}{dx}
自然対数微分 \ln(c) = \frac{1}{c}
この2つから  \{ \ln{f(x)} \}' = \frac{f'(x)}{f(x)}(↑↑の  g \ln のとき)★

微分するところの1行目で★を全部使ってるので一応示しておきます。