ラベル 統計計算 の投稿を表示しています。 すべての投稿を表示
ラベル 統計計算 の投稿を表示しています。 すべての投稿を表示

2023-02-10

MathJax を利用した数式表記の練習

最近、体重を少しずつ減らしていくため、朝は社バス、帰りは徒歩というのが通勤の習慣になってきました。歩いて帰ると一時間ぐらい掛かるのですが、道すがら今日あった出来事をあれこれ振り返っています。

そして今日は、データの前処理について釈然としないことがあって、それを考えながら歩いていました。結論はすぐに出たのですが、週末ということもあって、帰ってからあらためて確認しました。

釈然としなかったことというのは、例えば下記のようなデータを解析する際、

 

平均値がばらつきに比べて大きすぎるので、前処理として、下記のように定数(この例の場合は 95)で切るというものです。

 

※ 最近は Python ばかり使っていて R を使わなくなってしまったので、今回は敢えて R でプロットしています。というより R の方がこういうのは簡単にできます。

主成分分析を利用して解析をすることが多いので、これを聞いて、それでは分散の値は変わらない(= 解析精度は良くはならない)と思ったのですが、咄嗟にうまい言葉が出てきませんでした。いや、もしかすると、なにか重要な情報を聞き逃していて、こんな単純な話ではなかったのかもしれません。😅

とにかく、データに定数を足したり引いたりしても分散は不変であることを確認したくなりました。

ちょうど、ブログで数式表記をする手段を探しており、参考サイト [1] を参考に、本ブログでも MathJax を利用して数式表現をできるようにしたので、練習がてら利用してみました。

n 個のデータ x の平均値 μ は以下の式で算出できます。

\[ \mu = \frac{1}{n}\sum_{i=1}^n x_i \]

また分散 σ2 は、

\[ \sigma^2 = \frac{1}{n}\sum_{i=1}^n (x_i - \mu)^2 \]

となります。

次に、定数 d でデータ x を一律にカットした場合です。

先ほどと同じように平均値 μ1 を計算すると、

\[ \mu_1 = \frac{1}{n}\sum_{i=1}^n (x_i - d) = \frac{1}{n}\sum_{i=1}^n x_i - d = \mu - d \]

となって、平均値 μ1 も定数 d だけ減じた量になります。

このとき。分散 σ12 は、

\[ \sigma_1^2 = \frac{1}{n}\sum_{i=1}^n (x_i -d - \mu_1)^2 = \frac{1}{n}\sum_{i=1}^n (x_i -d - \mu + d)^2 = \frac{1}{n}\sum_{i=1}^n (x_i - \mu)^2 = \sigma^2 \]

と算出されます。

このように、データに定数を引こうが足そうが分散は不変です。つまり、例えば主成分分析のように分散を利用するデータ解析では、定数を引くことは有効なデータの前処理にはなっていないということになります。

久しぶりに LaTeX で記述した気分です。いや、数式の記述方法は同じですね。MathJax を利用した数式表記を本ブログで活用していきます。

【追記】スマホで見たら、数式表記が反映されていませんでした。😭

参考サイト

  1. Webの数式表現
  2. MathJax で利用可能な TeX コマンド(非公式)

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース



このエントリーをはてなブックマークに追加

2021-04-29

【備忘録】正規性の検定

このところ、データ集団が正規分布になっているかどうかを検定するために、Shapiro-Wilk や Anderson-Darling 検定を Python で実施する方法を調べていましたが、欲しかった情報がひとまず得られ、その上、信頼区間付きの Q-Q プロットも作成できました [1]。そこで、もともと作りたかった GUI サンプルを作成してみました。

最低限の機能を実装することが目的だったので、正規乱数を発生させてそのデータのプロットと正規性の検定をおこなっています。

以下に、PySide2 のサンプルを示しました(Qt6/PySide6 に Matplotlib のオブジェクトを埋め込むサポートがまだ利用できませんでした)。

qt_matplotlib_normality.py

Fedora 34 の GNOME デスクトップ環境で実行した例を示しました。

qt_matplotlib_normality.py の実行例

データ集団の正規性を調べるのに、検定だけでなく確率プロット、ボックスプロット、そしてヒストグラムを並べて確認したかったので、3つのプロットをひとつのイメージに収めようと四苦八苦しました。結局、グリッドで変態的なレイアウトの設定をしていますが、プロット上下の余白など、レイアウトにはまだ不満が残っています。😅

Qt 側で個々のプロットの比率を自分が望むように自在にコントロールできるのであれば、レイアウトのやり方にはまだまだ改善の余地がありそうです。

雑感

個人用途であれば R でササッと計算するだけですが、他の人と同じツールを共有して同じ目的で使いたい場合に困ってしまいます。統計計算用途で R は十分ポピュラーなツールですが、それでも、統計計算が主たる業務ではないエンジニアが、業務で統計計算をするのに R を使っているケースは稀です。

一方、Minitab や jmp といった市販の統計計算用ソフトウェアを企業で導入していれば、業務ではそれを利用することが望ましいです。しかし、使用資格やライセンス制限などの問題で、自分は利用できても相手が利用できない場合があります。さらに企業間でも、となれば、ソフトウェアが違っていたりして、同じやり方を共有することにはなかなか難しい課題があります。

