데이터를 대표하는 값 찾기
22 Jun 2017 | statistics
이 글에서는 데이터를 대표하는 값을 찾는 몇 가지 방법을 소개하였습니다. 너무도 쉽고 당연해 그냥 넘길 수 있는 지표들이지만 ‘Back to the basic’의 마음가짐으로 정리해봤습니다. 이 글은 ‘밑바닥부터 시작하는 데이터과학(조엘 그루스, 인사이트 펴냄)’과 ‘일반통계학(김우철 외, 영지문화사)’ 두 책을 참고했음을 먼저 밝힙니다. 그럼 시작하겠습니다.
평균
가장 널리쓰이는 지표는 평균(mean)일 것입니다. 특성값들을 모두 더한 뒤 전체 개체 수로 나눈 산술평균으로 정의됩니다. 예컨대 다음과 같이 우리나라 15세 이상 기혼여성을 대상으로 출생아 수를 조사한 결과가 다음과 같다고 가정해봅시다. 출생아 수의 평균은 특성값과 상대도수를 곱해 모두 더한 값이 됩니다.
특성값(출생아 수)
0
1
2
3
4
5
…
상대도수
.058
.151
.303
.175
.113
.083
…
일반적으로 평균은 가느다란 막대 위해 상대도수에 비례하는 질량의 물체를 각 특성값의 위치에 놓을 때 균형점의 위치가 됩니다. 평균은 해당 집단의 균형점으로서의 균형위치를 나타냅니다.
분위수
모집단 분포의 위치를 나타내는 대표값으로서 제$p$백분위수(pth percentile)가 있습니다. 특성값을 작은 것부터 순서대로 나열하였을 때 $p$% 이상의 특성값이 그 값보다 작거나 같고, 또한 $(100-p)$%의 특성값이 그 값보다 크거나 같게 되는 값으로 정의됩니다. 특히 제25백분위수를 제1사분위수(first quartile), 제50백분위수를 중앙값(median), 제75백분위수를 제3사분위수(third quartile)이라고 하며 각각 $Q_1$, $Q_2$, $Q_3$로 표시합니다.
이 가운데 모중앙값 $Q_2$는 모평균 $μ$와 같이 모집단 분포의 중심위치를 나타내며 특성값이 연속적인 무한 모집단의 경우에는 밀도곡선의 전체 넓이를 이등분하는 점이 됩니다. 모중앙값은 추정 이론의 어려움 때문에 모평균처럼 통상적으로 고려되는 추론의 대상은 아니지만, 비모수통계학(non-parametric statistics)에선 중요 고려 대상이 됩니다. 제$p$백분위수를 파이썬 코드로 나타내면 다음과 같습니다.
def percentile(x, p):
p_index = int(p * len(x))
return sorted(x)[p_index]
중앙값
중앙값을 파이썬 코드로 나타내면 다음과 같습니다.
def median(v):
n = len(v)
sorted_v = sorted(v)
midpoint = n // 2
if n % 2 == 1:
# 데이터 포인트의 개수가 홀수면 중앙값을 반환
return sorted_v[midpoint]
else:
# 데이터 포인트의 개수가 짝수면 두 중앙값의 평균을 반환
lo = midpoint - 1
hi = midpoint
return (sorted(v)[lo] + sorted(v)[hi]) / 2
산포
산포(dispersion)란 모집단에서 특성값이 흩어져 있는 상태를 뜻합니다. 산포에 관련된 대표적인 측도로 분산(variance)이 있습니다만 이 글 다른 꼭지에서 따로 다루겠습니다. 가장 간단한 형태의 산포 측도는 가장 큰 값과 작은 값의 차이를 나타내는 범위(range)일 겁니다. 다음과 같습니다.
def data_range(x):
return max(x) - min(x)
사분위수 범위
산포를 나타내는 다른 지표로 사분위수범위(interquantile range)가 있습니다. 제3사분위수와 제1사분위수의 차로 정의되며, 모집단에서 가운데 50% 특성값의 범위를 나타냅니다. 몇몇 이상치가 주는 영향을 제거해 모집단의 산포를 가늠하는 데 유용한 지표로 알려져 있습니다. 사분위수범위의 파이썬 코드는 다음과 같습니다.
# 몇몇 이상치가 주는 영향을 제거해 관측치 편차 비교할 때 유용
def interquantile_range(x):
return percentile(x, 0.75) - percentile(x, 0.25)
최빈값
데이터에 제일 자주 등장하는 특성값을 나타냅니다.
from collections import Counter
def mode(x):
# 최빈값이 하나보다 많다면 list를 반환
counts = Counter(x)
max_count = max(counts.values())
return [x_i for x_i, count in counts.items() if count == max_count]
평균을 0으로 맞추기
분산과 공분산을 구하려면 데이터의 평균을 0으로 맞추는 것이 여러모로 편리합니다. 이를 위한 함수를 정의했습니다.
def de_mean(x):
#x의 모든 데이터 포인트에서 평균을 뺌
n = len(x)
x_bar = sum(x) / n
return [x_i - x_bar for x_i in x]
분산과 표준편차
분산은 데이터의 평균과 각 특성값의 차(편차)를 제곱하여 산술평균한 것입니다. 표준편차는 분산의 제곱근입니다. 분산과 표준편차가 작을 수록 평균값에서 특성값들 사이의 거리가 가깝다는 걸 의미합니다. 이와 관련된 파이썬 코드는 다음과 같습니다.
# 분산
def variance(x):
n = len(x)
deviations = de_mean(x)
sum_of_squares = sum([x_i ** 2 for x_i in deviations])
return sum_of_squares / (n - 1)
# 표준편차
def standard_deviation(x):
return variance(x) ** 0.5
공분산과 상관관계
상관계수(correlation coefficient)는 두 확률변수의 직선관계가 얼마나 강하고 어떤 방향인지를 나타냅니다. 상관계수에 각 확률변수의 표준편차에 해당하는 값을 곱한 것을 공분산(covariance)이라고 합니다. 파이썬 코드는 다음과 같습니다.
import numpy as np
def covariance(x, y):
n = len(x)
return np.dot(de_mean(x), de_mean(y)) / (n - 1)
def correlation(x, y):
stdev_x = standard_deviation(x)
stdev_y = standard_deviation(y)
if stdev_x > 0 and stdev_y > 0:
return covariance(x, y) / stdev_x / stdev_y
else:
return 0
이 글에서는 데이터를 대표하는 값을 찾는 몇 가지 방법을 소개하였습니다. 너무도 쉽고 당연해 그냥 넘길 수 있는 지표들이지만 ‘Back to the basic’의 마음가짐으로 정리해봤습니다. 이 글은 ‘밑바닥부터 시작하는 데이터과학(조엘 그루스, 인사이트 펴냄)’과 ‘일반통계학(김우철 외, 영지문화사)’ 두 책을 참고했음을 먼저 밝힙니다. 그럼 시작하겠습니다.
평균
가장 널리쓰이는 지표는 평균(mean)일 것입니다. 특성값들을 모두 더한 뒤 전체 개체 수로 나눈 산술평균으로 정의됩니다. 예컨대 다음과 같이 우리나라 15세 이상 기혼여성을 대상으로 출생아 수를 조사한 결과가 다음과 같다고 가정해봅시다. 출생아 수의 평균은 특성값과 상대도수를 곱해 모두 더한 값이 됩니다.
특성값(출생아 수) | 0 | 1 | 2 | 3 | 4 | 5 | … |
---|---|---|---|---|---|---|---|
상대도수 | .058 | .151 | .303 | .175 | .113 | .083 | … |
일반적으로 평균은 가느다란 막대 위해 상대도수에 비례하는 질량의 물체를 각 특성값의 위치에 놓을 때 균형점의 위치가 됩니다. 평균은 해당 집단의 균형점으로서의 균형위치를 나타냅니다.
분위수
모집단 분포의 위치를 나타내는 대표값으로서 제$p$백분위수(pth percentile)가 있습니다. 특성값을 작은 것부터 순서대로 나열하였을 때 $p$% 이상의 특성값이 그 값보다 작거나 같고, 또한 $(100-p)$%의 특성값이 그 값보다 크거나 같게 되는 값으로 정의됩니다. 특히 제25백분위수를 제1사분위수(first quartile), 제50백분위수를 중앙값(median), 제75백분위수를 제3사분위수(third quartile)이라고 하며 각각 $Q_1$, $Q_2$, $Q_3$로 표시합니다.
이 가운데 모중앙값 $Q_2$는 모평균 $μ$와 같이 모집단 분포의 중심위치를 나타내며 특성값이 연속적인 무한 모집단의 경우에는 밀도곡선의 전체 넓이를 이등분하는 점이 됩니다. 모중앙값은 추정 이론의 어려움 때문에 모평균처럼 통상적으로 고려되는 추론의 대상은 아니지만, 비모수통계학(non-parametric statistics)에선 중요 고려 대상이 됩니다. 제$p$백분위수를 파이썬 코드로 나타내면 다음과 같습니다.
def percentile(x, p):
p_index = int(p * len(x))
return sorted(x)[p_index]
중앙값
중앙값을 파이썬 코드로 나타내면 다음과 같습니다.
def median(v):
n = len(v)
sorted_v = sorted(v)
midpoint = n // 2
if n % 2 == 1:
# 데이터 포인트의 개수가 홀수면 중앙값을 반환
return sorted_v[midpoint]
else:
# 데이터 포인트의 개수가 짝수면 두 중앙값의 평균을 반환
lo = midpoint - 1
hi = midpoint
return (sorted(v)[lo] + sorted(v)[hi]) / 2
산포
산포(dispersion)란 모집단에서 특성값이 흩어져 있는 상태를 뜻합니다. 산포에 관련된 대표적인 측도로 분산(variance)이 있습니다만 이 글 다른 꼭지에서 따로 다루겠습니다. 가장 간단한 형태의 산포 측도는 가장 큰 값과 작은 값의 차이를 나타내는 범위(range)일 겁니다. 다음과 같습니다.
def data_range(x):
return max(x) - min(x)
사분위수 범위
산포를 나타내는 다른 지표로 사분위수범위(interquantile range)가 있습니다. 제3사분위수와 제1사분위수의 차로 정의되며, 모집단에서 가운데 50% 특성값의 범위를 나타냅니다. 몇몇 이상치가 주는 영향을 제거해 모집단의 산포를 가늠하는 데 유용한 지표로 알려져 있습니다. 사분위수범위의 파이썬 코드는 다음과 같습니다.
# 몇몇 이상치가 주는 영향을 제거해 관측치 편차 비교할 때 유용
def interquantile_range(x):
return percentile(x, 0.75) - percentile(x, 0.25)
최빈값
데이터에 제일 자주 등장하는 특성값을 나타냅니다.
from collections import Counter
def mode(x):
# 최빈값이 하나보다 많다면 list를 반환
counts = Counter(x)
max_count = max(counts.values())
return [x_i for x_i, count in counts.items() if count == max_count]
평균을 0으로 맞추기
분산과 공분산을 구하려면 데이터의 평균을 0으로 맞추는 것이 여러모로 편리합니다. 이를 위한 함수를 정의했습니다.
def de_mean(x):
#x의 모든 데이터 포인트에서 평균을 뺌
n = len(x)
x_bar = sum(x) / n
return [x_i - x_bar for x_i in x]
분산과 표준편차
분산은 데이터의 평균과 각 특성값의 차(편차)를 제곱하여 산술평균한 것입니다. 표준편차는 분산의 제곱근입니다. 분산과 표준편차가 작을 수록 평균값에서 특성값들 사이의 거리가 가깝다는 걸 의미합니다. 이와 관련된 파이썬 코드는 다음과 같습니다.
# 분산
def variance(x):
n = len(x)
deviations = de_mean(x)
sum_of_squares = sum([x_i ** 2 for x_i in deviations])
return sum_of_squares / (n - 1)
# 표준편차
def standard_deviation(x):
return variance(x) ** 0.5
공분산과 상관관계
상관계수(correlation coefficient)는 두 확률변수의 직선관계가 얼마나 강하고 어떤 방향인지를 나타냅니다. 상관계수에 각 확률변수의 표준편차에 해당하는 값을 곱한 것을 공분산(covariance)이라고 합니다. 파이썬 코드는 다음과 같습니다.
import numpy as np
def covariance(x, y):
n = len(x)
return np.dot(de_mean(x), de_mean(y)) / (n - 1)
def correlation(x, y):
stdev_x = standard_deviation(x)
stdev_y = standard_deviation(y)
if stdev_x > 0 and stdev_y > 0:
return covariance(x, y) / stdev_x / stdev_y
else:
return 0
Comments