クローリングした画像を整備する

前回の続きでアニメ画像データセットを整備した際のメモ.
今回はゴミとして, 3次元画像・漫画画風画像を自動で除去した.
また, 顔でない画像などの微細なゴミは手動で除去した.

1キャラクタのディレクトリの中に複数のキャラクタが含まれる問題では,
今回は手動で1キャラにした.
今後の戦略としては, キャラクタごとのディレクトリに入っている各画像に対して,
髪色や目の色などを自動で分類し, ディレクトリに入っている半分以上の画像ファイルが同じ分類をされたらその半分を残すというアルゴリズムを用いれば, この問題を小さく抑えることができるという所感を持った.

取り合えず今の精度でも下のような感じのファイルが500ほど作れることが分かった.
f:id:umashika5555:20200511003607p:plain
f:id:umashika5555:20200511003615p:plain
f:id:umashika5555:20200511003624p:plain
f:id:umashika5555:20200511003643p:plain

【Python】Wikipediaの表の特定の項目のみを取得

アニメ一覧表から各アニメのタイトル、各アニメの記事へのリンクの2要素のみを取得しCSVとして保存する場合
ja.wikipedia.org

import requests
from bs4 import BeautifulSoup
import csv

# スクレイピング対象の URL にリクエストを送り HTML を取得する
res = requests.get('https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC%E3%81%AE%E3%83%86%E3%83%AC%E3%83%93%E3%82%A2%E3%83%8B%E3%83%A1%E4%BD%9C%E5%93%81%E4%B8%80%E8%A6%A7_(2010%E5%B9%B4%E4%BB%A3_%E5%BE%8C%E5%8D%8A)')

# レスポンスの HTML から BeautifulSoup オブジェクトを作る
soup = BeautifulSoup(res.text, 'html.parser')

# ページに含まれるテーブルをすべて取得する
tables = [table for table in soup.find_all("table", {"class":"wikitable"})]

# 各テーブルから行を取得する
rows = []
for table in tables:
    rows_each_table = [row for row in table.find_all("tr")]
    rows_each_table.pop(0) # 表の題目を除去 (deque推奨)
    rows +=  rows_each_table

# ラインのリストからタイトルとURLを取得
animes = []
for row in rows:
    a_list = row.find_all("a")
    anime_object = a_list[0]
    anime_name, anime_link = anime_object.get("title"), anime_object.get("href")
    animes.append((anime_name, anime_link))

# CSV へ書き込み
with open("./anime.csv", "w", encoding="utf-8") as f:
    writer = csv.writer(f, lineterminator="\n")
    for anime in animes:
        writer.writerow(anime)

【Python】google-images-download の使い方

公式でエラー出るのでパッチの方をダウンロード
100件までしかダウンロードできないらしいが, 私の用途だと20件程度で良かったので今のところ十分.

$ git clone https://github.com/Joeclinton1/google-images-download.git
$ cd google-images-download
$ sudo python setup.py install

使い方の例

JSONから引数取得
$ googleimagesdownload -cf example.json
検索キーワード, 検索上限
$ googleimagesdownload --keywords "Polar bears, baloons, Beaches" --limit 20
接頭辞検索

車について検索したい. 「赤い車」「青い車」「白い車」の順に検索したい場合

$ googleimagesdownload --k "car" -sk 'red,blue,white' -l 10
short hand command

\--limitを-l, --keywordを-kとしてもよい.

$ googleimagesdownload -k "Polar bears, baloons, Beaches" -l 20
画像ファイルではなく画像のリンクをダウンロードする
$ googleimagesdownload -k "sample" -u <google images page URL>
デフォルトディレクトリのdownload/ではなく, 指定したディレクトリに保存する
$ googleimagesdownload -k "boat" -o "boat_new"
URL指定で一つの画像をダウンロードする
$ googleimagesdownload --keywords "baloons" --single_image <URL of the images>

【確率統計】よく使われるもの

正規分布最尤推定

1次元データにおける正規分布を当てはめたときの最尤推定の計算

尤度関数


\begin{aligned}
p(\boldsymbol{x}; \mu, \sigma^2) &= \prod_{n=1}^{N}N(x_{n}; \mu, \sigma^2)
\end{aligned}

対数尤度関数


\begin{aligned}
\ln p(\boldsymbol{x}; \mu, \sigma^2) 
&= \ln \prod_{n=1}^{N}N(x_{n}; \mu, \sigma^2)\\
&= \ln \prod_{n=1}^{N} \frac{1}{\sqrt{2\pi\sigma^2}}\exp\left\{-\frac{(x-\mu)^2}{2\sigma^2}\right\}\\
&= \ln \left[ \left(\frac{1}{\sqrt{2\pi\sigma^2}}\right)^N \exp\left\{-\sum_{n=1}^{N}\frac{(x-\mu)^2}{2\sigma^2}\right\} \right]\\
&= -\frac{N}{2}\ln{2\pi}-\frac{N}{2}\ln{\sigma^2}-\frac{1}{2\sigma^2}\sum_{n=1}^{N}(x_{n}-\mu)^2\\
\end{aligned}

Chebyshev不等式

Pr(|X-\mu|\geq k) \leq \frac{\sigma^2}{k^2}を示す.

 
\begin{aligned}
\sigma^2 
&= \int_{-\infty}^{\infty}(x-\mu)^2f(x)dx\\
&=\int_{-\infty}^{\mu-k}(x-\mu)^2f(x)dx + \int_{\mu-k}^{\mu+k}(x-\mu)^2f(x)dx + \int_{\mu-k}^{\infty}(x-\mu)^2f(x)dx\\
&\geq \int_{-\infty}^{\mu-k}(x-\mu)^2f(x)dx + \int_{\mu-k}^{\infty}(x-\mu)^2f(x)dx\\
\end{aligned}

 
\begin{aligned}
X \leq \mu - k , \mu+k\leq X
& \Leftrightarrow X-\mu \leq -k, k \leq X -\mu\\
& \Leftrightarrow -(X-\mu)\geq k, k \leq (X-\mu) \\
& \Leftrightarrow |X-\mu|\geq k
\end{aligned}
したがって,
 (X-\mu)^2 \geq k^2

これより,

\begin{aligned}
\sigma^2 
&\geq \int^{\mu-k}_{-\infty}(x-\mu)^2f(x)dx + \int_{\mu+k}^{\infty}(x-\mu)^2f(x)dx\\
&\geq \int^{\mu-k}_{-\infty}k^2f(x)dx + \int_{\mu+k}^{\infty}k^2f(x)dx\\
&= k^2 \int_{|X-\mu|\geq k}f(x)dx\\
&= k^2 Pr(|X-\mu|>k)\\
\end{aligned}


 \therefore Pr(|X-k|\geq k)\leq \frac{\sigma^2}{k^2}

大数の法則

Chebyshevの不等式から証明できる.
Chebyshevの不等式の証明は次のリンクへ.
http://umashika5555.hatenablog.com/entry/2020/02/27/213325umashika5555.hatenablog.com


確率変数 \frac{X_1 + \cdots X_n}{n}の期待値と分散を計算する.
 
\begin{aligned}
E\left( \frac{X_1 + \cdots X_n}{n} \right)
&= \frac{1}{n}E(X_1 + \cdots + X_n)\\
&= \frac{1}{n}\left(E(X_1)+ \cdots + E(X_n)\right)\\
&= \frac{1}{n} (\mu + \cdots + \mu)\\
&= \frac{n\mu}{n}\\
&= \mu
\end{aligned}
 