それに、エンジニアリングにおいて汎用用途で統計計算用ソフトウェアを使うニーズはほとんど無く、多くは特定用途です。一部の機能しか使わなければ、汎用用途の統計計算ソフトウェアは(フローティングライセンスとしても)高価です。

いろいろな統計計算モジュールをあらかじめ用意しておいて、用途に併せて必要なモジュールを組み合わせて、必要なカスタマイズをしてパッケージにして、Windows 用のインストーラを作って配布すれば、多くの人と同じ目的のために使うツールを共有できます。Python を使えば、そういった使い方を実現できそうです。

参考サイト

  1. bitWalk's: Pingouin で Q-Q プロット [2021-04-25]

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2021-04-25

Pingouin で Q-Q プロット

Pingouin /pɛ̃.ɡwɛ̃/(フランス語でペンギンの意味)は、Python 3 で記述されたオープンソースの統計用パッケージで、主に Pandas と NumPy をベースにしています。分散分析、検定、相関、線形/ロジスティック回帰、ベイズ因子、多変量解析などなど、数多くの API が用意されています。

今回は、Q-Q プロットを作成するためにこのパッケージを利用します。

信頼区間付きの Q-Q プロット

Q-Q プロットを作成するだけならば、SciPy の probplot [1] で十分です。しかし、諸事情から信頼区間を表示されている Q-Q プロットを作成したかったので、対応しているパッケージを探したところ、Pingouin [2] を見つけたので、早速使ってみました。

下記の CSV ファイルのデータを読み込んでプロットしました。

データファイル data_norm.csv

以下に、PySide2 のサンプルを示しました(Qt6/PySide6 に Matplotlib のオブジェクトを埋め込むサポートがまだ利用できませんでした)。

qt_matplotlib_qqplot.py
Q-Q プロットの作成例

参考サイト

  1. scipy.stats.probplot — SciPy v1.6.2 Reference Guide
  2. Installation — pingouin 0.3.11 documentation
  3. Decide how to support qt6/gtk4 · Issue #19226 · matplotlib/matplotlib

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2021-04-24

正規性の検定 (SciPy) その2

SciPy は Python のための科学的ツールのオープンソース・ライブラリとして開発されています。SciPyは、NumPy をベースにしていて、統計、最適化、積分、線形代数、フーリエ変換、信号・イメージ処理、遺伝的アルゴリズム、ODE (常微分方程式) ソルバ、特殊関数、その他のモジュールを提供しています。

Wikipedia より引用、編集

本ブログの過去記事で、SciPy を利用して、データ集合の正規性を Shapiro-Wilk と Anderson-Darling の方法で検定しました [1]。やり方は判りましたが、Shapiro-Wilk 検定では p値が得られるのに対して、Anderson-Darling 検定では有意水準毎に判定するやり方で p値は算出されません。一方、R で同じ検定をしてみると、どちらの検定方法でも p値が得られます [2]。

Python/SciPy の Anderson-Darling 検定でも p値を算出できれば、運用上、Shapiro-Wilk 検定の出力と揃えられて便利です。そこでインターネット上で調べてみたところ、p値の算出方法が判りましたので、試してみました。

Anderson-Darling 検定で p値を計算

Anderson-Darling 検定で p値を計算する方法を調べてみると、下記の文献で紹介されている方法が広く使われているようです。

R.B. D'Augostino and M.A. Stephens, Eds., 1986, Goodness-of-Fit Techniques, Marcel Dekker

参考サイト [3] に、英文ですが、読みやすくまとめられてあります。ここで説明されている内容を参考にして、p値を計算しました。

今回は、R で検証する際に同じデータを扱えるように、下記の CSV ファイルのデータを読み込んで検定しました。

データファイル data_norm.csv

Python のサンプルは下記のとおりです。上記データを読み込んで、Shapiro-Wilk と Anderson-Darling 検定をします。

normality_test_2.py

以下に実行例を示しました。

[16.90967902 11.31394259 23.99799686 23.22058017 19.22506252 14.39123608
 23.66679924 18.0984158  15.13635741 14.06169534 25.50485539 21.30470429
 ...
 ...
 24.26806053 10.95348313 19.03384963 25.13764684 16.56651357 18.62142404
 35.02739838 11.8489582  17.36250313 26.87388481 21.2282162  23.02356501]

> Shapiro-Wilk test
W = 0.98509, p-value = 0.1058

> Anderson-Darling test
A = 0.36927, p-value = 0.4229

R で検証

同じ CSV ファイルを読み込んで、検定の結果が同じになることを確認しました。

normality_test_2.R

以下に実行例を示しました。

> library(nortest)
> 
> # sample dataset
> name.file <- "data_norm.csv"
> data <- read.csv(name.file)$x
> print(data)
  [1] 16.909679 11.313943 23.997997 23.220580 19.225063
  [6] 14.391236 23.666799 18.098416 15.136357 14.061695
 [11] 25.504855 21.304704 24.104321 18.417510 24.777343
