기본 콘텐츠로 건너뛰기

벡터와 행렬에 관련된 그림들

[data analysis] 베이즈정리 (Bayes theorem)

베이즈정리 (Bayes theorem)

관련된 내용

예 1)

표 1은 사무실 lamp을 생산하는 공장 A, B, C의 생산율과 불량품율에 대한 자료입니다.

표 1 공장별 생산에 대한 자료
공장 Product D, P(D|Product)
A 0.35 0.015
B 0.35 0.01
C 0.3 0.02
Product: 생산율, D: 불량률

생산된 불량품이 각 공장에서 생산되었을 확률?

공장 C에서 생산되었을 확률은 식1과 같이 나타낼 수 있습니다.

$$P(C\,|\, D) = \frac{P(C\, ∩\, D)}{P(D)}$$(식 1)

표 1에서 공장 C에서의 불량품율에 대한 정보를 사용할 수 있습니다. 즉, P(D|C)은 식 2와 같이 계산할 수 있습니다.

$$ P(D\, |\, C) = \frac{P(D\, ∩ \,C)}{P(C)}$$(식 2)

교집합은 교환법칙이 성립하므로 P(D ∩ C) = P(C ∩ D)로 치환할 수 있습니다(식 3).

\begin{align} P(C \,∩\, D)& = P(D\,|\,C)P(C)\\&= 0.020·0.3\\&=0.006\end{align} (식 3)

P(D)는 각 공장에서의 불량품 확률의 합과 같습니다(식 4).

\begin{align}P(D)&= P(D\,∩\,A) + P(D\,∩\,B) + P(D\,∩\,C)\\ &= P(D\,|\,A)P(A) + P(D\,|\,B)P(B) +P(D\,|\,C)P(C)\\ &= 0.015·0.35 + 0.01·0.35 + 0.02·0.30\\ &= 0.01475\end{align}(식 4)
A=np.array([0.35, 0.015])
B=np.array([0.35, 0.01])
C=np.array([0.3, 0.02])
data=pd.DataFrame(np.c_[A, B, C], index=["P(factory)","P(D|factory)"], columns=["A","B","C"]).T
data 
P(factory)P(D|factory)
A 0.35 0.015
B 0.35 0.010
C0.30 0.020
dat=data.values
D_tot=np.sum(np.prod(dat, axis=1))
print(D_tot)
0.01475

위 결과를 적용하면 불량품 D가 공장 C에서 생산되었을 확률 즉, 식 2의 계산결과는 다음과 같습니다.

DC=dat[2,0]*dat[2, 1]/D_tot
round(DC, 3)
0.407

P(D|C)와 같은 방법으로 공장 A, B에서 불량품을 생산할 확률을 계산해 봅니다(식 5).

\begin{align} P(A\, | \,D) &= \frac{P(A\, ∩ \,D)}{P(D)}\\ & = \frac{P(D\,|\,A)P(A)}{P(D)}\\P(B\, | \,D) &=\frac{P(B\, ∩ \,D)}{P(D)}\\ &= \frac{P(D\,|\,BB)}{P(D)}\end{align}(식 5)
AC=dat[0,0]*dat[0, 1]/D_tot
round(AC, 3)
0.356
BC=dat[1,0]*dat[1, 1]/D_tot
round(BC, 3)
0.237

위 예에서 P(A), P(B), P(C)는 부가적인 정보를 계산하기 전에 얻을 수 있는 확률로서 사전확률 (prior probability)라고 합니다. 이 사전확률들을 기반으로 계산할 수 있는 조건부확률 P(A|D), P(B|D), P(C|D)를 사후확률 (posterior probability)라고 합니다. 즉, 사후확률은 사전확률로부터 불량품률과 같은 부가적인 정보를 획득한 후에 어떤 사건의 조건부 확률을 계산할 수 있는 확률을 의미합니다. 위의 과정을 일반화한 정리를 베이즈정리 (Bayes theorem)이라 합니다.

[베이즈정리 (Bayes theorem)]

표본 공간 S에서 여러 부분공간들(B1, B2, · · · , Bk)이 독립인 경우 식 6과 같이 나타낼 수 있습니다.

$$S = B_1\, ∪ B_2\, ∪ … ∪B_k$$ (식 6)

표본 공간의 모든 사건이 독립이므로 표본 공간과 연관된 사건 A의 총 발생은 식 7과 같이 A를 조건으로 하는 모든 발생들의 합과 같습니다.

