ひらめの日常

日常のメモをつらつらと

dotfilesの管理/運用方法をまとめる

※現在はこちらの運用方法に変えています.

hiramekun.hatenablog.com

目標

様々な設定ファイルをgithubで管理運用するのは、以下のような目標があります。

  1. 他のpcに乗り換えた時に環境構築を簡単に行いたい
  2. 設定ファイルのバックアップを取っておきたい
  3. 他の人に自分の設定ファイルを共有したい

しかし、普通に管理しようとすると、github上に設定ファイル分のレポジトリを作成することになります。そこで、今回はdotfilesというレポジトリ一個で全ての設定ファイルを管理する方法をまとめておきます。

dotfilesをレポジトリ管理

管理用ディレクトリ作成

ルートディレクトリに、管理したいファイルをまとめておくディレクトリを作成します。

$ mkdir dotfiles

そこに、管理したいファイルを全て入れます。私の場合は、zsh/bash/fish, vim, karabiner, bettertouchtool, ide用のideavimrcなどを管理しています。

$ mv ~/.config/fish ~/dotfiles/fish
$ mv ~/.bashrc ~/dotfiles/.bashrc
$ mv ~/.zshrc ~/dotfiles/.zshrc
etc...

シンボリックリンクを貼る

このままでは、本来ファイルがあるべき場所に設定ファイルがないので、mvしたファイルの設定が読み込まれないことになります。
なので、シンボリックリンクを貼って、本来ファイルがあるべき場所にaliasを設定します。

$ ln -sf ~/dotfiles/fish ~/.config/fish
$ ln -sf ~/dotfiles/.bashrc ~/.bashrc
$ ln -sf ~/dotfiles/.zshrc ~/.zshrc

githubにpush

こちらの記事などを参考にして、githubにdotfilesという名前のレポジトリを作成→commit→pushという流れでgithubに登録します。
qiita.com

自分のdotfilesはこちらにあります。

github.com

Rでガウス最尤推定(フィッシャーの線形判別分析)

全ての実装はこちらにあります。
7/5:リンク先更新しました。

github.com

ガウス最尤推定

流れ

ガウスモデルに標本が従っていると仮定します。  

そのガウスモデルから計算した対数事後確率が最も高いクラスに、標本を振り分けると考えます。
そのために、ガウスモデルのパラメータ推定→事後確率計算という流れを経ることになります。

定義

ガウスモデルとは正規分布のことです。
こちらの記事でも紹介していますが、定義は以下のようになっています。

hiramekun.hatenablog.com

{ \displaystyle
f(x) = \frac{1}{(2\pi)^{\frac{D}{2}}|\Sigma|^{\frac{1}{2}}}\exp(-\frac{1}{2}(x-\mu)^{T}\Sigma^{-1}(x-\mu))
}

{D}:次元
{x}:D次元ベクトル
{\Sigma}:xの分散共分散行列
{\mu}:D次元の分散ベクトル

最尤推定

最尤推定自体に関する説明は省きます。
各カテゴリごとに異なるガウスモデルを仮定した場合(つまり、 {y_i} ごとに異なる平均や分散の値を持っているということです)、上記のガウスモデルの最尤推定量は次のように計算されます。
 {\displaystyle
\hat{\mu_y} = \frac{1}{n_y}\sum_{i:y_i = y}x_i
}

 {\displaystyle
\hat{\Sigma_y} = \frac{1}{n_y}\sum_{i:y_i = y}(x_i - \hat{\mu_y})(x_i - \hat{\mu_y})^{T}
}

{\sum_{i:y_i = y}}{y_i = y} を満たす  {i} に関する和

対数事後確率

ベイズの定理と事後確率自体に関する説明は省きます。
対数事後確率は、計算すると以下のようになります。
 {\displaystyle
\log{\hat{p}(y|x)} = -\frac{1}{2}(x-\hat{\mu_y})^{T}{\hat{\Sigma_y}}^{-1}(x-\hat{\mu_y}) - \frac{1}{2}\log{|\hat{\Sigma_y}|} + \log{n_y} + C
}