...
...
[141] 19.033850 25.137647 16.566514 18.621424 35.027398
[146] 11.848958 17.362503 26.873885 21.228216 23.023565
> 
> # Shapiro-Wilk test
> result.shapiro <- shapiro.test(data)
> print(result.shapiro)

	Shapiro-Wilk normality test

data:  data
W = 0.98509, p-value = 0.1058

> 
> # Anderson-Darling test
> result.anderson <- ad.test(data)
> print(result.anderson)

	Anderson-Darling normality test

data:  data
A = 0.36927, p-value = 0.4229

> 

次こそは GUI を利用して、Q-Q プロットやヒストグラムと一緒にしたサンプルを作成したいと考えています。

参考サイト

  1. bitWalk's: 正規性の検定 (SciPy) [2021-04-21]
  2. bitWalk's: 正規性の検定 (R) [2021-04-22]
  3. Anderson-Darling Test for Normality | BPI Consulting [June 2011]

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2021-04-22

正規性の検定 (R)

データの集合が正規分布とみなせるかの検定を Python/SciPy で計算してみましたが、Shapiro-Wilk と Anderson-Darling で出力の形式が異なっていたことが気になったので [1] 、同じことを R でもやってみました。

normality_test.R

以下に実行例を示しました。

> library(nortest)
> 
> # sample dataset
> data <- rnorm(150, mean = 20, sd = 5)
> print(data)
  [1] 12.056125 12.501325 17.523703 15.480088 17.297640 20.316994 21.197035 20.667794 17.005183
 [10] 28.084337 21.317987 20.472167 17.468762 16.851357 27.206106 11.313712 18.710486 17.259417
...
...
[145] 16.199152 22.915103 20.473811 27.863051 23.514593 24.095631
> 
> # Shapiro-Wilk test
> result <- shapiro.test(data)
> print(result)

	Shapiro-Wilk normality test

data:  data
W = 0.99663, p-value = 0.9831

> 
> # Anderson-Darling test
> result <- ad.test(data)
> print(result)

	Anderson-Darling normality test

data:  data
A = 0.23304, p-value = 0.7945

R の nortest パッケージを使って、Anderson-Darling 検定をおこなうと、出力は Shapiro-Wilk 検定と同じく p-value で出力されます。このように、どちらも p-value で検定結果を得られる方が、運用上は都合が良いので、SciPy でも p-value で検定結果を得られるように変更します(次回)。

参考サイト

  1. bitWalk's: 正規性の検定 (SciPy) [2021-04-21]
  2. CRAN - Package nortest

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2021-04-21

正規性の検定 (SciPy)

SciPy は Python のための科学的ツールのオープンソース・ライブラリとして開発されています。SciPyは、NumPy をベースにしていて、統計、最適化、積分、線形代数、フーリエ変換、信号・イメージ処理、遺伝的アルゴリズム、ODE (常微分方程式) ソルバ、特殊関数、その他のモジュールを提供しています。

Wikipedia より引用、編集

データの集合が正規分布とみなせるかの検定を Python でできるようにする必要があったので、参考サイト [1] を参考にして、Shapiro-Wilk および Anderson-Darling の正規性検定のサンプルを作ってみました。

normality_test.py

以下に実行例を示しました。

[24.61705496 19.56390871 19.13798944 17.16842011 12.8670519  21.24411178
 24.89046892 16.53493345 20.54015744 22.8150989  15.60100487 24.40446872
 ...
 ...
 19.64959102 14.48918507 22.90403538 18.97650011 23.17654791 21.12734951
  9.98367097 16.94422025 29.93326303 24.63846928 19.07507917 10.12488745]

> Shapiro-Wilk test
stat = 0.986, p-value = 0.137
Probably Gaussian at 5% level of significance

> Anderson-Darling test
stat = 0.463
Probably Gaussian : 0.562 critical at 15% level of significance
Probably Gaussian : 0.640 critical at 10% level of significance
Probably Gaussian : 0.767 critical at  5% level of significance
Probably Gaussian : 0.895 critical at  2% level of significance
Probably Gaussian : 1.065 critical at  1% level of significance

次は GUI を利用して、Q-Q プロットやヒストグラムと一緒にしたサンプルを作成したいと考えています。

参考サイト

  1. 10 Normality Tests-Python (2020) | Towards Data Science [2020-09-18]
  2. scipy.stats.shapiro — SciPy v1.6.2 Reference Guide
  3. scipy.stats.anderson — SciPy v1.6.2 Reference Guide

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ Linuxへ
にほんブログ村

2019-04-20

独立成分分析を使ってみる

ICA, Independent Component Analysis(独立成分分析)は、多変量の信号を複数の加法的な成分に分離するための計算手法です。

Wikipedia より抜粋、編集

大量の多変量データを解析するとき、主成分分析をよく使っています。多次元データをばらつきの大きさ順に直交座標に変換していく主成分分析の方法は直観的に理解しやすく、また、取り組むべき解析対象の優先付けをし易くしてくれるので、大変妥当な手法だと思っています。