\begin{align}A&=(A\,\cap\,B_1)\,\cup\,(A\,\cap\,B_2)\,\cup\,\cdots\,\cup\,(A\,\cap\,B_k)\\ P(A)&=P(A\,\cap\,B_1)\,\cup\,P(A\,\cap\,B_2)\,\cup\,\cdots\,\cup\,P(A\,\cap\,B_k)\\ &=\sum^k_{i=1}P(A\,\cap\,B_i)\\&=\sum^k_{i=1}P(A\,\vert\,B_i)P(B_i)\end{align} (식 7)

위의 관계로 부터 Bk의 사후확률은 식 8이 같이 계산됩니다.

\begin{align}P(B_k\,\vert\,A)&=\frac{P(B_k\,\cap\,A)}{P(A)}\\&= \frac{P(A\,\vert\,B_k)P(B_k)}{\sum^k_{i=1}P(A\,\vert\, B_i)P(B_i)} \end{align} (식 8)

예 2)

공구함에 포함되어 있는 40개의 퓨즈들 중에 5개는 완전한 불량품(D)이고 10개는 1시간 동안 지속되는 부분불량품(pD), 나머지 25개는 정상품(G)입니다. 한 개가 선택되는 경우 완전한 불량품이 아닌 상품을 선택할 확률?

퓨즈를 불량품과 불량(D)이 아닌 제품(ND)로 분류한다면 G는 ND에 포함되어 있습니다. 그러므로 문제의 조건부 확률 P(G|ND)는 식 9와 같이 계산됩니다.

\begin{align}P(G\, ∩ \,ND) &= P(G)\\ P(G \,|\, ND) &= \frac{P(G \,∩ \,ND)}{P(ND)}\\&=\frac{P(G)}{P(ND)}\end{align} (식 9)
PD=5/40
Ppd=10/40
PG=25/40
PND=PG+Ppd
condPG_ND=PG/PND
print(round(condPG_ND, 3))
0.714

예 3)

A에게 두 아이가 있는데 가장 어린 아들과 함께 어떤 모임에 참석해야 합니다. 그가 그 모임에 참석할 수 있다면 그의 가족에 두 아들들만이 포함될 확률?

  • 표본공간 S={(b,b), (b,g), (g, b), (g,g)}, b:boy, g: girl
  • 참석 조건에 부합하는 모든 사건 A={(b,b), (g, b)}
  • 대상이 되는 사건 B={(b,b)}

위 조건을 근거로 P(B|A)는 식 9와 같이 계산됩니다.

\begin{align}P(B\, | \,A) &= \frac{P(B\, ∩ \,A)}{P(A)}\\&=\frac{P(B)}{P(A)}\end{align}(식 9)
S=4
PA=2/S
PB=1/S
PB_A=PB/PA
PB_A
0.5

예 4)

다음 자료는 일정기간 kospi(kos)와 kodaq(kq)의 종가(Closing price)들에 대한 2일간의 변화에 대한 것으로 증가를 1, 하락을 0으로 목록화 한 것입니다. 두 종목의 가격 변동은 독립일까요?

kospi: [1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1]
kosdaq: [1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1]

이 자료는 파이썬 패키지 FinanceDataReader를 사용하여 호출한 일일 자료를 조정한 것으로 다음 코드를 사용하여 작성한 것입니다.

import FinanceDataReader as fdr
import pandas as pd
st=pd.Timestamp(2023, 2, 20) #(1)
et=pd.Timestamp(2023, 3,20)  
kos=fdr.DataReader('KS11', st, et)['Close'] #(2)
kq=fdr.DataReader('KQ11', st, et)['Close']
kos1=kos.pct_change()
kos1=kos1.replace(0, method='ffill')  #(3)
kos1=kos1.dropna() #(4)
kq1=kq.pct_change() #(5)
kq1=kq1.replace(0, method="ffill")
kq1=kq1.dropna()
kos2=pd.cut(kos1, bins=[-1, 0, 1],labels=[0, 1])  #(6)
kq2=pd.cut(kq1, bins=[-1, 0, 1],labels=[0, 1])
data= pd.concat([kos2, kq2], axis=1)  # (7)
data.index=range(1, len(kos2)+1)
data
Close Closel
1 1 1
2 0 0
3 1 1
16 1 1
17 0 1
18 1 1

