How to Use Normal Distribution like You Know What You Are Doing
Photo by Eva Elijas on Pexels
Introduction
당신은 한밤중에 통계학자를 깨워 정규분포(Normal Distribution)의 식에 대해 묻는다. 비몽사몽간에 통계학자는 종이에 아래 식을 나열한다.
정규분포는 세상에서 가장 기본적인 것중 하나이다. 이 분포는 자연, 과학, 수학 등 거의 어디에서나 보인다. 양자(proton)간 충돌, 군중의 행동같은 거의 미친 현상조차 정규분포를 상요하여 모델링 될 수 있다.
우리가 정규분포된 데이터를 그릴 때 보통 종모양(bell-shaped)의 형태를 이룬다.
그렇기 때문에 우리는 또한 이를 bell curve 또는 Gaussian distribution이라고도 부른다.(이것을 발견할 독일 수학자 Karl Gauss의 이름을 따옴.)
이것은 비즈니스 세계에 많은 영향을 미친다. 데이터 과학자와 통계학자가 정규성 가정(normality assumption)으로 시작하는 많은 새로운 데이터를 분석하는 것은 어디에나 있다. 게다가 이후에 다룰 중심극한정리(central limit theorem) 때문에 기본 분포(underlying distribution)가 비정규적일 때 조차 정규분포를 유도할 수 있다.
이 글에서는 이론적으로 이해하고 코드를 통해 아이디어를 적용해 봄으로써 일상적인 작업에서 이를 어떻게 사용하는지를 알아본다.
Normal Distribution Teaser
정규분포는 분석동안 꿈꿀 수 있는 최고의 것으로 작업을 쉽게 만들고 결과를 끌어내는 많은 '훌륭한' 속성(property)을 갖는다.
ND(정규분포)의 종모양 곡선을 보기 전에 곡선의 높이는 표준편차(standard deviation)의 값으로 결정된다. 작은 표준편차는 더 많은 데이터 포인트가 평균 주변에 모이지만 큰 값은 더 펼쳐진(spread-out) 분포를 나타낸다. 이는 또한 곡선의 밀도(density)가 표준편차로 결정된다는 것으로 해석될 수 있다.
정규분포의 평균은 X 축을 따라 중심을 옮긴다.
보이는 것과 같이 이론적으로 완벽한 정규분포는 단일 피크(peak)를 갖고 또한 대칭선이 분포를 가로지른다. 게다가 다음 서술은 완벽한 정규분포를 만족시킬 수 있다.
- 평균(mean), 중간값(median), 최빈값(mode)가 모두 같다.
- 정확히 값의 절반이 대칭선의 왼쪽에 있고 정확히 반이 오른쪽에 있다.
- 곡선 아래 전체 면적은 항상 1이다.
물론, 실제 데이터가 종모양 패턴을 따르는 경우는 거의 없다. 그러나 안전하게 정상으로써 다룰 수 있을지 를 보기위해 완벽한 정규분포와 기본분포간 유사도(similarity)를 추정할 가치가 있다. 이후 내용에서 이 유사도 프로세스를 생성하는 법을 알아본다.
What is PDF(Probability Density Function) really?
지금까지 정규분포의 도표를 보았지만 어떤 함수가 이 도표를 만드는지 모른다. 이를 알기 위해서는 연속확률분포(continuous probability distributions)가 무엇인지 이해해야 한다.
서술적인 통계학(descriptive statistics)에 따르면, 데이터는 별개(discrete)와 연속(continuous) 두가지 형태가 있다. 시험점수의 결과, 하루에 먹은 사과의 개수, 빨간불에 멈춰선 횟수 등과 같이 숫자를 세는 것으로 기록된 데이터는 별개이다(정수값). 반대로 연속적인 데이터는 키, 몸무게, 거리 등과 같이 측정으로 기록된 데이터이다. 시간 자체는 연속적인 데이터로 간주된다.
연속적인 데이터의 측면을 정의하는 하나는 동일한 데이터가 다른 단위로 표시될 수 있다는 것이다. 예를 들어 거리는 마일, 킬로미터, 미터, 센티미터, 밀리미터로 측정될 수 있으며 목록은 계속된다. 얼마나 작은지는 중요하지 않다. 연속적인 데이터에 대해 더 작은 단위를 찾을 수 있다. 또한 단일 측정에 대해 무한하게 많은 소수점이 있을 수 있다는 것을 나타낸다.
확률에서 만약 임의실험이 연속적인 결과를 만들면 이는 연속확률분포를 갖는다. 예를 들면, 임의 변수 X가 인치(inch)로 매일 강우량을 저장한다고 하자. 이제 이것은 강수량이 정수값을 갖을 가능성이 극단적으로 낮다. 왜냐하면 우리는 오늘 정확히 2인치 강우량이었다고 말할 수 없기 때문이다. 단일 물분자도 다소간 아니다. 그런 사건의 확률은 0이라고 안전하게 말할 수 있게 아주 작다.
2.1 또는 2.0000091 또는 2.000000001 같은 다른 값이 동일할 수 있다. 강수량이 정확히 일부 총량인 가능성은 항상 0이다. 그렇기 때문에 연속분포에 대해 PDF(Probability Density Functions)라는 다른 함수를 갖는다. 다른 글에서 PMF(확률질량함수, Probability Mass Functions)가 주사위 굴리기, 동전 던지기 또는 다른 베르누이 실행(Bernoulli trials)같은 별개의 이벤트에 대한 확률을 계산했다.
PMF는 높이(height)로써 결과의 확률을 인코딩한다. 다음은 단일 주사위 굴리기의 PMF 도표 예제이다.
보이는 것과 같이 각 막대의 높이는 1, 3, 5같은 단일 결과의 확률을 나타낸다. 이 결과들은 주사위가 별개의 균등분포(uniform distribution)를 갖기 때문에 모두 동일한 높이이다.
이제, PMF는 특정 확률을 나타내는 면적을 사용한다. 계속하기 전에 높이로 확률을 인코딩하면 어떻게 될지 생각해 보자. 언급했던것과 같이 연속적인 데이터가 아래처럼 높이가 모두 0으로 내려가는 특정 값을 갖는 것에 대한 확률은 매우 작다.
통계학자가 가장 선호하는 식을 기억해보자.
이것은 정규분포에 대한 PDF의 식이다. 그 자체로는 많은 것을 할 수 없다. 평균($\mu$)과 표준편차($\sigma$)를 알고있는 정규분포에서는 어떠한 x값이라도 함수에 입력할 수 있다. 이 식은 X축에서 해당 지점에 곡선의 높이를 출력한다. 확률(probability)을 이야기하고 있는 것이 아니란 것을 기억하자. 단지 곡선의 높이를 이야기하고 있다. 이미 언급했던 것 처럼 연속적인 분포에서 면적(area)은 특정 확률을 나타낸다. 그럼 도표에서 얇은 선은 면적을 갖지 않는다 따라서 처음 질문을 다시 구성해야 한다.
매일 강수량을 관찰한 임의의 실험에서 강수량이 3인치 또는 2.5인치일 확률 같은 질문은 하지 않을 것이다. 왜냐하면 그 대답은 항상 0이 될 것이기 때문이다. 대신, 이제는 1.6에서 1.9인치 사이의 강수량인 확률은 무엇인가라고 묻는다. 이것은 아래 그림에서 보이는 두 선 사이의 곡선아래 면적이 무엇인가를 묻는 것과 동일하다.
아래 적분공식(integral formular)으로 계산할 수 있다.
아직 계산하지 말자. 여기서는 수작업 또는 코드를 사용하여 이것을 계산하지 않을 것이다. 이후에 이것을 훨씬 더 쉽게 계산하는 방법을 알아볼 것이다.
위 공식은 강수량이 1.6에서 1.9인치 사이인 확률을 0과 1사이의 수로 만든다. 분명한 질문은 확률이 주어지지 않기 때문에 Y축으로부터 무엇을 해석하는가이다. 이 질문에 대답하기 위한 자격이 없다. 따라서 StackExchange의 이글과 3Blue3Brown의 이 비디오를 보는 것을 권한다.
다음으로 누적분포함수(Cumulative Distribution Function)에 대해 알아본다. 이것은 면적 아래의 확률을 계산하기 위한 더 나은 도구를 제공하고 정규분포의 개선된 시가과를 제공할 것이다.
누적분포함수(CDF, Cumulative Distribution Function)
이 시점에서 우리는 이미 정규분포의 그래프가 곡선을 이룬다는 것에 동의했고 이미 종 모양인 곡선도 보았다. 이제는 시그모이드(sigmoid) 곡선을 보자.
이 도표를 해석하기 전에 누적분포함수(CDF)가 무엇인지 간단한 예제로 알아보자.
Cdf.from_seq([1, 2, 3, 4, 5, 6])
어떤 분포에서 임의의 숫를 가져와 CDF에 넣으면 결과는 해당 임의의 수보다 작거나 같은 값을 갖게되는 확률이다. 위 도표는 단일 주사위의 누적분포함수(CDF)이다. 주사위는 1, 2, 3, 4, 5, 6의 분포를 갖는다. 여기서 임의로 4를 선택했다고 하자.
분포에서 4보다 작거나 같은 값을 보이는 확률은 무엇일까? 위의 CDF에 따르면 0.6666이다. 유사하게 6보다 작거나 같은 값을 보이는 확률은 100%이다. 왜냐하면 분포에서 모든 값이 6보다 작거나 같기 때문이다.
표기법으로는 아래와 같다.
CDF를 계산하기 위한 초기 단계는 각각의 출력에 대한 개별적인 확률을 계산하는 것이다. 그리고 어떤 값 x의 누적확률은 분포에서 x까지 정렬된 개별 확률의 합이 된다.
이제 정규분포의 CDF로 돌아가 보면 쉽게 이를 해석할 수 있다.
이 곡선을 시그모이드(sigmoid)라고도 부른다. 정규분포의 평균은 이 곡선의 중심이다.
CDF를 사용하면 정규분포의 식을 사용할 필요가 없다. 예를 들면, 1.6과 1.9사이에 떨어지는 X의 확률을 구하려면 상한선 CDF를 찾아 하한선 CDF를 빼면 된다.
Finally, Python Normal Stuff
마지막으로 지금까지의 종모양 곡선과 CDF를 그렸는지를 알아본다. 우선, 어떤 분포의 종모양 곡선은 Seaborn의 kdeplot 함수를 사용하여 그릴 수 있다.
분포를 그리기 위해 분포 자체를 만들어야 한다. 이것은 numpy.random.normal을 사용하여 만들 수 있다.
import numpy as np
normal_dist = np.random.normal(loc=5, scale=2, size=10000)
>>> normal_dist
array([7.8619458 , 2.65074237, 2.15212128, ..., 4.1277429 , 6.30277494, 8.21359059])
여기서는 평균이 5이고 표준편차가 2인 정규분포로부터 10,000개의 샘플을 사용한다. 다음은 곡선을 그리기 우해 kdeplot을 사용한다.
# Create fig, ax objects
fig, ax = plt.subplots(figsize=(10, 8))
# Create the curve
sns.kdeplot(normal_dist, bw_adjust=2, ax=ax)
# Labeling
ax.set(title='The PDF plot of Normal Distribution With Mean 5 and StD 2',
xlabel='X values', ylabel='Density')
plt.show();
kdeplot은 분포로 연속적인 값을 사용한다. bw_adjust 파리미터는 곡선의 매끄러운 정도를 제어한다. 이 함수에 대한 좀더 자세한 정보는 여기를 참조하자.
이제는 CDF를 만들기 위해서는 좀 더 작업이 필요하다. 직접 이를 만들 수 있지만 여기서는 empiricaldist 라이브러이의 Cdf 함수를 사용한다.
from empiricaldist import Cdf
Cdf는 분포의 CDF를 계산하는 from_seq 메소드가 있다.
normal_dist = np.random.normal(2, 5, size=10000)
normal_cdf = Cdf.from_seq(normal_dist)
>>> normal_cdf
다음은 pyplot으로 분포를 그린다.
# Create fig, ax objects
fig, ax = plt.subplots(figsize=(10, 8))
# Plot the CDF
ax.plot(normal_cdf)
# Labeling
ax.set(title='CDF of a Perfect Normal Distribution',
xlabel='Outcomes', ylabel='P(X <= x)')
plt.show();
예상된 바와 같이 그래프에서 매끄러운 시그모이드가 보인다.
마지막으로 실제로 사용하는 경우를 보자. 주어진 분포가 정규분포인지를 알기 위해 CDF 그래프를 사용한다. 그 예로써 Seaborn에서 Iris 데이터셋을 사용한다.
iris = sns.load_dataset('iris').dropna()
>>> iris.head()
>>> iris.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 150 entries, 0 to 149
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 sepal_length 150 non-null float64
1 sepal_width 150 non-null float64
2 petal_length 150 non-null float64
3 petal_width 150 non-null float64
4 species 150 non-null object
dtypes: float64(4), object(1)
memory usage: 7.0+ KB
많은 자연 현상들은 정규분포를 따른다. 따라서 Iris 꽃 품종의 측정은 정규분포를 따른다고 가정할 수 있다. 얼마자 정확한지 보자.
# Create fig, ax objects
fig, ax = plt.subplots(figsize=(10, 8))
# Create the KDE plot to see if it follows a normal dist
sns.kdeplot(iris['sepal_length'], ax=ax)
# Labeling
ax.set(title='PDF of Sepal Length of Iris Flowers',
xlabel='Length (mm)', ylabel='Density')
plt.show();
눈으로 확인하면 이미 가정이 틀렸다는 것을 볼 수 있다. 그러나 비교를 위해 완벽한 정규분포를 그리는 것이 더 낫다는 것을 확인하자. 어떤 정규분포가 필요한가? 물론 무한히 많은 정규분포가 있다. 그러면 어떻게 하나를 선택해야 하는가?
두 분포가 가깝도록 대상 분포와 동일한 평균과 표준편차를 가진 정규분포를 그리는 것이 현명할 것이다.
# Create fig, ax objects
fig, ax = plt.subplots(figsize=(10, 8))
# Create the KDE plot to see if it follows a normal dist
sns.kdeplot(iris['sepal_length'], ax=ax, label='Underlying Distribution')
# Get the parameters from the underlying dist
sepal_mean = iris['sepal_length'].mean()
sepal_std = iris['sepal_length'].std()
# Create the ND using the above params
sepal_normal = np.random.normal(sepal_mean, sepal_std, size=10000)
# Add it to the plot for comparison
sns.kdeplot(sepal_normal, bw_adjust=2, label='Perfect Normal Dist')
# Labeling
ax.set(title='PDF of Sepal Length of Iris Flowers',
xlabel='Length (mm)', ylabel='Density')
# Show the legend
ax.legend(fontsize=15)
plt.show();
이제 두 분포가 완전히 다르다는 것이 훨씬 더 명확하다. 그러나 두 분포가 서로 아주 가깝지만 꽤 다른 많은 경우 즉, 정규분포가 아닌 경우가 있다. 가까운 bell-curve를 비교하는 것은 사람의 눈으로는 쉽지 않다. 그래서 그런 분포를 비교하기 위해 더 나은 사각화 - 여기서는 CDF-를 사용한다.
위에서와 동일한 기술을 사용하지만 PDF를 CDF로 바꾼다.
# Create fig, ax objects
fig, ax = plt.subplots(figsize=(10, 8))
# Create the CDF of sepal lengths
sepal_cdf = Cdf.from_seq(iris['sepal_length'])
# Plot the CDF
ax.plot(sepal_cdf, label='Underlying Dist', marker='.', linestyle='none')
# Create the perfect Normal Dist and its CDF
normal_dist = np.random.normal(sepal_mean, sepal_std, size=10000)
normal_cdf = Cdf.from_seq(normal_dist)
# Plot it
ax.plot(normal_cdf, label='Perfect Normal CDF')
# Show the legend
ax.legend(fontsize=15)
# Labeling
ax.set(title='Comparison of CDF of the Perceft '
'and the Underlying Distributions',
xlabel='Sepal Length (mm)',
ylabel='P(X <= x)')
plt.show();
꽃받침 길이의 CDF를 만들고 선으로 도표를 그린다. 다음은 꽃받침 길이의 평균과 표준편차를 구하고 동일한 평균과 표준편차를 갖는 완벽한 정규분포를 만들고 CDF를 생성한다. 그리고 서로의 상단에 그래프를 그린다. 명확하게 하기 위해 선이 아닌 점으로 표시했다.
이제, 이를 해석하면 분포가 그렇게 다르지 않다는 것을 알 수 있다. 또한 샘플크기가 매우 작은 것(150개)도 고려해야 한다.
간단히, 정규분포를 시뮬레이션하려면 np.random.normal을 사용한다. 더 나은 정확도를 위해 샘플 크기를 늘려본다. 분포가 정규분포인지를 알고 싶다면, 분포의 CDF를 그리고 동일한 평균과 표준편차를 가진 완벽한 정규분포의 CDF를 그려본다.
Conclusion
이 글에서 많은 것을 다뤘지만 여전히 정규분포에 대해서 배울 것이 많다. 다시 말해, 여기서는 중심극한정리(Central Limit Theorem), 경험법칙(Empirical rule) 또는 많은 다른 주제를 다루지 않았다. 아래는 몇가지 주제에 대한 링크이다.
- Normal Distribution by Brilliant.org
- Central Limit Theorem by Brilliant.org
- Normal Distribution by Khan Academy
- The Wikipedia page