それでも、もっと良い方法が無いか、あるいは改善できるところがないか検討を重ねているのですが、「独立成分分析」という語を目にした時に?が思い浮かびました。(線型)独立って直交していることでないのかと勘違いをしていたのです。たまたま読んでいたサイト [1] の筆者も最初はそう考えたようでした。

直交関係にある複数のベクトルは線型独立の関係にありますが、逆は必ずしも成り立たないのです。が、その説明は省略します。

[1] のサイトで紹介されていた「独立成分分析」の R パッケージ fastICA [2] を使ってみました。

三つのデモプログラム

まずは、マニュアルの 4 ページに紹介されているデモサンプルを試してみました。

最初の例は、二次元の一様乱数を線形変換したサンプルを主成分分析と独立成分分析を適用した例です。

Example 1: un-mixing two mixed independent uniforms 
library(fastICA)

#---------------------------------------------------
#Example 1: un-mixing two mixed independent uniforms
#---------------------------------------------------
S <- matrix(runif(10000), 5000, 2)
A <- matrix(c(1, 1, -1, 3), 2, 2, byrow = TRUE)
X <- S %*% A
a <- fastICA(X, 2, alg.typ = "parallel", fun = "logcosh", alpha = 1,
             method = "C", row.norm = FALSE, maxit = 200,
             tol = 0.0001, verbose = TRUE)
par(mfrow = c(1, 3))
plot(a$X, main = "Pre-processed data")
plot(a$X %*% a$K, main = "PCA components")
plot(a$S, main = "ICA components")

runif で一様乱数を 10,000 個生成して、それを 5,000 行 × 2 列の行列にして、2 × 2 の行列を掛けて線型変換(回転、拡大)したデータをサンプルとして使っています。

Example 1 の実行例

左が元のデータ、真ん中が主成分分析で変換した結果、そして右が独立成分分析で変換した結果です。真ん中の主成分分析では、直交成分である PC1 と PC2 に変換したからと言って、データがその軸に沿って並ぶとは限らないことが判ります。

右の独立成分分析では、元のデータ S の分布の成分と同等な成分に変換しています。

 

二番目のサンプルは、いわゆるブラインド信号源分離をする例です。

Example 2: un-mixing two independent signals 
library(fastICA)

#--------------------------------------------
#Example 2: un-mixing two independent signals
#--------------------------------------------
S <- cbind(sin((1:1000)/20), rep((((1:200)-100)/100), 5))
A <- matrix(c(0.291, 0.6557, -0.5439, 0.5572), 2, 2)
X <- S %*% A
a <- fastICA(X, 2, alg.typ = "parallel", fun = "logcosh", alpha = 1,
             method = "R", row.norm = FALSE, maxit = 200,
             tol = 0.0001, verbose = TRUE)
par(mfcol = c(2, 3))
plot(1:1000, S[,1 ], type = "l", main = "Original Signals", xlab = "", ylab = "")
plot(1:1000, S[,2 ], type = "l", xlab = "", ylab = "")
plot(1:1000, X[,1 ], type = "l", main = "Mixed Signals", xlab = "", ylab = "")
plot(1:1000, X[,2 ], type = "l", xlab = "", ylab = "")
plot(1:1000, a$S[,1 ], type = "l", main = "ICA source estimates", xlab = "", ylab = "")
plot(1:1000, a$S[, 2], type = "l", xlab = "", ylab = "")

オリジナルの信号は、正弦波と三角波のような波形を持った二次元の信号 S です(下左)。これに 2 x 2 行列 A を乗じて、それぞれの成分を混ぜて線形変換します。これを X として各成分をプロットしたのが下の真ん中です。

Example 2 の実行例

X に対して独立成分分析して信号を分離したのが上右のプロットです。符号は逆になっていますが、元の信号に分離されているのが確認できます。

 

三番目のサンプルは、混合した二変数の正規分布を独立成分分析して射影追跡した例です。射影追跡とは, 多次元データの特徴的な構造を、低次元空間に線形射影することによって探るデータ解析手法です [3] 。

Example 3: using FastICA to perform projection pursuit on a mixture of bivariate normal distributions 
library(fastICA)

#-----------------------------------------------------------
#Example 3: using FastICA to perform projection pursuit on a
# mixture of bivariate normal distributions
#-----------------------------------------------------------
if(require(MASS)){
  x <- mvrnorm(n = 1000, mu = c(0, 0), Sigma = matrix(c(10, 3, 3, 1), 2, 2))
  x1 <- mvrnorm(n = 1000, mu = c(-1, 2), Sigma = matrix(c(10, 3, 3, 1), 2, 2))
  X <- rbind(x, x1)
  a <- fastICA(X, 2, alg.typ = "deflation", fun = "logcosh", alpha = 1,
  method = "R", row.norm = FALSE, maxit = 200,
  tol = 0.0001, verbose = TRUE)
  par(mfrow = c(1, 3))
  plot(a$X, main = "Pre-processed data")
  plot(a$X %*% a$K, main = "PCA components")
  plot(a$S, main = "ICA components")
}

二つの異る二次元の正規分布群 x と x1 を合わせたデータ(下左)に対して主成分分析(下の真ん中)と独立成分分析(下右)を行っています。