\begin{aligned}
V\left( \frac{X_1 + \cdots X_n}{n} \right)
&= \frac{1}{n^2} \left(V(X_1) + \cdots V(X_n)\right)\\
&= \frac{1}{n^2}(\sigma^2 + \cdots + \sigma^2)\\
&= \frac{1}{n^2} n\sigma^2\\
&= \frac{\sigma^2}{n}
\end{aligned}

次にChebyshevの不等式より
 
\begin{aligned}
P\left\{|\frac{X_1 + \cdots + X_n}{n} - \mu | \geq \epsilon \right\} \leq \frac{\frac{\sigma^2}{n}}{k^2} = \frac{\sigma^2}{nk^2}
\end{aligned}
 n \rightarrow \inftyのとき,
 P\left\{|\frac{X_1 + \cdots + X_n}{n} - \mu | \geq \epsilon \right\} \rightarrow 0

これはすなわち,  \frac{X_1 + \cdots + X_n}{n} \rightarrow \muを表している.

中心極限定理

中心極限定理
 
\begin{aligned}
p\left\{\frac{X_1 + \cdots + X_n -n\mu}{\sqrt{n}\sigma} \leq x \right\} \rightarrow \int_{-\infty}^{x}\frac{1}{\sqrt{2\pi}}e^{-\frac{x^2}{2}}dx
\end{aligned}
を示す.

中心極限定理は, 母平均とのズレがGauss分布に近づくという意味である.
左辺は母平均とのズレの分布関数, 右辺は, N(0,1)のGauss分布を表している.
証明は, 左辺の確率変数の積率母関数が右辺の分布関数の積率母関数と同じになることを示す.

まず右辺について,
 
\begin{aligned}
\int_{-\infty}^{x}\frac{1}{\sqrt{2\pi}}e^{-\frac{x^2}{2}}dx =\int_{-\infty}^{x} N(x; 0, 1) dx 
\end{aligned}
 X\sim N(x; 0,1)積率母関数は,  e^{\frac{1\cdot \theta^2}{2} + 0\cdot \theta} = e^{\frac{\theta^2}{2}}
※Gauss分布の積率母関数は次のリンクへ.
http://umashika5555.hatenablog.com/entry/2020/02/22/030913umashika5555.hatenablog.com


次に, 左辺についてみていく.
 p\left\{\frac{X_1 + \cdots + X_n -n\mu}{\sqrt{n}\sigma} \leq x \right\} = p\left\{\frac{(X_1-\mu) + \cdots + (X_n-\mu) }{\sqrt{n}\sigma} \leq x \right\} より,
 Y_k = X_k -\muと置くと考えやすい. (と言うか, コレが本質)
 E(Y_k) = E(X_k - \mu) = E(X_k) - \mu = \mu - \mu = 0
 
\begin{aligned}
E(Y_k^2) &= E((X_k - \mu)^2) \\
&= E(X_k^2 - 2\mu X_k + \mu^2)\\ 
&= E(X_k^2)  - 2\mu E(X_k) + \mu^2\\ 
&= V(X_k) + E(X_k)^2 -2\mu E(X_k) + \mu^2  \\
&= \sigma^2 + \mu^2 -2\mu^2 + \mu^2 \\
&= \sigma^2\\
\end{aligned}
 Y_k積率母関数は,
 
\begin{aligned}
\phi(\theta) 
&= 1 + \frac{1}{1!}\cdot E(Y_k) \cdot \theta + \frac{1}{2!}\cdot E(Y_k^2) \cdot \theta^2 + O(\theta^3)\\
&= 1 + \frac{1}{1!}\cdot 0 \cdot \theta + \frac{1}{2!}\cdot \sigma^2 \cdot \theta^2 + O(\theta^3)\\
&= 1 + \frac{\sigma^2}{2}\theta^2 + O(\theta^3)
\end{aligned}
確率変数 \frac{X_1 + \cdots + X_n -n\mu}{\sqrt{n}\sigma} = \frac{Y_1 + \cdots + Y_{n}}{\sqrt{n}\sigma} = \frac{Y_1}{\sqrt{n}\sigma} + \cdots + \frac{Y_n}{\sqrt{n}\sigma}積率母関数を考える.
互いに独立な確率変数 X, Yについて,  X+Y積率母関数は各々の積率母関数の積で表されることを証明する.
 
\begin{aligned}
\Psi(\theta) &= E(e^{\theta (X+Y)})\\
&= E(e^{\theta X + \theta Y} )\\
&= E(e^{\theta X} \cdot e^{\theta Y})\\
&= E(e^{\theta X}) \cdot E(e^{\theta Y})\\
&= \phi_1(\theta)\phi_2(\theta)
\end{aligned}
これはn個に拡張できることは自明なので,
 \frac{Y_1 + \cdots + Y_n}{\sqrt{n}\sigma} =\frac{Y_1}{\sqrt{n}\sigma} + \cdots + \frac{Y_n}{\sqrt{n}\sigma}積率母関数 \phi_n(\theta) Y_k積率母関数 \phi(\theta)を用いて次のように表現できる.
 
\begin{aligned}
\phi_n(\theta) &= \left\{\phi(\frac{\theta}{\sqrt{n}\sigma})\right\}^n \\
&= \left\{1+\frac{\sigma^2}{2}(\frac{\theta}{\sqrt{n}\sigma})^2 + O(n^{-\frac{3}{2}})\right\}^n\\
&= \left\{1+\frac{\theta^2}{2n} + O(n^{-\frac{3}{2}})\right\}^n\\
\end{aligned}
ここで,  x = \frac{\theta^2}{2n} + O(n^{-\frac{3}{2}})と置くと,  n = \frac{1}{x}\left\{\frac{\theta^2}{2} + O(n^{-\frac{1}{2}})\right\}となる.
 n\rightarrow \inftyのとき,  x\rightarrow 0より,
 
\begin{aligned}
\phi_n(\theta) 
&= \left\{1+\frac{\theta^2}{2n} + O(n^{-\frac{3}{2}})\right\}^n\\
&= (1 +x)^{\frac{1}{x}\{\frac{\theta^2}{2}+O(n^{-\frac{1}{2}})\}} \\
&= \left( (1 +x)^\frac{1}{x}\right)^{\frac{\theta^2}{2}+O(n^{-\frac{1}{2}})} \\
&\rightarrow e^{\frac{\theta^2}{2}}
\end{aligned}

正規分布エントロピー


\begin{aligned}
H(X) &= E(-\ln f(x))\\
&= \int_{-\infty}^{\infty}(-\ln f(x))f(x)dx\\
&= \int_{-\infty}^{\infty}\left(-\ln \frac{1}{\sqrt{2\pi\sigma^2}}\exp\left\{-\frac{(x-\mu)^2}{2\sigma^2}\right\}\right)\frac{1}{\sqrt{2\pi\sigma^2}}\exp\left\{-\frac{(x-\mu)^2}{2\sigma^2}\right\}dx\\
&= \frac{\ln (2\pi\sigma^2)}{2\sqrt{2\pi\sigma^2}}\int_{-\infty}^{\infty}e^{-\frac{(x-\mu)^2}{2\sigma^2}}dx + \frac{1}{2\sigma^2\sqrt{2\pi\sigma^2}}\int_{-\infty}^{\infty}(x-\mu)^2 e^{-\frac{(x-\mu)^2}{2\sigma^2}}dx\\
\end{aligned}

前項はガウス積分
 \frac{\ln (2\pi\sigma^2)}{2\sqrt{2\pi\sigma^2}}\sqrt{\frac{\pi}{\frac{1}{2\sigma^2}}} = \frac{\ln (2\pi\sigma^2)}{2}