위 코드에 사용한 코드는 다음과 같습니다.

코드 번호함수/메소드내용
(1) Timesptamp()날짜 데이터를 생성하는 것으로 수치형을 날짜형으로 변환
(2) DataReader() 호출한 자료는 DataFrame 형식으로 열이름은 'Open','High','Low','Close', 'Volume', 'Change'등을 포함합니다. 이중에 'Close'만을 선택
(3) .replace()특정한 값을 지정한 값으로 변환. 자료 중 0을 앞 행의 값으로 변환
(4) .dropna() 자료 중 결측치 값을 포함한 행을 제거
(5) .pct_change()같은 열의 2개의 행간의 변화율을 계산
(6) .cut()연속변수의 구간을 설정하여 categorical 변수로 전환
(7) .concat()두 DataFrame 객체를 결합

두 집단의 독립여부는 교집합을 고려하여 판단할 수 있습니다. 즉, 독립사건들의 교집합에 대한 확률은 두 확률의 곱으로 계산됩니다. 두 집단이 독립이라면 식 10과 같이 그 두 확률의 곱 결과는 조건부 확률에 의한 결과와 같을 것입니다.

P(kos = 1) ∩ P(kq = 1) = P(kos = 1|kq = 1)P(kq = 1)(식 10)
→ 독립인 경우 P(kos = 1) ∩ P(kq = 1) = P(kos = 1) * P(kq = 1)

위 표에 대한 교차표를 작성해 봅니다. 이는 pd.crosstab() 함수를 사용합니다.

  • pd.crosstab(index, columns, rownames=None, colnames=None, margins=False, margins_name= 'All', dropna= True, normalize=False)
    • 두 개 (또는 그 이상)의 요인(factor)에 대한 교차표를 작성합니다.
    • index, columns : 각각 행과 열에서 그룹화 할 값
    • rownames, colnames: 표의 행과 열의 이름
    • margins=True → 행합과 열합을 마지막 행과 열에 첨부, 그 행과 열의 이름은 margins_name으로 지정할 수 있음
    • dropna=True이면 NA 값은 삭제. 행과 열의 수가 일치하지 않을 경우는 False를 선택 즉, 행과 열의 수가 일치하지 않을 경우 True이면 행 기준의 합과 열의 합 사이에 불일치가 발생
    • 값들의 정규화의 여부를 지정. 이 인수에 전달 할 수 있는 인수값은 다음과 같습니다.
      • normalize=True or all 이면 각 값은 총합으로 나눈 값을 반환
      • normalize=index, 각 행에 대해 정규화
      • normalize=column, 각 열에 대해 정규화
kos= np.array([1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1])
kq= np.array([1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1])
ct=pd.crosstab(kos, kq, rownames=['kospi'], colnames=['kq'], margins=True)
ct
kq 0 1 All
kospi
0 6 2 8
1 2 8 10
All 8 10 18

P(kos = 1) * P(kq = 1)의 결과

round(ct.iloc[1,2]/18*ct.iloc[1,2]/18, 4)
0.3086

P(kos = 1) ∩ P(kq = 1)의 결과

round(ct.iloc[1,1]/18, 4)
0.4444

위 두 결과가 같지 않으므로 독립이 아닙니다.

댓글

이 블로그의 인기 게시물

[Linear Algebra] 유사변환(Similarity transformation)

유사변환(Similarity transformation) n×n 차원의 정방 행렬 A, B 그리고 가역 행렬 P 사이에 식 1의 관계가 성립하면 행렬 A와 B는 유사행렬(similarity matrix)이 되며 행렬 A를 가역행렬 P와 B로 분해하는 것을 유사 변환(similarity transformation) 이라고 합니다. $$\tag{1} A = PBP^{-1} \Leftrightarrow P^{-1}AP = B $$ 식 2는 식 1의 양변에 B의 고유값을 고려한 것입니다. \begin{align}\tag{식 2} B - \lambda I &= P^{-1}AP – \lambda P^{-1}P\\ &= P^{-1}(AP – \lambda P)\\ &= P^{-1}(A - \lambda I)P \end{align} 식 2의 행렬식은 식 3과 같이 정리됩니다. \begin{align} &\begin{aligned}\textsf{det}(B - \lambda I ) & = \textsf{det}(P^{-1}(AP – \lambda P))\\ &= \textsf{det}(P^{-1}) \textsf{det}((A – \lambda I)) \textsf{det}(P)\\ &= \textsf{det}(P^{-1}) \textsf{det}(P) \textsf{det}((A – \lambda I))\\ &= \textsf{det}(A – \lambda I)\end{aligned}\\ &\begin{aligned}\because \; \textsf{det}(P^{-1}) \textsf{det}(P) &= \textsf{det}(P^{-1}P)\\ &= \textsf{det}(I)\end{aligned}\end{align} 유사행렬의 특성 유사행렬인 두 정방행렬 A와 B는 'A ~ B' 와 같...