Example 3 の実行例

比較している内容は判るのですが、どうせなら二つの群を色分けして確認したかったので、少し手を加ました。

Example 3 (b): 
library(fastICA)
library(MASS)

plot.xy <- function(m, title, labels) {
  colnames(m) <- labels
  df = data.frame(m)
  df$Group <- sapply(strsplit(as.character(row.names(df)), "_"), "[[", 1)
  plot(df[, 1:2], main = title, type="n")

  colors <- data.frame(Group = unique(df$Group))
  colors$Color = c("#FF4000", "#0040FF")
  for(g in unique(df$Group)) {
    points(df[df$Group == g, 1:2], col = colors[colors$Group == g, "Color"], cex = 0.25)
  }
}

n.max <- 1000
x1 <- mvrnorm(n = n.max, mu = c(0, 0), Sigma = matrix(c(10, 3, 3, 1), 2, 2))
row.names(x1) <- paste("A", c(1:n.max), sep = "_")
x2 <- mvrnorm(n = n.max, mu = c(2, -2), Sigma = matrix(c(10, 3, 3, 1), 2, 2))
row.names(x2) <- paste("B", c(1:n.max), sep = "_")

X <- rbind(x1, x2)
colnames(X) = c("x1", "x2")
a <- fastICA(X, 2, alg.typ = "deflation", fun = "logcosh", alpha = 1,
             method = "R", row.norm = FALSE, maxit = 200,
             tol = 0.0001, verbose = TRUE)

b <- prcomp(X)

par(mfrow = c(1, 3))
plot.xy(X, "Raw data", c("x", "y"))
#plot.xy(a$X %*% a$K, "PCA components", c("PC1", "PC2"))
plot.xy(b$x, "PCA components", c("PC1", "PC2"))
plot.xy(a$S, "ICA components", c("IC1", "IC2"))
Example 3 (b) の実行例

二種類のデータを混合して、主成分分析と独立成分分析をして比較する限り、独立成分分析の方がデータ群の差異を説明するための解釈の助けになるように思いました。もっと次元が多い複雑な系でどうなるか評価して、取り組んでいるデータ解析に適用できるかどうか検討したいと思います。

参考 サイト

  1. RでPCAとICA
  2. CRAN - Package fastICA
  3. 射影追跡:その考え方と実際

 

ブログランキング・にほんブログ村へにほんブログ村

2019-01-12

歩留まりと二項分布

WBT とは Web Based Training の略です。PC のブラウザ上、ビデオなどでトレーニングが受けられるシステムです。

今回は WBT で出題された理解度確認問題の内容について愚痴ります。😅

自分が勤務している会社は米国に本社がある外資系だからなのか WBT が充実しています。新年になると日本企業と違って四月を待たずに直ちに期が変わります。今年もたくさんの WBT のトレーニングが割り当てられました。その中に、新しく統計コースが出来ていたので、珍しさも手伝って聴講してみました。このコースの最初は二項分布とポアソン分布のトレーニングでした。

トレーニングビデオは英語ですが、資料の説明を聴いているだけなので楽でした。しかし最後に、確認テストが 10 問あって、しかも実際に計算をしなければならない内容でした。

設問

例えば以下の設問です。これがなんとも変な問題だったのです。

Calculate the probability that a unit process with 98% yield will have exactly 97 good wafers out of 100 wafers run.

日本語に直せば下記のようになるでしょうか。

歩留まり 98% の単一工程で、ウェハーを100 枚処理して 97 枚が良品になる確率を計算しなさい。

勤務している会社は半導体製造装置を製造・販売および関連のサービスを提供する会社です。そのため、社員教育には半導体デバイス製造にあてはめた事例が多くあります。そしてこれはウェハー歩留まりの問題なのですが、なんともしっくりきません。🤔

ここは二項分布とポアソン分布の理解度確認問題ですので、出題意図を汲み取れば期待されている値を算出することはできます。

R では次のように計算します。

> dbinom(x = 97, size = 100, prob = 0.98)
[1] 0.1822759

これは、成功確率が 0.98 である試行を 100 回実施したときに、97 回成功する確率を計算したものです。もちろん、これで正解です。🤗

さらに 0 〜 100 回成功する確率を全て計算して棒グラフにすると下記のような二項分布になります。

> barplot(dbinom(0:100, 100, 0.98), names = 0:100, ylab = "Probability", col = "magenta", cex.names = 0.75, cex.axis = 0.75, cex.lab = 0.75)
成功確率が 0.98 である試行を 100 回実施したときに、成功する回数の確率分布

ちなみに、97 回以上(100 回まで)成功する確率は、

> sum(dbinom(x = 97:100, size = 100, prob = 0.98))
[1] 0.8589616

あるいは、

> 1 - pbinom(q = 97 - 1, size = 100, prob = 0.98)
[1] 0.8589616

となります。

しっくりこない原因

確率の問題と割り切ればそれほど変に感じない問題が、確率を「歩留まり」に置き換えた途端にしっくりこなくなりました。「たかが社内教育の理解度確認問題なのだから割りきって考えなさい。」という声がどこからか聞こえてきそうですが、半導体製造の歩留まりを改善するために長年取り組んできた経験から、ここは譲れません。しっくりとこない原因を考えたくなります。

