Py) 통계 - 기술통계(변이 통계량)

Py) 통계 - 기술통계(변이 통계량)

파이썬으로 기술통계 중 변이 통계량의 계산에 대해 알아보자.


※ 본 내용에서 사용하는 diamonds.csv 파일은 별도로 다운로드 받아야 한다.
diamonds.csv 다운받기 [클릭]

개요

기술 통계는 주어진 데이터 세트를 설명하고 요약하는 데 사용되는 통계 기법이며 다음과 같이 크게 세 종류로 나뉜다.

  1. 위치 통계량(Measures of Location)
  2. 변이 통계량(Measures of Dispersion)
  3. 모양 통계량(Measures of Shape)

이 중 변이 통계량에 대해 알아보고자 한다.

분산, 표준편차, 변동계수, 범위, IQR, 백분위수

범위

범위(range)는 데이터의 최대값에서 최소값을 뺀 값이며 가장 쉽게 계산할 수 있는 변이 통계량이나 극단치에 영향을 많이 받기에 해석 및 활용에 주의해야 한다.

$$max(x) - min(x)$$

IQR

사분위 범위(IQR, Inter Quantile Range)는 데이터의 제 3 사분위수에서 제 1 사분위수를 뺀 값이며 자료의 분포가 몰려있는 대략적인 범위를 파악하거나 극단치를 식별할 때 활용하는 변이 통계량이다.

$$Q_{3} - Q_{1}$$

분산

분산(variance)는 각 데이터에서 그 평균을 뺀 값인 편차(deviation)를 모두 더한 다음 그 값을 제곱하여 구할 수 있다. 단순히 편차의 평균을 구하게 되면 음수 때문에 편차가 서로 상쇄되어버려 제곱을 취한 모양새인데 아쉽게도 제곱을 하다보니 원 데이터 대비 값이 매우 커지거나 작아지고 단위도 달라져(ex. $m → m^2$) 해석에 어려움이 있다. 그리고 분산은 평균값이 변하더라도 분산의 계산방법이나 성질에 영향을 주지 않기 때문에 “평균값에 독립적”이라고 하기도 하고 평균값이 변하더라도 분산의 값은 같기 때문에 “평균에 대해 이동 불변성을 가진다.”라고 하기도 한다.

$$\frac{1}{n}\sum_{i = 1}^{n}{(x_{i} - \bar{x})^2}$$

분산은 실수의 제곱이기 때문에 항상 0 이상의 값을 가진다.

$$Var(X) \ge 0$$

데이터의 모든 값이 같은 상수(a)의 분산은 0이다.

$$Var(a) = 0$$

그리고 상기 사항에 대하여 어떤 확률변수 $X$의 분산이 0이라면 해당 확률변수는 상수(a)이며 이 역 또한 성립한다.

$$Var(a) = 0 \Leftrightarrow \exists a: P(X = a) = 1$$

좀 더 깊게 들어가자면 분산은 확률변수 $X$의 기댓값(평균) $\mu = E[X]$를 기준으로 확률변수가 얼마나 떨어져있는지 그 정도를 제곱한 것의 기댓값과 같다. 이와 관련해서 다음과 같은 수식으로 표현할 수 있다.

$$ \begin{align} Var(X) &= E[(X - \mu)^2]\\ &= E[(X - E[X])^2]\\ &= E[(X^2 - 2XE[X] - E[X]^2)]\\ &= E[X^2] - 2E[X]E[X] - E[X]^2\\ &= E[X^2] - E[X]^2\\ \end{align} $$

표준편차

표준편차는 분산의 (양의)제곱근으로 원 데이터의 스케일과 같은 단위를 가지기 때문에 데이터의 변동을 파악하고자 할 때 많이 사용된다. 그리고 분산과 마찬가지로 평균값이 변하더라도 표준편차의 계산방법이나 성질에 영향을 주지 않기 때문에 “평균값에 독립적”이라고 하기도 하고 평균값이 변하더라도 분산의 값은 같기 때문에 “평균에 대해 이동 불변성을 가진다.”라고 하기도 한다.

$$\sqrt{\frac{1}{n}\sum_{i = 1}^{n}{(x_{i} - \bar{x})^2}}$$

표준편차는 실수의 (양의)제곱근이기 때문에 항상 0 이상의 값을 가진다.

$$Std(X) \ge 0$$

데이터의 모든 값이 같은 상수(a)의 표준편차는 0이다.

$$Std(a) = 0$$

좀 더 깊게 들어가자면 표준편차는 확률변수 $X$의 기댓값(평균) $\mu = E[X]$를 기준으로 확률변수가 얼마나 떨어져있는지 그 정도를 제곱한 것의 기댓값의 (양의)제곱근과 같다. 이와 관련해서 다음과 같은 수식으로 표현할 수 있다.

$$ \begin{align} Std(X) &= \sqrt{E[(X - \mu)^2]}\\ &= \sqrt{E[(X - E[X])^2]}\\ &= \sqrt{E[(X^2 - 2XE[X] - E[X]^2)]}\\ &= \sqrt{E[X^2] - 2E[X]E[X] - E[X]^2}\\ &= \sqrt{E[X^2] - E[X]^2}\\ \end{align} $$

변동계수

