忘れては思い出したいポアソン分布
スマホで文字打ち込んでいるのでLaTeXに出来ませんがまぁご愛嬌。
ポアソン分布の確率関数
Pr(X=k) = exp(-θ)θ^k/k! ただしk は0以上の整数
ポアソン分布の期待値
E[X] = θ
ポアソン分布の期待値の導出
overはΣの添字が走る範囲です。またexp(θ)=Σθ^h/h! over h≧0
を用います。
E[X] = Σkexp(-θ)θ^k/k! over k≧0 = Σkexp(-θ)θ^k/k! over k≧1 = exp(-θ)Σθ^k/(k-1)! over k≧1 = θexp(-θ)Σθ^(k-1)/(k-1)! over k-1≧0 = θexp(-θ)Σθ^h/h! over h≧0 = θexp(-θ)exp(θ) = θ
Rで階層的クラスタリング
あけましておめでとうございます今年も統計学とRの勉強を継続します。
ということで、いつもの通り(?)Yuyaさんの動画にて階層的クラスタリングを見たので、Rを使ってクラスタリングしてみます。
コード
# データの準備 dd <- data.frame( ht = c(2,1,2,4,6) ,sp = c(1,4,6,1,5) ) row.names(dd) <- c('A','B','C','D','E') # 距離行列 dd.dst <- dist(dd) # 階層的クラスターの作成 hc.comp <- hclust(dd.dst,method = "complete") # 最遠隣法 hc.sing <- hclust(dd.dst,method = "single") # 最近隣法 hc.wd <- hclust(dd.dst,method = "ward.D2") # ウォード法 # グラフの作図 dev.off() par(mfrow = c(3,1) ) par(family = "HiraKakuProN-W3") for(i in 1:3){ plot(hc.comp,main = "最遠隣法") plot(hc.sing,main = "最近隣法") plot(hc.wd, main = "ウォード法") }
グラフ
参考
データサイエンス100本ノックをRでやってみた
1日1~2時間×1週間ぐらいで終えました。
感想
- tidyverseに感謝
- 日付の計算はstrptimeよりlubridate使った方が簡単
- inner_joinはbyを指定しないときnatural joinになって便利
- 正規表現を使う問題はstr_subやstr_detectを用いても代替可能(問題の趣旨に反するが・・・。)
- slice_*系でデータ取り出し、が失敗することもあるのでそんな時はheadを利用
つまずいた問題たち
供養と復習を兼ねて書いておきます。どの問題も実用的なのでスラスラと書けるようになりたいですね。
R-029
R-029: レシート明細データフレーム(df_receipt)に対し、店舗コード(store_cd)ごとに商品コード(product_cd)の最頻値を求めよ。
最頻値ってどうやって出すのっていうか最頻値出す関数無くない?と一時停止した問題です。inner_joinを駆使してなんとかひねり出した自分の答えに対してAnswerの解法はエレガントでした。勉強も兼ねてrecodeしたものが以下です。
df_receipt %>% group_by(store_cd, product_cd) %>% summarise(cnt = n(), .groups = 'drop') %>% group_by(store_cd) %>% filter( cnt == max(cnt) ) # Ans の n == n %>% max() は、 n == max(n) と同じ。
R-058
R-058: 顧客データフレーム(df_customer)の性別コード(gender_cd)をダミー変数化し、顧客ID(customer_id)とともに抽出せよ。結果は10件表示させれば良い。
ダミー変数化って要するにどうなるんだっけ?と思考停止した問題です。変数の取りうる値の範囲が事前に分かっていればdecodeすれば良いのだけど、そうではない時にはAnswerにある通りdummyVars()を使うそうです。
# ダミー変数化がわからなかったのでAnsを参照した。 # すると、gender_cd = {0,1,9} を gender_cd0,gender_cd1,gender_cd9と3つの変数に分離することらしい。 # 横持ち形式ということかなぁ。 # で、dummyVars()というのは{caret}パッケージの関数であるもよう。 # if_else で書けるといえば書けるのだが、 # よく考えると「取りうる値」が事前に分かっていないとコーディングできないね。 # ということで、「取りうる値」が分からない場合はdummyVars()を使うしかないわね。 df_customer %>% mutate( gender_cd0 = if_else(gender_cd == 0,1,0) ,gender_cd1 = if_else(gender_cd == 1,1,0) ,gender_cd9 = if_else(gender_cd == 9,1,0) ) %>% select(customer_id, starts_with("gender")) %>% slice(1:10)
R-087
R-087: 顧客データフレーム(df_customer)では、異なる店舗での申込みなどにより同一顧客が複数登録されている。名前(customer_name)と郵便番号(postal_cd)が同じ顧客は同一顧客とみなし、1顧客1レコードとなるように名寄せした名寄顧客データフレーム(df_customer_u)を作成せよ。ただし、同一顧客に対しては売上金額合計が最も高いものを残すものとし、売上金額合計が同一もしくは売上実績の無い顧客については顧客ID(customer_id)の番号が小さいものを残すこととする。
SQLだったらwindow関数とpartition by でうまくいくのになぁとモヤモヤした問題です。Answerはとてもエレガントでdistinct関数をうまく利用した解法です。自分で出した解答は確かに問題文の題意をそのまま愚直に書き下した感がありエレガントではないでした。一番悔しかった問題です。
df_receipt %>% group_by(customer_id) %>% summarise(sum_amount = sum(amount) , .groups = 'drop' ) -> dfr df_customer %>% left_join(dfr) %>% mutate(sum_amount = replace_na(sum_amount,0) ) %>% group_by(customer_name, postal_cd) %>% mutate( rank_amount = min_rank(desc(sum_amount)) ,rank_cust = min_rank(customer_id) ,num_amount = n_distinct(sum_amount) # 売上金額合計の種類の数 ) %>% filter( ( (num_amount > 1) & (rank_amount == 1) ) | ( (num_amount == 1)&( rank_cust == 1 ) ) ) %>% select(-rank_amount,-rank_cust,-num_amount) -> df_customer_u2
「 平均点以上の人の平均点」を求めるための条件付き確率密度関数が確率密度関数であることを確認する
多変量正規分布の条件付き期待値・条件付き分散
やること
『統計学』東京図書 p.147 練習問題 問5.1の[2]、多変量正規分布の条件付き期待値・条件付き分散を解きます。
問題
が平均ベクトル、分散共分散行列が正値対称行列
の時、X = xおよびZ = zを与えた下でのYの
- 条件付き期待値
- 条件付き分散
を求めよ。
解法
※ mathjaxだと面倒なので画像で行きます。
確率ベクトルX: p×1行列 が 平均ベクトルμ: p×1行列, 分散共分散行列Σ: p×p行列を用いた N(μ, Σ)に従っている。そして『統計学』東京図書 p.45 にあるように
と区分けすることを考える。
この時、『統計学』東京図書 p.46の定理2.2.6により、
が成り立つ。
これを踏まえると、今回の問題はと順番を入れ替えて
と区分けすることができる。(赤線の区分けと添字の対応は以下の通り。)
ということで、E[Y | X = x, Z = z]を求めると、
となる。
一方、V[Y | X = x, Z = z]を求めると、
となる。
なお今回の3変量正規分布の条件付期待値と分散は、変数2つが固定されるので一次元正規分布となる。なので、ベクトル・行列の演算結果はスカラーになる。
参考
- http://users.stat.umn.edu/~helwig/notes/norm-Notes.pdf のp.34あたりから。
- 多変量正規分布における条件付き確率の式と意味 - 具体例で学ぶ数学
- Deriving the conditional distributions of a multivariate normal distribution - Cross Validated
- self study - Conditional Probability Distribution of Multivariate Gaussian - Cross Validated
- Covariance matrix - Wikipedia
sweep関数の使い方を忘れがちなので自分へのメモ
まとめ
sweep関数の
- MARGIN = 1の時は
- i 行目のそれぞれの値に対してSTATSの i番目の値をFUNと二項演算する
- MARGIN = 2の時は
- j 列目のそれぞれの値に対してSTATSの j番目の値をFUNと二項演算する
お気持ち
行平均の引き算のお気持ち
- sweepで1行目の行平均を引き算したいとき、1行目の各要素から引き算する値はスカラーな行平均。
- sweepで2行目の行平均を引き算したいとき、2行目の各要素から引き算する値はスカラーな行平均。
- ...
となる。sweep(mat, MARGIN = 1, ...)の時、1行目ベクトルからSTATSベクトルを減算し、2行目ベクトルからSTATSベクトルを減算し・・・とはならないので要注意。 忘れたら行平均の減算、列平均の減算を思い出そう。
確認コード
MARGIN = 1の場合
> # 行列を生成し > (m <- matrix(c(3,1,4,1,5,9,2,6,5,3,5,9),ncol=4)) [,1] [,2] [,3] [,4] [1,] 3 1 2 3 [2,] 1 5 6 5 [3,] 4 9 5 9 > # 行平均を確認 > rowMeans(m) [1] 2.25 4.25 6.75 > # 行平均を各行から引く > sweep(m, MARGIN = 1, STATS = rowMeans(m), FUN = "-") [,1] [,2] [,3] [,4] [1,] 0.75 -1.25 -0.25 0.75 [2,] -3.25 0.75 1.75 0.75 [3,] -2.75 2.25 -1.75 2.25 >
MARGIN = 2 の場合
> # 列平均を確認 > colMeans(m) [1] 2.666667 5.000000 4.333333 5.666667 > # 列平均を各列から引く > sweep(m, MARGIN = 2, STATS = colMeans(m), FUN = "-") [,1] [,2] [,3] [,4] [1,] 0.3333333 -4 -2.3333333 -2.6666667 [2,] -1.6666667 0 1.6666667 -0.6666667 [3,] 1.3333333 4 0.6666667 3.3333333 >
となる。
雑だけどirisを機械学習する
まえがき
Data Science: Machine Learningを受講しています。今までのR BasicsやVisualizationに比べて課題が多くてなかなか進まないです。8月中には完了させたいですね。
本題ですが、今回は「雑だけどirisを機械学習する」ということで、とりあえずcaret使って機械学習を動かしてみようと思います。理論が分からないと機械学習なんて触っちゃダメだろーと思っていましたが、まぁまずはtryですよ。
ソースコード
# テストデータで10行 # 訓練データはそれ以外 ind <- sample(iris %>% nrow(), size = 10, replace = FALSE) iris_test <- iris[ind, ] iris_train <- iris[-ind,] # trainのメソッドを欲張りセットでこしらえる methods <- list("lda","qda","knn","rf","nnet") # Accuracyを出す accuracies <- map_dbl(methods, function(me){ trained <- train(Species ~ ., data = iris_train, method = me ) predicted <- predict(trained, iris_test) confusionMatrix(data = predicted, reference = iris_test$Species)$overall["Accuracy"] }) # ベクトルに名前をつけて names(accuracies) <- methods # 表示 accuracies
結果
2,3回ぶん回しましたがだいたい8~9割ぐらいのAccuracyが出ました。
> accuracies lda qda knn rf nnet 1.0 1.0 0.8 0.8 0.9
2次元正規分布のデータから2通りの方法で回帰直線を引く
タイトルの通りです。
lm
で単回帰直線- 平均と分散共分散からE[Y|X=x] *1を計算
の2通りで回帰直線を引きます。
コード
library(MASS) library(scales) options(digits = 3) # 平均 mx <- 10 my <- 22 # 分散 Sx <- sqrt(9) Sy <- sqrt(16) Sxy <- sqrt(9.6) # サンプルサイズ n <- 10000 # 平均ベクトル M <- c(mx, my) # 分散共分散行列 Sig <- c(Sx^2,Sxy,Sxy,Sy^2) %>% matrix(2,2) z <- MASS::mvrnorm(n, mu = M, Sigma = Sig ) # dev.off() # 散布図プロット plot(z[,2] ~ z[,1], xlab = "x", ylab = "y",col = c(alpha('orange', 0.2)) ) # 単回帰直線(青) lm.z <- lm(z[,2] ~ z[,1]) coef(lm.z) abline(lm.z, col ="blue", lwd = 2, lty = 2) # E[Y|X = x]で直線を引く(赤) list("Intercept" = my - mx * (Sxy/(Sx*Sy))*(Sy/Sx), "Slope" = (Sxy/(Sx*Sy))*(Sy/Sx) ) %>% unlist() abline(my - mx * (Sxy/(Sx*Sy))*(Sy/Sx), (Sxy/(Sx*Sy))*(Sy/Sx), col="red", lwd = 3, lty = 2)
結果
だいたい一致しました。青が単回帰直線、赤がE[Y|X = x]です。
- lmでの係数
> coef(lm.z) (Intercept) z[, 1] 18.552 0.344
- E[Y|X = x]での係数
> list("Intercept" = my - mx * (Sxy/(Sx*Sy))*(Sy/Sx), "Slope" = (Sxy/(Sx*Sy))*(Sy/Sx) ) %>% unlist() Intercept Slope 18.557 0.344
参考
改訂版 日本統計学会公式認定 統計検定2級対応 統計学基礎 のp.86 (2.9.18)
*1:母数から計算しているのでおそらく母回帰直線、と思われる。