しっくりとこない原因を解くヒントは、トレーニングビデオに示されていた参考文献 [1] の Figure 1 にありました。

Figure 1 のタイトルは

Probabilities for number of wafers surviving from a lot of 25 wafers, assuming a line yield of 90%, calculated using the binomial distribution.

とあります。日本語に直せば、

ライン歩留まりを 90% と仮定したとき、1 ロット(ウェハー 25 枚)が処理されて、最後まで残るウェハー枚数の確率を二項分布で計算した結果

とでもなりましょうか。

昨今のNAND フラッシュメモリーやプロセッサーなど半導体デバイスの製造工程は何百工程とあり、大きく、フロントエンドライン(ウェハー上のデバイス加工)とバックエンドライン(チップのパッケージ加工)に分かれています。ラインの工程内検査で規格外れがあれば、原則リジェクト(廃棄の意味で、ボツなどともいいます)となります。ライン歩留まり 90% ということは、25 枚ウェハーを 1 ロットとしてフロントエンドラインへ投入すると、ラインアウト(全工程完了)時には 25 × 0.90 = 22.5 ~ 23 枚ぐらいに減ってしまうということです。歩留まりが低いとは思いますが、不自然な話ではありません。

この事例のライン歩留まりを、社内の WBT では、製造装置メーカーだからと単一工程の歩留まりに書き換えたのです。ここに無理があったようです。単一工程の歩留まりをウェハーの枚数という単位で、良・不良を論じようとするところに出題者の経験の浅さが現れています。統計の専門家であっても半導体製造は素人です。そもそも歩留まり 98% の単一工程なんて最悪です、とても量産には使えません。

なーんて、いろいろ文句を言いながらも二項分布の復習がしっかりできたのでした。😄

参考 サイト

  1. D. S. Boning, J. Stefani, S.W. Bulfer ″Statistical Methods for Semiconductor Manufacturing, Encyclopedia of Electrical Engineering”, J. G. Webster, Ed., Wiley, to appear, Feb. 1999

 

ブログランキング・にほんブログ村へ
にほんブログ村

2014-01-04

AlgDesign: 実験計画/解析用ツールについて考える (2)

AlgDesign は、前のブログの記事でも触れたように、最適計画である D-, I-, A-optimal の各デザイン(計画)を作成する R の拡張パッケージですが、Fedora の RPM では提供されていなかったので、既に Fedora で提供されている R の拡張パッケージの RPM の(SPEC ファイルの)「作り」を参考にして作ってみました。x64_64 (64bit) のパッケージとソースパッケージを SourceForge.jp の下記のサイトにアップしてあります。32bit 用パッケージは追って作成してアップします。

最適計画の詳しい紹介は、サンプルを使っておいおいして行く予定です。


追記

x86 (32bit) 用に R-AlgDesign-1.1.7-1.fc20.i686.rpm もビルドして上記のサイトにアップしました。

2010-10-31

統計解析ツール ~ 歩き始め ~

一元配置の分散分析ができたからといって、全て見通しが立ったわけではありません。しかし、自分が納得できる統計解析ツール、特に実験計画法の為の解析ツールを作りたいという欲求を抑えることができず、少しずつ GUI の部分を作り始めています。

GUI では、かゆいところに手が届くような操作性と柔軟性を実現したいので、じっくり時間をかけて作り込む予定です。若いころに BBN RS/1 というツールを VAX Station 上で使っていましたが、実験計画用のモジュール (Discover とか Explorer という名前でした)の使い心地が忘れられません。今なら GUI でもっともっと使い易く出来るはずです。



実は、むかしむかしも同じようなツールを自分で作りたいと考えていました。その時は応答曲面法 (RSM) を全面に出していましたが、行列計算の量が多く、手許の PC で実用的な処理速度を得られず、挫折してしまいました。

そもそも Tcl/Tk を使い続けている理由も、こういうツールを自分で作りたいという欲求があるからです。かつての人気はすっかり無くなってしまいましたが、Tcl/Tk の開発は止まっていません。Tktable も BLT (RBC) も利用できます。Eclipse などの統合開発環境が利用出来るので、ソフトウェアの開発が格段に楽になってきてもいます。

今回は、オーソドックスに一元配置の分散分析からはじめて、直交表までをカバーして、その次に中心複合計画やコンピュータの計算応力を駆使する最適計画など応答曲面法までを目指したいと考えています。

さて、完成はいつになるやら…。まずはアルファ版を公開することを目指します。とりあえずは決意表明をしておこう。

参考/引用文献

[1] 岩崎 学 著, 統計的データ解析入門 実験計画法 (東京図書)ISBN4-489-00725-6
 

2010-10-10

ちょっと分散分析(2)

p 値の計算をするためにガンマ関数やらベータ関数を計算するルーチンを C で作成し、Tcl の拡張パッケージ上の拡張された算術関数として利用できるようにして、その上で P 値を計算するルーチンを作ってはみましたが、計算した値が合いません。きっと自分の理解不足によるもののと考え、とりあえず諦めてしまいました(泣)。