변동계수(CV, Coefficient of Variation)는 변이계수 또는 상대표준편차(RSD, Relative Standard Variation)라고 한다. 표준편차의 경우 단일 데이터의 변동을 알아보기에 적합한 통계량이나 두 개 이상의 데이터간 상대비교를 위해서는 부적합 할 수 있다. 첫 번째로 데이터간 단위가 다르고 두 번째는 데이터간 단위가 같더라도 그 범위(스케일)가 상이할 수 있다. 그래서 서로 단위와 범위가 다른 데이터의 변동을 비교하고자 할 때 이 변동계수를 사용하기도 한다.

$$CV = \frac{\sigma}{\mu} \times 100$$

실습

실습을 위해 다음의 “diamonds.csv” 데이터세트를 준비한다.
※ “diamonds.csv” 파일은 포스팅 상단 링크를 통해 다운로드 가능

1
2
df = pd.read_csv("data/diamonds.csv")
df.head(2)
carat cut color clarity depth table price x y z
0 0.23 Ideal E SI2 61.5 55.0 326 3.95 3.98 2.43
1 0.21 Premium E SI1 59.8 61.0 326 3.89 3.84 2.31

범위

최소값과 최대값을 사용하여 계산하며 다음과 같이 두 가지 방식으로 산출 할 수 있다.

1
2
3
4
5
df["carat"].max() - df["carat"].min()
## 4.81

df["carat"].agg(lambda x: x.max() - x.min())
## 4.81

IQR

사분위 범위는 제 1사분위수와 제 3사분위수로 계산하며 다음과 같이 세 가지 방법으로 산출 할 수 있다.

1
2
3
4
5
6
7
8
9
10
df["carat"].quantile(q = 0.75) - df["carat"].quantile(q = 0.25)
## 0.64

df["carat"].agg(lambda x: x.quantile(0.75) - x.quantile(0.25))
## 0.64

df["carat"].quantile([0.25, 0.75]).diff()
## 0.25 NaN
## 0.75 0.64
## Name: carat, dtype: float64

분산

분산은 .var() 메서드로 계산할 수 있다. 단, 해당 메서드는 자유도가 1이 기본값이기 때문에 자유도를 0으로 설정하고 계산하려면 “ddof” 인자에 0을 할당해야 한다. NumPy로 분산을 계산하는 경우 자유도의 기본값이 0이고 Pandas로 분산을 계산하는 경우 자유도의 기본값이 1이기 때문에 각 라이브러리의 기능을 같이쓰지 않도록 주의해야하고 같이 사용하는 경우 자유도를 통일하거나 데이터의 특성에 맞게 자유도를 올바르게 지정하여야 한다.

1
2
3
4
5
6
7
8
df["carat"].var()
## 0.22468665982273753

df["carat"].var(ddof = 0)
## 0.22468249433034185

df["carat"].var(ddof = 1)
## 0.22468665982273753

표준편차

표준편차는 .std() 메서드로 계산할 수 있다. 단, 해당 메서드는 .var() 메서드와 마찬가지로 자유도가 1이 기본값이기 때문에 자유도를 0으로 설정하고 계산하려면 “ddof” 인자에 0을 할당해야 한다. 분산과 마찬가지로 NumPy로 분산을 계산하는 경우 자유도의 기본값이 0이고 Pandas로 분산을 계산하는 경우 자유도의 기본값이 1이기 때문에 각 라이브러리의 기능을 같이쓰지 않도록 주의해야하고 같이 사용하는 경우 자유도를 통일하거나 데이터의 특성에 맞게 자유도를 올바르게 지정하여야 한다.

1
2
3
4
5
6
7
8
df["carat"].std()
## 0.47401124440538067

df["carat"].std(ddof = 0)
## 0.47400685050992863

df["carat"].std(ddof = 1)
## 0.47401124440538067

변동계수

변동계수는 표준편차와 평균을 활용하여 계산하기 때문에 다음과 같이 접근할 수 있다.

1
2
3
4
5
df["carat"].std() / df["carat"].mean() * 100
## 59.40439057859712

df["carat"].agg(lambda x: x.std() / x.mean() * 100)
## 59.40439057859712

그리고 변동계수의 경우 단일 변수가 아니라 여러 변수를 대상으로 계산하고 이를 비교하는 경우가 많기 때문에 수치형 변수만 따로 골라내어 계산해보겠다. 다음과 같이 .select_dtypes() 메서드를 사용해서 “df_num” 객체를 준비하자.

1
2
df_num = df.select_dtypes(include = "number")
df_num.head(2)
carat depth table price x y z
0 0.23 61.5 55.0 326 3.95 3.98 2.43
1 0.21 59.8 61.0 326 3.89 3.84 2.31

여러 변수의 일괄 계산은 .apply() 메서드와 lambda 함수를 활용하였다. 특히 “carat”과 “price”변수의 표준편차와 변동계수가 크게 달라진 것을 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
df_num.std()
## carat 0.474011
## depth 1.432621
## table 2.234491
## price 3989.439738
## x 1.121761
## y 1.142135
## z 0.705699
## dtype: float64


df_num.apply(lambda x: x.std() / x.mean() * 100)
## carat 59.404391
## depth 2.320057
## table 3.888966
## price 101.440196
## x 19.573023
## y 19.916811
## z 19.942129
## dtype: float64
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×