やや複雑な形になるので、今回は各カテゴリの分散共分散行列が等しい時を考えます(つまり、 {y_i} の分散は等しく、同じ散らばりを持った分布であるとします)。

その時、対数事後確率は以下のように簡略化できます。
 {\displaystyle
\log{\hat{p}(y|x)} = \hat{\mu_y}^{T}{\hat{\Sigma_y}}^{-1}x - \frac{1}{2}\hat{\mu_y}^{T}{\hat{\Sigma_y}}^{-1}\hat{\mu_y} + \log{n_y} + C^{'}
}

フィッシャーの線形判別分析

この、分散共分散行列が共通の時、決定境界は超平面になります。
この場合をフィッシャーの線形判別分析と呼びます。

Rで手書き文字を分類する

事後確率計算

trainデータの分散共分散行列と平均を受け取って、testデータに対する事後確率を計算します。

calc_possibility = function(mean, invs, test_label) {
  mean %*% invs %*% test_label - (mean %*% invs %*% t(mean) / 2)[1][1]
}

結果

2クラス分類

まずは1と2を分類するタスクを実装しました。

正確には、2のtestデータセットを与え、1と判別するか2と判別するかを測定しました。
すると、testデータセット200に対して精度が99%と出ました。

[1] 0.99

そこで間違えて分類している2枚の画像はこんな感じ。
f:id:thescript1210:20180506051123p:plain

多クラス分類

今度は0~9までの数字全てに対して一度に分類を行ってみました。

それぞれの数字に対する精度を出力しました。

[1] "Accuracy of 1: 0.995000"
[1] "Accuracy of 2: 0.845000"
[1] "Accuracy of 3: 0.905000"
[1] "Accuracy of 4: 0.910000"
[1] "Accuracy of 5: 0.815000"
[1] "Accuracy of 6: 0.925000"
[1] "Accuracy of 7: 0.905000"
[1] "Accuracy of 8: 0.825000"
[1] "Accuracy of 9: 0.910000"
[1] "Accuracy of 0: 0.960000"

平均は約89%で、もちろんdeepには及ばないものの、簡単な実装でそこそこの精度が出ることがわかりました。

[1] 0.8995

RでKLダイバージェンスを描画する

今回はRでKLダイバージェンスを描画します。
KLダイバージェンスとは、カルバック・ライブラー情報量の略称。2つの確率分布の差異を測る距離的尺度として捉えることができます。

と言われても実感がわかないと思うので、実際に描画して感覚を掴んでいきたいと思います。
実装はこちらにあります。
7/5:リンク先更新しました。

github.com

定義

まずはエントロピーの説明をし、その上にあるKLダイバージェンスの定義を述べます。

エントロピー

連続関数のエントロピーは、情報量の期待値という定義なので次のように表せます。

\displaystyle
H(X) = -\int_{-\infty}^{\infty}p(x)\ln{p(x)} dx
直感的には、次に得られる情報量がどれだけの価値がある可能性があるかを示している数値になります。
(情報量とは、確率的に低いものを得た時に情報量を多く得たと判断するものです。)

KLダイバージェンス

今、正しい確率分布  p(x) と、その確率分布を近似したモデルである  q(x) があるとします。
この時に、 q(x) によって真の値を推測するために追加で必要な情報量の平均として定義されます。
具体的には、次のように表されます。「 q(x)エントロピー-  p(x)エントロピー」と捉えるとわかりやすいかもしれません。
{\displaystyle
KL(p||q) = -\int_{-\infty}^{\infty}p(x)\ln{\frac{q(x)}{p(x)}}dx
}

描画してみる

対象とするモデル

以下のように、平均mean2=2, 標準偏差sd2=2の正規分布を対象とします。

X = seq(-10, 10, length = n)
Y4 = dnorm(X, mean = mean2, sd = sd2)
plot(X,
Y4,
type = "l",
col = "blue")

f:id:thescript1210:20180501005147p:plain

KLダイバージェンスの図示

左の図は平均値を変化させた時のKLダイバージェンスの値。平均値が対象モデルと同じ2の時にKLダイバージェンスは最小値を取ることがわかります。
右の図は標準偏差を変化させた時のKLダイバージェンスの値。標準偏差が対象モデルと同じ2の時にKLダイバージェンスは最小値を取ることがわかります。

これらのことから、KLダイバージェンスは、モデル間のパラメータを用いて、モデル間の距離を表していると捉えることができますね。

f_kl_divergence = function(m1, m2, sd1, sd2) {
  log(sd1 / sd2) + (sd2 ^ 2 + (m1 - m2) ^ 2) / (2 * sd1 ^ 2) - 1 / 2
}
y_mean = c()
x = seq(-4, 4, length = 100)
for (i in x) {
y_mean = append(y_mean, f_kl_divergence(i, mean2, sd2, sd2))
}

y_sd = c()
x2 = seq(1, 3, length = 100)
for (i in x2) {
   y_sd = append(y_sd, f_kl_divergence(mean2, mean2, i, sd2))
}

layout(matrix(1:2, ncol=2))
plot(x, y_mean, type="l")
plot(x2, y_sd, type="l")

f:id:thescript1210:20180501005336p:plain

(番外編)Rのライブラリを用いてみる

Rには、KLダイバージェンスにしたがって乱数を生成し、元モデルのパラメータを推定する関数があります。
その関数であるKL.divergence()を用いて乱数を発生させ、それをプロットしました。

するとその結果は先ほどplotした理論値に近いグラフを描画することができました。

library(FNN)
set.seed(100)

kl_mean = c()
Y1 =  rnorm(n * 10, mean = mean2, sd = sd2)
for (i in seq(-4, 4, length = 100)) {
  Y2 = rnorm(n * 10, mean = i, sd = sd2)
  divs = KL.divergence(Y1, Y2, k = 2)
  kl_mean = append(kl_mean, mean(divs))
}

kl_sd = c()
for (i in seq(1, 3, length = 100)) {
  Y3 = rnorm(n * 10, mean = mean2, sd = i)
  divs2 = KL.divergence(Y1, Y3, k = 2)
  kl_sd = append(kl_sd, mean(divs2))
}

layout(matrix(1:2, ncol=2))
plot(seq(-4, 4, length = 100), kl_mean, type="l")
plot(seq(1, 3, length = 100), kl_sd, type="l")

f:id:thescript1210:20180501005418p:plain

Rで2次元正規分布を描画する

自分の実装はgithubにあります。

github.com

D次元正規分布

1次元正規分布はよく統計学とかでも出て来ますが、今回は2次元正規分布確率密度関数を描画したいと思います。

定義

{ \displaystyle
f(x) = \frac{1}{(2\pi)^{\frac{D}{2}}|\Sigma|^{\frac{1}{2}}}\exp(-\frac{1}{2}(x-\mu)^{T}\Sigma^{-1}(x-\mu))
}

{D}:次元
{x}:D次元ベクトル
{\Sigma}:xの分散共分散行列
{\mu}:D次元の分散ベクトル

以後D=2の場合を扱っていきます。

散布図

とりあえず確率密度関数を描画する前に、2次元正規分布に従う散布図をプロットしてみます。

library(mvtnorm)
sigma = matrix(c(2, 0.8, 0.8, 2), ncol = 2)
rand = rmvnorm(n = 1000, mean = c(0, 0), sigma)
x1 = rand[, 1]
x2 = rand[, 2]
plot(x1, x2)

mvtnormが多次元正規分布を描画するときには必要になります。
流れとしては、

  1. sigmaという分散共分散行列の定義
  2. rmvnormの引数に、平均と分散共分散行列を渡す
  3. rmvnormは渡された次元数を元に、多次元正規分布に従った乱数を生成

f:id:thescript1210:20180425000159p:plain

確率密度関数

それでは、確率密度関数{f(x)}を描画していきます。

x1 = seq(-3, 3, length = 50)
x2 = x1
f = function(x1, x2) {
  dmvnorm(matrix(c(x1, x2), ncol = 2), mean = c(0, 0), sigma = sigma)
}
z = outer(x1, x2, f)
z[is.na(z)] = 1
op = par(bg = "white")
persp(x1, x2, z, theta = 30, phi = 30, expand = 0.5, col = "orange")  

今回は、dmvnormという関数を用います。

  1. x1, x2に軸用の値を代入
  2. dmvnormの第一引数に軸ラベル、そして平均と分散共分散行列を渡す
  3. dmvnormは渡された次元数を元に、多次元正規分布を生成
  4. 多次元正規分布の出力をzに代入しperspでグラフ描画

こんな感じになります。
f:id:thescript1210:20180425000954p:plain

参考

こちらのサイトなどを参考にさせていただきました。
http://cse.naro.affrc.go.jp/minaka/R/R-binormal.html

Shift-JISのエクセルファイルの文字化けを直す

何回も同じことを調べていて覚えないので備忘録的に残します。
ファイルの文字コードを調べる

>> nkf -g hoge.csv
Shift-JIS

ファイルの文字コードをUTF-BOMに変更する
UTFの文字コードにすると、エクセルは適切に読み込んでくれないので、UTF-BOMに変換する必要があるようです。

>> nkf --overwrite --oc=UTF-8-BOM hoge.csv
>> nkf -g hoge.csv
UTF-8

メモリの種類を10分でまとめる(ROM, RAM)

◎ROM

Read Only Mmory
その名の通り基本動作は読み出しのみ。
次のようにROMには様々な種類があります。

○マスクROM

メモリLSI(データを記憶に特化した回路のこと)の設計時に内容が決まる。ユーザーによる消去・書き込みは不可能。

○PROM ROM

Programmable ROM
ユーザーによる消去・書き込みが可能。

ヒューズROM

ユーザーが一度だけ書き込みが可能。以後の消去・書き込みは不可能。

EPROM

Erasable PROM
ユーザーによる消去・書き込みが何度でも可能。

  • UVEPROM(紫外線で消去・書き込み)
  • EEPROM(電気で消去・書き込み)
  • フラッシュメモリ(電気で消去・書き込み。ブロック単位で高速に処理可能)

◎RAM

Random Access Mmory
基本動作は読み出しと書き込み。
次のようにRAMにも様々な種類があります。

SRAM

Static RAM
セルはフリップフロップで、リフレッシュ(後述)不要。
高速で、レジスタファイルやキャッシュメモリなどに用いられる。

DRAM

Dynamic RAM
セルはコンデンサ
コンデンサなので、放置しておくと電荷が流れてしまう。そこで、ある時間ごとに電荷の状態を確認して再び電荷を加え直したりしなければならない。このことをリフレッシュという。

高速モードDRAM

連続する列アクセスを高速化。

SDRAM

Static DRAM
クロック同期とアクセスのオーバーラップによる高速化。

RDRAM

Rambus DRAM
データ幅の縮小と直列接続による高速化。


こちらのpdfファイルを参考にしました
http://www.mtl.t.u-tokyo.ac.jp/~sakai/hard/hard2.pdf

コマンドラインからpickleファイルの中身確認

Pythonファイルでは

pythonではpickle.dump()で書き込み、pickle.load()で読み込みます。

# 書き込み
with open("hoge.pkl", mode="wb") as f:
    pickle.dump({"hoge":"fuga"}, f)

# 読み込み
with open("hoge.pkl", mode="rb") as f:
    hoge = pickle.load(f)

コマンドラインでは

しかし、これでは手軽にpickleファイルの中身を確認することができません。
pythonファイルを別に作ってそれを毎回指定して実行するのも面倒な気がします。

すると、コマンドラインからでも次のようにすれば読み込めるとのこと。

$ python -m pickle hoge.pkl
{hoge: fuga}

これだけ。

こちらの記事を参考にさせていただきました。
qiita.com