そのかわり近似計算をしているサイトをいろいろ探し、サイト[1] を参考にして P 値を与えるルーチンを追加しました。悔しいのでもっと勉強して、自分で納得できるルーチンを作成していきます。

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh8.6 "$0" "$@"
# 分散分析
# $Id: anova_1way.tcl,v 1.6 2010/10/10 05:15:34 bitwalk Exp bitwalk $

# サンプルデータ1
set a [list {3.42  3.84  3.96  3.76}]
set b [list {3.17  3.63  3.47  3.44  3.39}]
set c [list {3.64  3.72  3.91}]

# サンプルデータ2
#set a [list {25 30 20 32}]
#set b [list {30 33 29 40 36}]
#set c [list {32 39 35 41 44}]

# データ
set data [list $a $b $c]

# -----------------------------------------------------------------------------
#  クラス anova
# -----------------------------------------------------------------------------
oo::class create anova {
    constructor {a} {
        my variable x way

        # データリスト
        set x $a
        # 分散分析の対象フラグのリセット
        set way ""
    }
    # -------------------------------------------------------------------------
    # 一元配置
    # -------------------------------------------------------------------------
    method oneway {} {
        my variable x way
        my variable n k
        my variable SSb SSw SSt
        my variable df_b df_w df_t
        my variable MSb MSw
        my variable F p

        # Sum of Squared Deviations
        # SSt (TOTAL)
        set x_simple [my list_simple $x]
        set n [llength $x_simple]
        set x_mean [my mean $x_simple $n]
        set SSt [my var $x_simple $x_mean]
        # SSb (BETWEEN GROUPS)
        set k [llength $x]
        set SSb 0
        for {set i 0} {$i < $k} {incr i} {
            set x_b($i) [my list_simple [lindex $x $i]]
            set n_b($i) [llength $x_b($i)]
            set x_mean_b($i) [my mean $x_b($i) $n_b($i)]
            set SSb [expr $SSb + $n_b($i) \
                * ($x_mean_b($i) - $x_mean) \
                * ($x_mean_b($i) - $x_mean)]           
        }
        # SSw (WITHIN GROUPS)
        # set SSw [expr $SSt - $SSb]
        set SSw 0
        for {set i 0} {$i < $k} {incr i} {
            set x_w($i) [my list_simple [lindex $x $i]]
            set n_w($i) [llength $x_w($i)]
            set x_mean_w($i) [my mean $x_w($i) $n_w($i)]
            set SSw [expr $SSw + [my var $x_w($i) $x_mean_w($i)]]
        }
        # Degree of Freedom
        set df_b [expr $k - 1]
        set df_w [expr $n - $k]
        set df_t [expr $n - 1]
        # Mean Square
        set MSb [expr $SSb / $df_b]
        set MSw [expr $SSw / $df_w]
        # F value, the ratio of the two variance estimates
        set F [expr $MSb / $MSw]
        set p [my f_pval $F $df_b $df_w]
        # flag
        set way "One Way"
        return 1
     }
    # -------------------------------------------------------------------------
    # result
    # 結果の表示
    # -------------------------------------------------------------------------
    method result {} {
        my variable way

        switch $way {
            "One Way" {
                my result_1way
            }
            default {
                puts "No result yet!"
            }
        }
    }
    # -------------------------------------------------------------------------
    # result_1way
    # 結果の表示(一元配置)
    # -------------------------------------------------------------------------
    method result_1way {} {
        my variable x
        my variable n k
        my variable SSb SSw SSt
        my variable df_b df_w df_t
        my variable MSb MSw
        my variable F p

        puts "ANOVA (1way)"
        puts "Source        SS       df       MS    F val    P Val"
        puts -nonewline "Between"
        puts -nonewline [format " %8.3f" $SSb]
        puts -nonewline [format " %8d" $df_b]
        puts -nonewline [format " %8.3f" $MSb]
        puts -nonewline [format " %8.3f" $F]
        puts -nonewline [format " %8.6f" $p]
        if {$p < 0.001} {
            puts " ***"
        } elseif {$p < 0.01} {
            puts " **"
        } elseif {$p < 0.05} {
            puts " *"
        } else {
            puts ""
        }
        puts -nonewline "Within "
        puts -nonewline [format " %8.3f" $SSw]
        puts -nonewline [format " %8d" $df_w]
        puts -nonewline [format " %8.3f" $MSw]
        puts ""
        puts -nonewline "Total  "
        puts -nonewline [format " %8.3f" $SSt]
        puts -nonewline [format " %8d" $df_t]
        puts ""
    }
    # -------------------------------------------------------------------------
    # mean
    # 平均値の計算
    # -------------------------------------------------------------------------
    method mean {xList num} {
        set sum [my sum $xList]
        return [expr $sum / $num]
    }
    # -------------------------------------------------------------------------
    # sum
    # 合計の計算
    # -------------------------------------------------------------------------
    method sum {xList} {
        set total 0.0
        foreach x $xList {
            set total [expr $total + $x]
       }
        return $total
    }
    # -------------------------------------------------------------------------
    # var
    # 分散の計算
    # -------------------------------------------------------------------------
    method var {xList xMean} {
        set var 0.0
        foreach x $xList {
            set var [expr $var + ($x - $xMean) * ($x - $xMean)]
        }
        return $var
    }
    # -------------------------------------------------------------------------
    # f_pval
    # P値(F分布の上側確率の算出)
    # -------------------------------------------------------------------------
    method f_pval {f df1 df2} {
        set m2pi 0.636619772367581343076
        set m_pi 3.14159265358979323846
        set i1 [expr 2 - ($df1%2)]
        set i2 [expr 2 - ($df2%2)]
        set w [expr $df2/($df2 + $df1*$f)]
        set y [expr 1.0 - $w]
        set p [expr sqrt($w)]
        set s [expr sqrt($y)]

        if {[expr 2*$i1 - $i2] == 0} {
            set p [expr 1.0 - $s]
            set c [$s*$w/2.0]
        } elseif {[expr 2*$i1 - $i2] == 1} {
            set c [expr $s*$p/$m_pi]
            set p [expr 1.0 - atan2($s, $p) * $m2pi]
        } elseif {[expr 2*$i1 - $i2] == 2} {
            set p $w
            set c [expr $w*$y]
        } else {
            set c [expr $y*$p/2.0]
        }
        for {set i2 $i2} {$df2 > $i2} {incr i2 2} {
            set p [expr $p - 2.0/$i2*$c]
            set c [expr $c*$w*($i1 + $i2)/$i2]
        }
        for {set i1 $i1} {$df1 > $i1} {incr i1 2} {
            set p [expr $p + 2.0/$i1*$c]
            set c [expr $c*$y*($i1 + $i2)/$i1]
        }
        return [expr ($p < 0.0 && abs($p) < 1e-10) ? 0.0 : $p]
    }
    # -------------------------------------------------------------------------
    # list_simple
    # 入れ子になっているリストをシンプルなリストに変換
    # -------------------------------------------------------------------------
    method list_simple {xList} {
        regsub -all {[\{\}]} $xList {} foo
        regsub -all {\s{2,}} $foo { } baa
        return $baa
    }
}
# -----------------------------------------------------------------------------
#  メイン
# -----------------------------------------------------------------------------
set obj [anova new $data]
if {[$obj oneway]} {
    $obj result
} else {
    puts "failed"
}
# ---
# END PROGRAM
実行例を以下に示しました。
$ ./anova_1way.tcl
ANOVA (1way)
Source        SS       df       MS    F val    P Val
Between    0.318        2    0.159    4.615 0.041749 *
Within     0.310        9    0.034
Total      0.628       11