[sympy] Sympy객체의 표현을 위한 함수들

Sympy객체의 표현을 위한 함수들 General simplify(x): 식 x(sympy 객체)를 간단히 정리 합니다. import numpy as np from sympy import * x=symbols("x") a=sin(x)**2+cos(x)**2 a $\sin^{2}{\left(x \right)} + \cos^{2}{\left(x \right)}$ simplify(a) 1 simplify(b) $\frac{x^{3} + x^{2} - x - 1}{x^{2} + 2 x + 1}$ simplify(b) x - 1 c=gamma(x)/gamma(x-2) c $\frac{\Gamma\left(x\right)}{\Gamma\left(x - 2\right)}$ simplify(c) $\displaystyle \left(x - 2\right) \left(x - 1\right)$ 위의 예들 중 객체 c의 감마함수(gamma(x))는 확률분포 등 여러 부분에서 사용되는 표현식으로 다음과 같이 정의 됩니다. 감마함수는 음이 아닌 정수를 제외한 모든 수에서 정의됩니다. 식 1과 같이 자연수에서 감마함수는 factorial(!), 부동소수(양의 실수)인 경우 적분을 적용하여 계산합니다. $$\tag{식 1}\Gamma(n) =\begin{cases}(n-1)!& n:\text{자연수}\\\int^\infty_0x^{n-1}e^{-x}\,dx& n:\text{부동소수}\end{cases}$$ x=symbols('x') gamma(x).subs(x,4) $\displaystyle 6$ factorial 계산은 math.factorial() 함수를 사용할 수 있습니다. import math math.factorial(3) 6 a=gamma(x).subs(x,4.5) a.evalf(3) 11.6 simpilfy() 함수의 알고리즘은 식에서 공통사항을 찾아 정리하...

sympy.solvers로 방정식해 구하기

sympy.solvers로 방정식해 구하기 대수 방정식을 해를 계산하기 위해 다음 함수를 사용합니다. sympy.solvers.solve(f, *symbols, **flags) f=0, 즉 동차방정식에 대해 지정한 변수의 해를 계산 f : 식 또는 함수 symbols: 식의 해를 계산하기 위한 변수, 변수가 하나인 경우는 생략가능(자동으로 인식) flags: 계산 또는 결과의 방식을 지정하기 위한 인수들 dict=True: {x:3, y:1}같이 사전형식, 기본값 = False set=True :{(x,3),(y,1)}같이 집합형식, 기본값 = False ratioal=True : 실수를 유리수로 반환, 기본값 = False positive=True: 해들 중에 양수만을 반환, 기본값 = False 예 $x^2=1$의 해를 결정합니다. solve() 함수에 적용하기 위해서는 다음과 같이 식의 한쪽이 0이 되는 형태인 동차식으로 구성되어야 합니다. $$x^2-1=0$$ import numpy as np from sympy import * x = symbols('x') solve(x**2-1, x) [-1, 1] 위 식은 계산 과정은 다음과 같습니다. $$\begin{aligned}x^2-1=0 \rightarrow (x+1)(x-1)=0 \\ x=1 \; \text{or}\; -1\end{aligned}$$ 예 $x^4=1$의 해를 결정합니다. solve() 함수의 인수 set=True를 지정하였으므로 결과는 집합(set)형으로 반환됩니다. eq=x**4-1 solve(eq, set=True) ([x], {(-1,), (-I,), (1,), (I,)}) 위의 경우 I는 복소수입니다.즉 위 결과의 과정은 다음과 같습니다. $$x^4-1=(x^2+1)(x+1)(x-1)=0 \rightarrow x=\pm \sqrt{-1}, \; \pm 1=\pm i,\; \pm1$$ 실수...