後項は \frac{x-\mu}{\sqrt{2\sigma^2}} = tとおいて,  e^{-t^2} = -\frac{(e^{-t^2})'}{2t}として部分積分して,
 \frac{1}{2\sigma^2\sqrt{2\pi\sigma^2}}\int_{-\infty}^{\infty}(x-\mu)^2 e^{-\frac{(x-\mu)^2}{2\sigma^2}}dx = \frac{1}{2}

よって,
 H(X) = \frac{1}{2}\left\{\ln (2\pi\sigma^2) + 1\right\} = \frac{1}{2}\ln (2\pi\sigma^2e)

エントロピーは分散によって比例する関数であることが分かり, 分散が大きくなるほどエントロピーが大きくなることがわかる.

【確率論】確率分布まとめ

Poisson分布

定義

 p(k; \lambda)= e^{-\lambda}\frac{\lambda^k}{k!}

導出

Poisson分布は二項分布の np=\lambda, n \rightarrow \infty(p \rightarrow 0) にして定義されている.
二項分布

\begin{aligned}
b(k; n,p) 
&= \dbinom{n}{k}p^k(1-p)^{n-k}\\
&= \frac{n!}{k!(n-k)!}p^k(1-p)^{n-k}\\
&= \frac{n(n-1)\cdots (n-k+1)}{k!}p^k(1-p)^{n-k}\\
&= \frac{n(n-1)\cdots (n-k+1)}{n \cdot n \cdots n}n^kp^k\frac{1}{k!}(1-p)^{n-k}\\
&= \frac{n(n-1)\cdots (n-k+1)}{n \cdot n \cdots n}(np)^k\frac{1}{k!}\frac{(1-p)^{n}}{(1-p)^{k}}\\
&= \frac{n(n-1)\cdots (n-k+1)}{n \cdot n \cdots n}\lambda^k\frac{1}{k!}\frac{((1-\frac{\lambda}{n})^{-\frac{n}{\lambda}})^{-\lambda}}{(1-p)^{k}}\\
& \rightarrow 1\cdot \lambda^k \cdot \frac{1}{k!} \cdot e^{-\lambda}\\
&= e^{-\lambda}\frac{\lambda^k}{k!}
\end{aligned}

積分

 f(x)=e^xマクローリン展開 f^{(n)}(x)=e^xより f^{(n)}(0)=1であるから,
 e^x=f(0)+f'(0)+\frac{1}{2!}f''(0)x^2+\cdots + \frac{1}{n!}f^{(n)}x^n+\cdots =1+x+\frac{1}{2!}x^2+\cdots + \frac{1}{n!}x^n+\cdots

\begin{aligned}
\sum^{\infty}_{k=0}e^{-\lambda}\frac{\lambda^k}{k!}
&= e^{-\lambda}\sum_{k=0}^{\infty}\frac{\lambda^k}{k!}\\
&= e^{-\lambda}\left(\frac{\lambda^0}{0!}+\frac{\lambda^1}{1!}+\frac{\lambda^2}{2!}+\cdots + \frac{\lambda^n}{n!}+\cdots \right)\\
&= e^{-\lambda}e^{\lambda}\\
&= 1
\end{aligned}

期待値


\begin{aligned}
E(X)
&= \sum_{k=0}^{\infty}ke^{-\lambda}\frac{\lambda^{k}}{k!}\\
&= e^{-\lambda}\sum_{k=0}^{\infty}k\frac{\lambda^{k}}{k!}\\
&= e^{-\lambda}\sum_{k=1}^{\infty}k\frac{\lambda^{k}}{k!}\\
&= e^{-\lambda}\lambda\sum_{k=1}^{\infty}\frac{\lambda^{k-1}}{(k-1)!}\\
&= e^{-\lambda}\lambda\sum_{m=0}^{\infty}\frac{\lambda^{m}}{m!}\\
&= e^{-\lambda}\lambda e^{\lambda}\\
&= \lambda
\end{aligned}

分散

 k^2=k(k-1)+kを利用する.

\begin{aligned}
E(X^2)
&=\sum_{k=0}^{\infty}k^2e^{-\lambda}\frac{\lambda^k}{k!}\\
&= \left(\sum_{k=0}^{\infty}k(k-1)\frac{\lambda^{k-2}}{k(k-1)(k-2)!}\lambda^2+e^{\lambda}E(X)\right)\\
&= e^{-\lambda}\left(\sum_{k=2}^{\infty}\frac{\lambda^{k-2}}{(k-2)!}\lambda^2+e^{\lambda}\lambda\right)\\
&= e^{-\lambda}\left(\sum_{m=0}^{\infty}\frac{\lambda^{m}}{m!}\lambda^2+e^{\lambda}\lambda\right)\\
&= e^{-\lambda}(e^{\lambda}\lambda^2+e^{\lambda}\lambda)\\
&= \lambda^2 + \lambda\\
V(X) 
&= E(X^2) -E(X)^2\\
&= \lambda^2 + \lambda - \lambda^2\\
&= \lambda
\end{aligned}

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from IPython.core.pylabtools import figsize
figsize(12.5, 4)

poi = stats.poisson # Poisson分布
lambda_ = [1.5, 5.5, 12] # Poisson分布のパラメタ(強度λ)
colors = ["#348ABD", "#A60628", "#66FFB2"]

a = np.arange(16) # [0, 1, 2, ..., 15]
# poi.pmf(a, λ)でPoisson分布の値を得る
plt.bar(a, poi.pmf(a, lambda_[0]), color=colors[0], label="$\lambda = %.1f$"%lambda_[0], alpha=0.6, edgecolor=colors[0], lw=1)
plt.bar(a, poi.pmf(a, lambda_[1]), color=colors[1], label="$\lambda = %.1f$"%lambda_[1], alpha=0.6, edgecolor=colors[1], lw=1)
plt.bar(a, poi.pmf(a, lambda_[2]), color=colors[2], label="$\lambda = %.1f$"%lambda_[2], alpha=0.6, edgecolor=colors[2], lw=1)
plt.legend()
plt.ylabel("Probability of $k$") #kの確率
plt.xlabel("$k$")

f:id:umashika5555:20200228004910p:plain

幾何分布

定義

 P\left\{X=k\right\}=(1-p)^{k}p

意味

ベルヌーイ試行で初めて成功するまでの試行回数の確率

期待値

 
\begin{aligned}
E(X)
&= \sum_{k=0}^{\infty}k(1-p)^kp\\
&=p\lim_{n\rightarrow \infty}\sum_{k=0}^{n}k(1-p)^{k}\\
& =p\lim_{n\rightarrow \infty} \frac{1-p}{p^2}\left(1-(1-p)^n(1+np^2)\right)\\
&= p \frac{1-p}{p^2}\\
&= \frac{1-p}{p}
\end{aligned}

分散

 
\begin{aligned}
E(X^2)
&=\sum^{\infty}_{k=0}k^2(1-p)^{k}p\\
&=p\sum^{\infty}_{k=0}k^2(1-p)^k\\
&=p\lim_{n\rightarrow \infty}\sum^{n}_{k=0}k^2(1-p)^k\\\\
&= p \lim_{n\rightarrow \infty}\left(\frac{1}{p}\left\{2\sum^{n}_{k=1}k(1-p)^k - \sum_{k=1}^n(1-p)^k\right\}\right)\\
&= p \lim_{n\rightarrow \infty} \frac{1}{p}\left[\left(\frac{2}{p}-1\right)\frac{(1-p)\{1-(1-p)^n\}}{p}-\frac{2n}{p}(1-p)^n\right]\\
&= p\frac{1}{p}\left(\frac{2}{p}-1\right)\frac{1-p}{p}\\
&= \frac{p^2-3p+2}{p^2}\\
V(X)
&= E(X^2) - E(X)^2\\
&= \frac{p^2-3p+2}{p^2}-\left(\frac{1-p}{p}\right)^2\\
&= \frac{1-p}{p^2}
\end{aligned}

scipy.stats.geomでは (1-p)^{k-1}pで定義されているため, k=0は定義なし.
成功確率が高いときは大きい試行回数の値で確率が小さくなり, 反対に成功確率が小さいときは大きい試行回数でも確率が比較的に小さくならない.

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from IPython.core.pylabtools import figsize
figsize(12.5, 4)

geo = stats.geom # Geometric分布
p = [0.1, 0.5, 0.9] # Geometric分布のパラメタ(確率p)
colors = ["#348ABD", "#A60628", "#66FFB2"]

k = np.arange(16) # [0, 1, 2, ..., 15]
# geo.pmf(k,p)でGeometric分布の値を得る
plt.bar(k, geo.pmf(k, p[0]), color=colors[0], label="$p = %.1f$"%p[0], alpha=0.6, edgecolor=colors[0], lw=1)
plt.bar(k, geo.pmf(k, p[1]), color=colors[1], label="$p = %.1f$"%p[1], alpha=0.6, edgecolor=colors[1], lw=1)
plt.bar(k, geo.pmf(k, p[2]), color=colors[2], label="$p = %.1f$"%p[2], alpha=0.6, edgecolor=colors[2], lw=1)

plt.xticks(k, k)
plt.legend()
plt.ylabel("Probability of $k$") #kの確率
plt.xlabel("$k$")

f:id:umashika5555:20200228010632p:plain

Gauss分布

定義

 N(x ; \mu, \sigma^2)=\frac{1}{\sqrt{2\pi\sigma^2}}\exp{\left(-\frac{(x-\mu)^2}{2\sigma^2}\right)}

積分

まずガウス積分 \int_{-\infty}^{+\infty}\exp{(-x^2)}dx=\sqrt{\pi}の導出を行う.
 x=r \cos \theta , y=r \sin \thetaと置き, ヤコビアン rと計算できる.

\begin{aligned}
I =  \int_{-\infty}^{+\infty}\exp{(-x^2)}dx 
\end{aligned}
とおく.

\begin{aligned}
I^2 
&=  \int_{-\infty}^{+\infty}\exp{(-x^2)}dx \int_{-\infty}^{+\infty}\exp{(-x^2)}dx \\
&=  \int_{-\infty}^{+\infty}\int_{-\infty}^{+\infty} \exp{(-(x^2+y^2))}dxdy \\
&= \int_{0}^{2\pi}d\theta \int^{\infty}_{0} \exp{(-r^2)}r dr\\
&= 2\pi(-\frac{1}{2})\left[\exp{(-r^2)}\right]^{\infty}_{0}\\
&= 2\pi(-\frac{1}{2})(0-1)\\
&=\pi\\
\therefore I &=\sqrt{\pi}\ (\because\ I>0)
\end{aligned}
次に,  \int_{-\infty}^{+\infty}\exp{(-ax^2)}dx=\sqrt{\frac{\pi}{a}}の導出を行う.
これは \sqrt{a}x = tと置きガウス積分に代入できる.
その際,  dx = \frac{1}{\sqrt{a}}dtよりガウス積分の結果 \sqrt{\pi}に係数 \frac{1}{\sqrt{a}}が付き,
最終的な結果が \sqrt{\frac{\pi}{a}}となる.

これらの結果から, 正規分布積分が計算できる.
 
\begin{aligned}
\int^{+\infty}_{-\infty}\frac{1}{\sqrt{2\pi\sigma^2}}\exp{\left(-\frac{(x-\mu)^2}{2\sigma^2}\right)}dx
&= \frac{1}{\sqrt{2\pi\sigma^2}} \int^{+\infty}_{-\infty}\exp{\left(-\frac{(x-\mu)^2}{2\sigma^2}\right)}dx\\
&= \frac{1}{\sqrt{2\pi\sigma^2}} \sqrt{\frac{\pi}{\frac{1}{2\sigma^2}}}\\
&= \frac{1}{\sqrt{2\pi\sigma^2}} \sqrt{2\pi\sigma^2}\\
&= 1
\end{aligned}

期待値

 x=(x-\mu) + \muとして, 後ろの項は定数なので, 確率分布のみの積分となり, 確率分布の性質から積分して1になる.
 
\begin{aligned}
E(X) 
&= \int_{-\infty}^{\infty}xf(x)dx\\
&= \int_{-\infty}^{\infty}(x-\mu)f(x)dx + \mu\int_{-\infty}^{\infty}f(x)dx\\
&= 0 + \mu \cdot 1\\
&= \mu
\end{aligned}

分散

 x^2 = (x-\mu)^2 + 2\mu x - \mu^2を用いる.

\begin{aligned}
E(X^2)
&= \int_{-\infty}^{\infty}x^2N(x; \mu, \sigma^2)dx\\
&= \frac{1}{\sqrt{2\pi\sigma^2}}\int_{-\infty}^{\infty}x^2\exp\left\{-\frac{(x-\mu)^2}{2\sigma^2}\right\}dx\\
&= \frac{1}{\sqrt{2\pi\sigma^2}}\int_{-\infty}^{\infty}(x-\mu)^2\exp\left\{-\frac{(x-\mu)^2}{2\sigma^2}\right\}dx + 2\mu \int_{-\infty}^{\infty}x\frac{1}{\sqrt{2\pi\sigma^2}}\exp\left\{-\frac{(x-\mu)^2}{2\sigma^2}\right\}dx - \frac{\mu^2 }{\sqrt{2\pi\sigma^2}}\int_{-\infty}^{\infty}\exp\left\{-\frac{(x-\mu)^2}{2\sigma^2}\right\}dx\\
&= \frac{1}{\sqrt{2\pi\sigma^2}}\int_{-\infty}^{\infty}(x-\mu)^2\exp\left\{-\frac{(x-\mu)^2}{2\sigma^2}\right\}dx + 2\mu E(X) - \frac{\mu^2 }{\sqrt{2\pi\sigma^2}}\int_{-\infty}^{\infty}\exp\left\{-\frac{(x-\mu)^2}{2\sigma^2}\right\}dx\\
\end{aligned}
第1項は,  (x-\mu)=tとして,  e^{-t^2} = -\frac{(e^{-t^2})'}{2t}と見なし部分積分して \sigma^2
第2項は,  2\mu E(X) = 2\mu\cdot\mu = 2\mu^2\
第3項はガウス積分を行い,  -\frac{\mu^2}{\sqrt{2\pi\sigma^2}}\cdot\sqrt{\frac{\pi}{\frac{1}{2\sigma^2}}}= -\frac{\mu^2}{\sqrt{2\pi\sigma^2}}\cdot \sqrt{2\pi\sigma^2}=-\mu^2
よって,  E(X^2) = \sigma^2 + 2\mu^2 - \mu^2 = \sigma^2 +\mu^2
したがって分散は,  V(X) = E(X^2) - E(X)^2 = \sigma^2 + \mu^2 -\mu^2 = \sigma^2

積率母関数


\begin{aligned}
\int_{-\infty}^{\infty}e^{\theta x}N(x; \mu, \sigma^2)dx
&= \frac{1}{\sqrt{2\pi\sigma^2}}\int_{-\infty}^{\infty}\exp{\left(\theta x-\frac{(x-\mu)^2}{2\sigma^2}\right)}dx
\end{aligned}
ここで exp()内をxについて整理する.

\begin{aligned}
g(x) &:= \theta x - \frac{(x-\mu)^2}{2\sigma^2}\\
&= -\frac{1}{2\sigma^2}\left(x-(\sigma^2\theta+\mu)\right)^2+\frac{\sigma^2\theta^2}{2}+\mu\theta
\end{aligned}
この形はガウス積分なので係数と合わせて1となる.

\begin{aligned}
e^{\frac{\sigma^2\theta^2}{2}+\mu\theta} \cdot \frac{1}{\sqrt{2\pi\sigma^2}}\int_{-\infty}^{\infty}\exp{\left(-\frac{\left(x-(\sigma^2\theta+\mu)\right)^2}{2\sigma^2}\right)}dx
&= e^{\frac{\sigma^2\theta^2}{2}+\mu\theta} \cdot 1\\
&= e^{\frac{\sigma^2\theta^2}{2}+\mu\theta}
\end{aligned}

多次元Gauss分布

 

\begin{aligned}
N(\boldsymbol{x}; \boldsymbol{\mu}, \boldsymbol{\Sigma}) = \frac{1}{(2\pi)^{\frac{D}{2}}}\frac{1}{|\Sigma|^{\frac{1}{2}}}\exp\left\{-\frac{1}{2}(\boldsymbol{x}-\boldsymbol{\mu})^{T}\boldsymbol{\Sigma}^{-1}(\boldsymbol{x}-\boldsymbol{\mu})\right\}
\end{aligned}

指数分布

定義

 f(x) = 
  \begin{cases}
    \lambda e^{-\lambda x}\ &(x\geq 0)\\
    0\ &(x<0)
  \end{cases}

期待値


\begin{aligned}
E(X)
&= \int_{-\infty}^{\infty}xf(x)dx\\
&= \int_{0}^{\infty}x\lambda e^{-\lambda x}dx\\
&= \lambda \left(-\frac{1}{\lambda}\right)\int_{0}^{\infty}x(e^{-\lambda x})'dx\\
&= - \int_{0}^{\infty}x(e^{-\lambda x})'dx\\
&= -[xe^{-\lambda x}]^{\infty}_{0} + \int_{0}^{\infty}e^{-\lambda x}dx\\
&= (0-0) + [-\frac{1}{\lambda}e^{-\lambda x}]^{\infty}_{0}\\
&= \frac{1}{\lambda}
\end{aligned}

分散

 
\begin{aligned}
E(X^2)
&= \int_{-\infty}^{\infty}x^2f(x)dx=\lambda\int^{\infty}_{0}x^2e^{-\lambda x}dx\\
&= \lambda \left(\frac{1}{\lambda}\right)\int^{\infty}_{0}x^{2}(e^{-\lambda x})'dx\\
&=-\int^{\infty}_{0}x^{2}(e^{-\lambda x})'dx\\
&= -[x^2(e^{-\lambda x})]^{\infty}_{0} + 2\int^{\infty}_{0}xe^{-\lambda x}dx\\
&= 0 + 2\left(\frac{E(X)}{\lambda}\right)\\
&= \frac{2}{\lambda^2}\\
V(X)
&= E(X^2)-E(X)^2\\
&= \frac{2}{\lambda^2} - \left(\frac{1}{\lambda}\right)^2\\
&= \frac{1}{\lambda^2}
\end{aligned}

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from IPython.core.pylabtools import figsize
figsize(12.5, 4)

expo = stats.expon
lambda_ = [0.5, 1, 1.5] # 指数分布のパラメタλ
colors = ["#348ABD", "#A60628", "#66FFB2"]

a = np.linspace(0, 4, 100) # 本来は連続値だがグラフにする上で離散値をつくる

for l, c in zip(lambda_, colors):
  # 指数分布は scale=1/λ を入力する
  plt.plot(a, expo.pdf(a, scale=1. / l), lw=3, color=c, label="$\lambda = %.2f$"%l)
  plt.fill_between(a, expo.pdf(a, scale=1. /l), color=c, alpha=.33)
  

plt.legend()
plt.ylabel("$f(k$)") #kの確率
plt.xlabel("$k$")

f:id:umashika5555:20200228005623p:plain

二項分布

定義

 b(k; n, p) = \dbinom{n}{k}p^k(1-p)^{n-k}
k: ベルヌーイ試行についてある事象が成功する回数
n: すべての試行回数
p: ベルヌーイ試行についてある事象が成功する確率

積分

二項定理より自明
 \sum_{k=0}^{n}b(k: n,p) = \sum_{k=0}^{n}\dbinom{n}{k}p^k(1-p)^{n-k}=\left(p+(1-p)\right)^n=1^n=1

期待値


\begin{aligned}
E(X)
&=\sum_{k=0}^{n}kb(k;n,p)\\
&=0+\sum_{k=1}^{n}k\dbinom{n}{k}p^{k}(1-p)^{n-k}\\
&=\sum_{k=1}^{n}\frac{n(n-1)\cdots (n-k+1)}{(k-1)!}p^k(1-p)^{n-k}\\
&= np \sum_{k=1}^{n}\frac{(n-1)\cdots (n-k+1)}{(k-1)!}p^{k-1}(1-p)^{n-k}\\
&= np \sum_{l=0}^{n-1}\frac{(n-1)\cdots (n-l)}{l!}p^{l}(1-p)^{(n-1)-l}\\
&= np(p+(1-p))^{n-1}\\
&= np
\end{aligned}

分散

 V(X) = E(X^2) - E(X)^2を用いる.
 E(X^2)の計算では, 二項定理の係数を消すためと, 期待値の定義式に落とし込むため,
 k^2 = k(k-1) +k という処理を施す. 前半は, 期待値の計算のように二項定理の係数項が2つ分うち消える.
後半は, 期待値の定義の式と一致する.

\begin{aligned}
E(X^2)
&=\sum_{k=0}^{n}k^2b(k;n,p)\\
&=\sum_{k=2}^{n}k(k-1)\dbinom{n}{k}p^{k}(1-p)^{n-k} + \sum_{k=1}^{n}k\dbinom{n}{k}p^{k}(1-p)^{n-k}\\
&=n(n-1)\sum_{k=2}^{n}\frac{(n-2)\cdots (n-k+1)}{(k-2)!}p^k(1-p)^{n-k}+np\\
&=n(n-1)\sum_{m=0}^{n-2}\frac{(n-2)\cdots (n-m-1)}{m!}p^{m+2}(1-p)^{n-m-2}+np\\ 
&=p^{2}n(n-1)\sum_{m=0}^{n-2}\frac{(n-2)\cdots ((n-2)-m+1)}{m!}p^{m}(1-p)^{(n-2)-m}+np\\
&=p^{2}n(n-1)\left(p+(1-p)\right)^{n-2}+np\\
&=p^{2}n(n-1)+np\\
&=n^2p^2-np(1-p)\\

V(X)
&=E(X^2)-E(X)^2\\
&=n^2p^2+np(1-p)-(np)^2\\
&=np(1-p)\\
\end{aligned}

n=10のとき, p=0.1だと1回成功する確率が38%くらい. p=0.5だと5回成功する確率が25%くらい., p=0.9だと9回成功する確率が38%くらいと読み取れる.
実際, 代入して計算すると,
 b(k=1; n=10, p=0.1)=0.3874204890000005
 b(k=5, n=10, p=0.5)=0.24609375000000025
 b(k=9; n=10, p=0.9)=0.38742048900000037

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from IPython.core.pylabtools import figsize
figsize(12.5, 4)

binom = stats.binom # Binomial分布
n_ = [5, 10]
p_ = [0.1, 0.5, 0.9] # Binomial分布のパラメタ(確率p)
colors = ["#348ABD", "#A60628", "#66FFB2"]

for n in n_:
    for i, p in enumerate(p_):
        k = np.arange(n+1) # [0, 1, 2, ..., 15]
        # binom.pmf(k, n ,p)でBinomial分布の値を得る
        plt.bar(k, binom.pmf(k, n, p), color=colors[i], label="$n= %d, p = %.1f$"%(n,p), alpha=0.6, edgecolor=colors[i], lw=1)
  
    plt.xticks(k, k)
    plt.legend()
    plt.ylabel("Probability of $k$") #kの確率
    plt.xlabel("$k$")
    plt.show()
    plt.close()

f:id:umashika5555:20200228012208p:plain
f:id:umashika5555:20200228012220p:plain

【PyTorch】DataLoaderで(images, labels)だけでなく(images, labels, paths)をロードできるようにする

まずglob.glob()を用いて, すべての画像データのパスを保持したリストを作る.

def make_datapath_list(phase="train"):
     rootpath = "./data/"
     target_path = os.path.join(rootpath, phase,  "**", "*.jpg") # 最初の**はクラスのディレクトリ
     path_list = []
     # globを利用してサブディレクトリまでファイルパスを格納
     for path in glob.glob(target_path):
          path_list.append(path)
     return path_list
# 動作確認
train_list = make_datapath_list(phase="train")

次に前処理クラスを作っておく.
前処理クラスはImage.open("path")で読み込んだ1画像配列を受け取り, 変形などをしtorch.tensorを返すクラス

class ImageTransform():
     def __init__(self, resize, mean, std):
          self.data_transform = transforms.Composee([transforms.ToTensor(), transforms.Normalize(mean, std)])
     def __call__(self, img):
          return self.data_transform(img)

次にDatasetクラスを作成する. この際に, __getitem__()メソッドで返す値を3要素のタプルにする.

class Dataset(data.Dataset):
     def __init__(slef, file_list, transform=None):
          self.file_list = file_lsit
          self.file_transform = transform # 前処理クラスのインスタンス
     
     def __len__(self):
          return len(slef.file_list)
     
     def __getitem__(self, index):
           img_path = self.file_list[index] # index番目のpath
           img = Image.open(img_path) # index番目の画像ロード
           img_transformed = slef.transform(img) # 前処理クラスでtensorに変換
           label = img_path.split("/")[2] # クラスを表すディレクトリの文字列
           label = convert(label) # クラスを表すディレクトリ文字列から数値に変更
           return img_transformed, label, img_path

train_dataset = Dataset(file_list=train_list = make_datapath_list(phase="train"), transform=ImageTransform(size, mean, std))

データローダを作成

batch_size = 32
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)

# 動作確認: イテレータを作って初めのやつを表示する
tmp = iter(train_dataloader)
inputs, labels, paths = next(tmp)
print(inputs.size()) # torch.Size([32, 3, h, w])
print(labels) # tensor([label0, ...., label31])
print(paths) # [file_path0, ..., file_path31]

尚、動作の保証なし

Datasetクラスの__getitem__を工夫すれば, 良いことがわかった.
例えば, 2つの画像の組をロードすることや, 1つの画像とそれをセグメンテーションモデルにかけたもう1つのマスク画像の対をロードすることなど出来そう

UbuntuでLoLをプレイ

ゲームは基本的にWindowsでやるものだが, Linuxでもプレイすることができる.
Ubuntu18.04 LTSで動作を確認している.

手順としてはLutrisをインストールし, LutrisのWEBページからLeague of Legendsをinstallする.

# Ubuntu の場合
$ sudo add-apt-repository ppa:lutris-team/lutris
$ sudo apt-get update
$ sudo apt-get install lutris

lutris.net
lutris.net

物体認識を試す

ImageNetにおける物体認識をしたいとする.
通常ならイチからモデルを組み, データを入手し, 学習させ……という作業が必要なわけだが, ディープラーニングフレームワークKearsならこれが簡単にできる.
さらに, VGGやResNet, Xception, MobileNetなど自宅の計算機スペックでは学習が難しそうなモデルでも予め用意されたパラメータを取得することで, 研究所並の精度の予測ができる.

import numpy as np
from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input, decode_predictions
import keras.preprocessing.image as Image

# モデルの宣言
model = VGG16(weights="imagenet")


続いて予測を行う.
画像は次の画像を用いる.

f:id:umashika5555:20190115142604p:plain
アンゴラウサギ

# 予測
image_path = "angora.png"
image = Image.load_img(image_path, target_size=(224, 224))  # ImageNetのサイズ
x = Image.img_to_array(image)
x = np.expand_dims(x, axis=0)  # 次元を追加。(224, 224)->(1, 224, 224)
x = preprocess_input(x) # ImageNetでやってる前処理を同じようにやる

result = model.predict(x)
result = decode_predictions(result, top=3)[0]
print(result)  # show description

結果は以下の通り「この画像がアンゴラである確率は99.99%以上」スゴイッ!!

[('n02328150', 'Angora', 0.9999628), ('n02123394', 'Persian_cat', 1.3111491e-05), ('n02111889', 'Samoyed', 1.070684e-05)]

k-NN法をフルスクラッチ実装

今日はk-NN法(k-NearestNeighbor)を実装する.

k-NN法の概念

k-NN法は教師データから未知データを予測する教師あり学習の一つで, また, 線形回帰などのようにパラメータを最適化するような手法を取らない.
すなわち, 「教師データから識別境界のようなものを学習してから未知データが境界のどちらにあるか」という手法をとらずに, 「それぞれの未知データに対して教師データとの関係を見てどちらのクラスかを予測する」という方法をとる. これを怠惰学習というらしい.
k-NN法に関しては, 名前の通り, 未知データに対して最も近い教師データk個のうち多い方のクラスラベルを予測クラスとする.
まず下図のようなデータがあるとする. 赤色がクラス1, 緑色がクラス0 とする. 星がクラスラベルのわかっていない未知データである.
この未知データがどちらのクラスに入れた方が良いのかを予測したい.

f:id:umashika5555:20181223013754p:plain
データ


今k=3すると未知データから最も近い3つの教師データを抽出できる.
f:id:umashika5555:20181223020457p:plain
3-NN
赤色(クラス1)のデータが1つで緑色(クラス0)のデータが2つである.
よって多数決をとって, 緑(クラス0)データの方が多いので, 未知データは緑(クラス0)と予想する.
式で表すとこのようになるが, わざわざ式で表さなくてもよい.
f:id:umashika5555:20181223015047g:plain

データの生成

k-NN法を実装するために二次元のデータを生成する.
k-NN法は分布を仮定した方法ではないため, 分布から生成する必要は無いと思うが, ラベル付きのデータを生成したかったので取り敢えずガウス分布を使ってデータを生成した.

f:id:umashika5555:20181223015313p:plain
データ

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 乱数固定
np.random.seed(0)
# 平均ベクトル
Mu1, Mu2 = np.array([1, 10]), np.array([9,2])
# 分散共分散行列
sigma11, sigma12, sigma21, sigma22 = 4, 5,  6, 3
SIGMA1, SIGMA2 = np.array([[sigma11**2, np.sqrt(sigma11*sigma12)],[np.sqrt(sigma11*sigma12), sigma12**2]]), np.array([[sigma21**2, np.sqrt(sigma21*sigma22)],[np.sqrt(sigma21*sigma22), sigma22**2]])
# データ生成
values1 = np.random.multivariate_normal(Mu1, SIGMA1, 200)
values2 = np.random.multivariate_normal(Mu2, SIGMA2, 200)
# データ保存
np.save("./data/values1.npy", values1)
np.save("./data/values2.npy", values2)
# 散乱図の表示
plt.scatter(values1[:,0], values1[:,1], color="r")
plt.scatter(values2[:,0], values2[:,1], color="g")
plt.xlabel("x")
plt.ylabel("y")
plt.xlim(-10, 30)
plt.ylim(-10, 25)
plt.savefig("./img/data.png")
plt.show()

k-NN法による未知データの分類

格子点を未知データとして考え領域分割を行う.
格子点から各データ点までの距離を計算し, 最も近いデータ点k個のラベルから多数決を行う.
閾値が0.5のとき, kが奇数の場合は多数決が成立するのだが, kが偶数の場合で各ラベルが同じ個数あるとき多数決が成立しない.
よってkは奇数にするほうが良いことが分かる.
またkが大きくなると, 汎用性が高くなることが分かる.

f:id:umashika5555:20181223015636p:plain
k=1
f:id:umashika5555:20181223015651p:plain
k=2
f:id:umashika5555:20181223015705p:plain
k=3
f:id:umashika5555:20181223015720p:plain
k=4
f:id:umashika5555:20181223015818p:plain
k=5

f:id:umashika5555:20181223015836p:plain
k=7

f:id:umashika5555:20181223015854p:plain
k=9

f:id:umashika5555:20181223151116p:plain
k=51

import numpy as np
import matplotlib.pyplot as plt

# k-NN法のパラメータkを設定
k = 200
# データのロード
values1 = np.load("./data/values1.npy")
values2 = np.load("./data/values2.npy")

# データを
# 統合, その際に教師情報もつける
data = np.vstack((values1, values2))
labels = np.hstack((np.ones(len(values1)), np.zeros(len(values2))))

# 未知のデータとして格子点を作成
# 2つのデータから最小, 最大のx, yを探す
x_min, x_max = min(np.min(values1[:,0]), np.min(values2[:,0])), max(np.max(values1[:,0]), np.max(values2[:,0]))
y_min, y_max = min(np.min(values1[:,1]), np.min(values2[:,1])), max(np.max(values1[:,1]), np.max(values2[:,1]))
# 格子点を作成
xx = np.linspace(x_min-1, x_max+1, 300)
yy = np.linspace(y_min-1, y_max+1, 300)
xxx, yyy = np.meshgrid(xx, yy)# 格子点(xxx, yyy)が生成された. これを未知データとみなしてk-NN法を適用する.

class0 = []
class1 = []
thresholds = []

# k-NN法の適用
for i, (xx, yy) in enumerate(zip(xxx, yyy)):
    for j, (x, y) in enumerate(zip(xx, yy)):
        # 未知データ(x,y)から既知データdata各点への距離を計算する
        # 距離はユークリッド距離の二乗, すなわちl2ノルムの二乗を計算する
        tmp = data - (x, y)
        distances = np.linalg.norm(tmp, axis=1)
        # 最も小さいスコア上位k点のラベルを参照
        supervisers_index = np.argsort(distances)[:k]
        # print(supervisers_index)
        supervisers = labels[supervisers_index]
        # print(supervisers)
        res = np.sum(supervisers)/ k 
        # if res > 0.5 then x_res in class1
        if res > 0.5:
            class1.append((x, y))
        elif res == 0.5:
            thresholds.append((x, y))
        else:
            class0.append((x, y))
        
class0, class1, thresholds = np.array(class0), np.array(class1), np.array(thresholds)
plt.scatter(values1[:,0], values1[:,1], color="r", marker="x", s=20)
plt.scatter(values2[:,0], values2[:,1], color="g", marker="x", s=20)
plt.scatter(class1[:,0], class1[:,1], color="r", marker="o", s=1, alpha=0.1)
plt.scatter(class0[:,0], class0[:,1], color="g", marker="o", s=1, alpha=0.1)
try:# 奇数の場合, 必ず多数決が成立するので閾値(0.5)とイコールになるものがないためエラー処理しておく
    plt.scatter(thresholds[:,0], thresholds[:,1], color="b", s=1, alpha=0.1)
except:
    pass

plt.title("./img/{}-NN methods".format(k))
plt.xlabel("x")
plt.ylabel("y")
plt.xlim(-9, 23)
plt.ylim(-7, 23)
plt.savefig("./img/{}-NN.png".format(k))
plt.show()

最小二乗法を実装する

予測モデルをつくるときに最も簡単な方法としては「最小二乗法による線形モデル」と「k近傍モデル」である.
この2つは統計学機械学習を学んでいない人でも割と思いつきそうな方法である.
線形モデルとはパラメータに対して線形なモデルという意味である.
例えば, y = ax + b という1次関数を中学で学んだ.
今, データxが観測されたときに, yを予測するというタスクを行う.
このときa(傾き), b(切片)の値によって予想するべき値yが異なってくる.
すなわちa, bが決定されれば全てのxの入力に対してyという出力ができるようになる.
このようなa, b をパラメータという.
これを多次元に拡張すると

y = w_0 + w_1x_1 + w_2x_2 + \ldots w_nx_n
これは

y = w_01 + w_1x_1 + w_2x_2 + \ldots w_px_p
と見て

y = \boldsymbol{x}^T \boldsymbol{w}
とベクトル表記で書くことができる.
これは, p+1 次元の一つのデータに対する予測の式なので, n個のデータを同時に扱う場合には

\boldsymbol{y} = \boldsymbol{X}^T \boldsymbol{w}
とする.  \boldsymbol{X} は(p+1, n)行列であり転置すると(n, p+1)行列, パラメータベクトル \boldsymbol{w}は(p+1)ベクトルである. ((p+1, 1)行列という表現もできる)
この線形モデルを, 最小二乗法によりフィットする. (予測と実際の誤差を最小にする)
 
min: RSS(\boldsymbol{w}) = (\boldsymbol{y} - \boldsymbol{X}\boldsymbol{w})^T(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{w})

\begin{align*}
RSS(\boldsymbol{w}) &= (\boldsymbol{y}^T-(\boldsymbol{X}\boldsymbol{w})^T)(\boldsymbol{y}-\boldsymbol{X}\boldsymbol{w})\\
 &= \boldsymbol{y}^T\boldsymbol{y}-\boldsymbol{y}^T\boldsymbol{X}\boldsymbol{w}-(\boldsymbol{X}\boldsymbol{w})^T\boldsymbol{y}+(\boldsymbol{X}\boldsymbol{w})^T(\boldsymbol{X}\boldsymbol{w})\\
 &= \boldsymbol{y}^T\boldsymbol{y}-(\boldsymbol{y}^T\boldsymbol{X})\boldsymbol{w}-\boldsymbol{w}^T(\boldsymbol{X}^T\boldsymbol{y})+\boldsymbol{w}^T(\boldsymbol{X}^T\boldsymbol{X})\boldsymbol{w}
\end{align*}
この式はパラメータ\boldsymbol{w}に関して二次式であるので最小値が存在する.
パラメータ\boldsymbol{w}微分して\boldsymbol{0}になるパラメータ\boldsymbol{w}を求める.

\begin{align*}
&\boldsymbol{0} - \frac{\partial (\boldsymbol{y}^T\boldsymbol{X})\boldsymbol{w}}{\partial \boldsymbol{w}} - \frac{\boldsymbol{w}^T(\boldsymbol{X}^T\boldsymbol{y})}{\partial \boldsymbol{w}} + \frac{\partial \boldsymbol{w}^T(\boldsymbol{X}^T\boldsymbol{X})\boldsymbol{w}}{\partial \boldsymbol{w}} = \boldsymbol{0}\\
&-(\boldsymbol{y}^T\boldsymbol{X})^T-(\boldsymbol{X}^T\boldsymbol{y}) + (\boldsymbol{X}^T\boldsymbol{X} + (\boldsymbol{X}^T\boldsymbol{X})^T)\boldsymbol{w} = \boldsymbol{0}\\
&-\boldsymbol{X}^T\boldsymbol{w}-\boldsymbol{X}^T\boldsymbol{y} + (\boldsymbol{X}^T\boldsymbol{X} + \boldsymbol{X}^T\boldsymbol{X})\boldsymbol{w} = \boldsymbol{0}\\
&-2\boldsymbol{X}^T\boldsymbol{y} + 2\boldsymbol{X}^T\boldsymbol{X}\boldsymbol{w} = \boldsymbol{0}\\
&2\boldsymbol{X}^T\boldsymbol{X}\boldsymbol{w} = 2\boldsymbol{X}^T\boldsymbol{y}\\
&\boldsymbol{w} = (\boldsymbol{X}^T\boldsymbol{X})^{-1}\boldsymbol{X}^T\boldsymbol{y}
\end{align*}


ベクトルに対する微分の以下の式は覚えておいたほうが良い.

\begin{align*}
\frac{\partial A^T \boldsymbol{x}}{\partial \boldsymbol{x}} = \frac{\partial \boldsymbol{x}^T A}{\partial \boldsymbol{x}} &= A\\
\frac{\partial \boldsymbol{x}^TA\boldsymbol{x}}{\partial \boldsymbol{x}} &= (A+A^T)\boldsymbol{x}\\
if\  A\  is\  symmetric\  matrix\\
&= 2A\boldsymbol{x}
\end{align*}

線形モデルの最小二乗法について, パラメータの解が

\begin{align*}
\boldsymbol{w} = (\boldsymbol{X}^T\boldsymbol{X})^{-1}\boldsymbol{X}^T\boldsymbol{y}
\end{align*}
で得られることが分かった.
これをPythonによって実装してみる. 今回は一次関数のパラメータa,b を求め直線フィッティングを行う.
まずデータを生成する. データ生成のアルゴリズムは以下の通りに行った.

  1. a, b, σを決定する
  2. [-10, 10]の範囲でデータxをランダムに生成する
  3. 決定したa, bからt=ax+bを計算する
  4. t=ax+b+εを計算する. ただしε~N(0, σ^2)
### 単純な線形モデルy = ax + b についてのパラメータa,b を求める問題におけるデータを生成する
### 
### a, b, σの値を決定する
### [-x_min, x_max]のデータxをランダムにN個用意 
### 各データに対して, N(ax+b, σ^2)に従うガウス分布からtを生成
### 

import numpy as np
from numpy.random import seed
import matplotlib.pyplot as plt

seed(0)

a, b, sigma = 2, 3, 3
N = 100
x_min, x_max = -10, 10

# データ生成
X = (x_max-x_min) * np.random.rand(N) + x_min
Epsiron = np.random.normal(0, sigma**2, N)# N(0, sigma^2)のN個の正規乱数
T = (a*X + b) + Epsiron

# データをファイルに出力
f = open("data00.csv", "w")
for (x, t) in zip(X, T):
    f.write("{}, {}\n".format(x,t))
f.close()

# データをプロット
plt.scatter(X, T)
plt.show()

以下の図のようになった.

f:id:umashika5555:20181221091859p:plain
データの様子
このデータから,

\begin{align*}
\boldsymbol{w} = (\boldsymbol{X}^T\boldsymbol{X})^{-1}\boldsymbol{X}^T\boldsymbol{y}
\end{align*}
に従ってパラメータを決定する.

import numpy as np
import matplotlib.pyplot as plt

# データの読み込み
name_data = "data00"
path_data = name_data + ".csv"
data = np.loadtxt(path_data,delimiter=",")
x, t = data[:,0], data[:,1]
p = x.shape[0]
ones = np.ones(p)
x_ = np.c_[ones, x]

# パラメータベクトルの計算
A = np.dot(x_.T, x_)
w = np.dot(np.dot(np.linalg.inv(A), x_.T), t)
print(w)

# データのプロット
plt.scatter(x, t)

# 回帰曲線の描画
b, a = w
xx = np.linspace(np.min(x)-2, np.max(x)+2, 100)
yy = a * xx + b
plt.plot(xx, yy, color="red")

plt.xlabel("x")
plt.ylabel("y")
plt.title("a=2, b=3, σ=2")
plt.savefig(name_data.format(a,b))
plt.show()

f:id:umashika5555:20181221092149p:plain
data00
上図のように実際に目で観ても綺麗にフィットできていることがわかる.


次回はこの線形モデルを更に発展させ, 基底関数, 正則化あたりをやっていきたい.

convert コマンド よく使う操作

画像のリサイズ

a.pngを指定した高さ/幅に同一比のまま縮尺拡大したb.pngを出力する.

# 幅に合わせる
convert -resize 640x a.png b.png
# 高さに合わせる
convert -resize x640 a.png b.png

a.pngという画像を640px * 640pxのb.pngに変換する.

convert -resize 640x640! a.png b.png

ディレクトリ内にある全ての画像に適応するならば

for filename in *.JPG; do convert -resize 640x640! ${filename} ${filename%.JPG}_640x640.jpg; done;

# ファイル名を変えずに実行したい場合
mogrify -resize 640x640! *.png;

ディレクトリresize_dirに変換後の画像を格納する場合

mkdir resize_dir
for filename in *.JPG; do convert -resize 640x640 $filename reseize_dir/${filename%.JPG}_640x640.JPG; done;

画像の形式変換

ディレクトリ内のJPGファイルをPNGファイルに一括変換する.

# ディレクトリ内のJPGファイルを探す
find ./ -name "*.jpg"
# ディレクトリ内のJPGファイルの個数を数える
find ./ -name "*.jpg" | wc -l
# JPGファイルをPNGに変換する
for filename in *.jpg;do convert "$filename" "${filename%.jpg}.png";done

【環境設定】ubuntu 18.04 LTSにslackを入れる

slackのデスクトップアプリケーションを, dpkgでインストールする方法
単純にslackのwebサイトからダウンロードして

$ sudo dpkg -i xxx.deb

とやったらlibappindicator1が無いみたいなエラーがなされたので,

$ sudo apt --fix-broken install
$ sudo apt install libindicator1
$ sudo dpkg -i xxx.deb

と行う.

【環境設定】ubuntu18.04のproxy関連設定

aptの設定

自宅でインストールしたubuntuをプロキシ環境下にあるネットワーク環境に持っていったとき, システム全体のプロキシ設定でブラウジングなどできたので, apt installなどできると思っていたが別に設定しないといけないらしい.
参考にしたのはこれ
usado.jp

$ sudo emacs /etc/environment

http_proxy="http://proxy-server:port/"
https_proxy="http://proxy-server:port/"

gitの設定

qiita.com
qiita.com

$git config --global http.proxy http://proxy.example.com:8080
$git config --global https.proxy http://proxy.example.com:8080

設定場所は.gitconfig

BitBucketの設定

22ポートが閉じられているので443ポートで通信を行う.

$ touch ~/.ssh/config
$ emacs ~/.ssh/config
Host bitbucket.org
    User git
    IdentityFile ~/.ssh/id_rsa
    HostName altssh.bitbucket.org
    Port 443
    ProxyCommand connect.exe -H hoge.proxy.jp:1080 %h %p

qiita.com
qiita.com
qiita.com
re-dzine.net