参考サイト

[1] 統計関数の確率計算
[2] The Free Statistics Calculators Website - Home (算出値の検証用)
 

追記

この記事を書いた後、なぜ用意した関数でうまくできなかったのかが突然判ってしまいました。長年 Tcl を使っているのに、Tcl 特有の計算の落とし穴にすっかりハマっていたのです。

以下は、用意していた規格化された不完全ベータ関数 betai を使って書き直したメソッド f_pval です。Tcl では、整数÷整数の結果は自動的に整数になってしまいます。浮動小数の結果が必要な場合は、分母分子のどちらか一方を浮動小数の値に明示にしておく必要があります。
    # -------------------------------------------------------------------------
    # f_pval
    # P値(F分布の上側確率の算出)
    # -------------------------------------------------------------------------
    method f_pval {f df1 df2} {
        set x [expr $df1 * $f / ($df2 + $df1*$f)]
        return [expr 1 - betai($df1/2.0, $df2/2.0, $x)]
    }
実行例を以下に示しましたが、上記と同じ結果が得られています。
$ ./anova_1way.tcl
ANOVA (1way)
Source        SS       df       MS    F val    P Val
Between    0.318        2    0.159    4.615 0.041749 *
Within     0.310        9    0.034
Total      0.628       11

今のところ規格化された不完全ベータ関数 betai の算出には、下記の GSL の関数を利用しています。
double gsl_sf_beta_inc (double a, double b, double x)
以下のようなルーチンを使って Tcl の拡張パッケージを作成しています。
/*****************************************************************************
 * int func_betai
 * 規格化された不完全ベータ関数の処理部
 *
 * Tcl 側のコマンド
 *   expr betai($a, $b, $x)
 *****************************************************************************/
int
func_betai (ClientData clientData, Tcl_Interp * interp,
        Tcl_Value * args, Tcl_Value * resultPtr)
{
  double a, b, x;

  a = args->doubleValue;
  args++;
  b = args->doubleValue;
  args++;
  x = args->doubleValue;

  /* 計算結果 */
  resultPtr->type = TCL_DOUBLE;
  resultPtr->doubleValue = gsl_sf_beta_inc (a, b, x);

  return TCL_OK;
}
ただ、GSL の配布ライセンスは GPLv3 (GNU General Public License) に従っているので、扱い難いと感じています。計算方法の検証ができたので、他に BSD などの配布ライセンスで良いライブラリがあれば乗り換えようと思っています。オープンソースを推進したい者としては矛盾した考えですが、しかたがありません。