728x90
반응형

중심경향치(Center Tendency)

 이전 포스트에서는 최빈값, 중앙값을 구하는 방법에 대해 알아보았다. 이번 포스트에서는 가장 자주 사용되는 중심경향치인 산술 평균과 기하 평균, 조화 평균에 대해서 알아보도록 하자.

 

 

 

1. 산술 평균(Arithmetic mean)

  • 주어진 수의 합을 수의 개수로 나눈 값인 산술 평균은, 통계학에서 가장 많이 사용되는 중심경향치로, 단순하게 평균(Mean)이라고 부르기도 한다.
  • 중앙값처럼 산술 평균 역시, 양적 변수를 대상으로만 사용할 수 있다.

 

1.1. 산술평균의 정의

  • $N$ 개로 구성된 모집단의 관찰값 $X_1, X_2, X_3, ..., X_N$이 있다고 할 때, 모집단의 평균 $\mu$는 다음과 같이 구한다.

$$\mu = \frac{X_1 + X_2 + X_3 + \cdots X_N}{N} = \frac{1}{N}\sum_{i=1}^{N}X_i$$


  • 통계학에서 같은 값을 구한다고 할지라도 모집단을 대상(모수)으로 하는지, 표본집단을 대상(통계량)으로 하는지에 따라, 공식이 약간 달라지게 된다.
  • 평균은 모수와 통계량 모두 공식이 동일하지만, 사용하는 기호가 $\mu$에서 $\bar{x}$로 달라진다.

 

1.2 모평균과 표본평균이 동일한 이유.

 앞서 산술평균에서 단순하게 모수와 통계량의 공식은 동일하지만, 모수는 $\mu$로 통계량은 $\bar{x}$로 사용하는 기호가 다르다고 했다. 이는, 모집단의 평균과 표본 집단의 평균값이 같다는 소리인데, 어떻게 이 것이 가능한 것일까?

  • 먼저, 표본 집단을 완전 무작위로 추출한다고 가정해보자.
  • 이 무작위 추출은 복원 추출(뽑은 값을 또 뽑을 수 있음)을 가정한다.
  • 복원 추출을 가정한 완전 무작위 표본 추출이므로, 원소들이 뽑히는 사건은 서로 독립이다.

  • 위 증명을 보면, 아주 쉽게 표본평균의 기댓값이 모평균과 같다는 것을 찾아내었다.
  • 중간에 나온 원소가 1개인 표본 집합의 기댓값이 모평균과 같다는 이유는 무엇일까?

  • 위와 같은 이유로, 원소가 1개인 표본평균의 분산이 모집단과 동일하다.
  • 즉, 표본을 무수히 많이 뽑게 된다면, 표본 평균의 기댓값은 모평균과 동일하게 된다.

 

 

 

 

 

2. 파이썬으로 산술 평균 구하기.

2.1. 도수분포표로 평균 구하기

  • 중앙값과 마찬가지로, 도수분포표로 평균을 추정할 수는 있으나, 실제 평균과 일치하지는 않는다.
  • 원시 자료를 가지고 있는 상황이라면, 굳이 도수분포표를 구하고, 부정확한 평균을 추론할 필요는 없으나, 혹시나 구할 수 있는 데이터가 도수분포표밖에 없는 상황이 있을 수도 있으므로, 이를 가정하여, 도수분포표로 평균을 구하는 방법에 대해 알아보도록 하겠다.
  • 사용할 데이터와 양적 변수의 범주화된 도수분포표 변환 함수는 다음과 같다.

Data_for_study.csv
3.39MB

import pandas as pd
import numpy as np
def make_freq_table(data, column):
    """
    -------------------------------------------------------------------------------
    지정된 변수의 관찰값이 20개보다 많은 경우, 10개의 등급을 가진 데이터를 반환한다.
    10개의 등급은 동일한 간격으로 자른 것이다.
    -------------------------------------------------------------------------------
    Input: DataFrame, str
    Output: DataFrame
    """
    # array 생성
    target_array = data[column].to_numpy()

    # class의 수가 20개보다 많은 경우 10개로 줄인다.
    class_array = np.unique(target_array)

    if len(class_array) > 20:

        min_key = class_array.min()
        max_key = class_array.max()
        split_key = np.linspace(min_key, max_key, 10)

        a0 = str(round(split_key[0], 2)) + " 이하"
        a1 = str(round(split_key[0], 2)) + " ~ " + str(round(split_key[1], 2))
        a2 = str(round(split_key[1], 2)) + " ~ " + str(round(split_key[2], 2))
        a3 = str(round(split_key[2], 2)) + " ~ " + str(round(split_key[3], 2))
        a4 = str(round(split_key[3], 2)) + " ~ " + str(round(split_key[4], 2))
        a5 = str(round(split_key[4], 2)) + " ~ " + str(round(split_key[5], 2))
        a6 = str(round(split_key[5], 2)) + " ~ " + str(round(split_key[6], 2))
        a7 = str(round(split_key[6], 2)) + " ~ " + str(round(split_key[7], 2))
        a8 = str(round(split_key[7], 2)) + " ~ " + str(round(split_key[8], 2))
        a9 = str(round(split_key[8], 2)) + " 이상"
        new_index = [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]


        target_array= np.where(target_array <= split_key[0], 0,
                               np.where((target_array > split_key[0]) & (target_array <= split_key[1]), 1,
                                        np.where((target_array > split_key[1]) & (target_array <= split_key[2]), 2,
                                                 np.where((target_array > split_key[2]) & (target_array <= split_key[3]), 3,
                                                          np.where((target_array > split_key[3]) & (target_array <= split_key[4]), 4,
                                                                   np.where((target_array > split_key[4]) & (target_array <= split_key[5]), 5,
                                                                            np.where((target_array > split_key[5]) & (target_array <= split_key[6]), 6,
                                                                                     np.where((target_array > split_key[6]) & (target_array <= split_key[7]), 7,
                                                                                              np.where((target_array > split_key[7]) & (target_array <= split_key[8]), 8, 9)))))))))


    # 도수분포표 생성
    freq_table = pd.DataFrame(pd.Series(target_array).value_counts(), columns = ["freq"])
    freq_table.index.name = column

    freq_table.sort_index(inplace = True)
    freq_table["ratio"] = freq_table.freq / sum(freq_table.freq)
    freq_table["cum_freq"] = np.cumsum(freq_table.freq)
    freq_table["cum_ratio"] = np.round(np.cumsum(freq_table.ratio), 2)
    freq_table["ratio"] = np.round(freq_table["ratio"], 2)

    if "new_index" in locals():
        freq_table.index = new_index
        freq_table.index.name = column

    return freq_table
  • 키에 대하여 범주화된 도수분포표를 뽑아보자.
Rawdata = pd.read_csv("Data_for_study.csv")
make_freq_table(Rawdata, "키")

  • 범주화된 도수분포표를 이용한 평균 계산은 각 등급(Class)의 중앙값에 각 빈도를 곱해 평균을 계산한다.
  • 위와 같이 136 이하, 189.33 이상이 존재하는 경우, 두 등급에 속하는 빈도가 전체에서 차지하는 비중이 매우 작으므로, 단순하게 우리가 알고 있는 136, 189.33에 대하여 빈도를 곱하거나, 이상치로 보고 제거해도 된다.
  • 애초에 도수분포표를 이용해 중심경향치를 계산하는 것은 정확한 값을 얻기 위해서가 아닌, 대략적인 값을 얻기 위해서이므로, 이번에는 저 두 값에 그냥 빈도를 곱하도록 하겠다.
>>> ((136.0*1)+((142.67+136.0)/2*70)+((149.33+142.67)/2*869)+((156.0+149.33)/2*7079)+
    ((162.67+156.0)/2*14131)+((169.33+162.67)/2*14640)+((176.0+169.33)/2*12492)+
    ((182.67+176.0)/2*5118)+((189.33+182.67)/2*1241)+(189.33*107))/55748
    
165.47919010547466
  • 위 코드처럼 값을 하나하나 쓰기 싫은 사람을 위해, pandas의 str 모듈을 사용해 계산하는 방법도 보도록 하겠다.
>>> 키_도수분포표 = make_freq_table(Rawdata, "키")
>>> 키_도수분포표.reset_index(drop=False, inplace=True)

# 1 부터 8번 행까지 처리
>>> 키1_8_array = 키_도수분포표[1:9].키.str.split(" ~ ", expand=True).values.astype("float")
>>> 키1_8_sum = np.sum(((키1_8_array[:,0] + 키1_8_array[:,1])/2) * 키_도수분포표[1:9].freq.to_numpy())

# 0, 9 행 처리
>>> 키0_9_array = 키_도수분포표.loc[[0,9]].키.str.partition(" ")[0].to_numpy().astype("float")
>>> 키0_9_sum = np.sum(키0_9_array * 키_도수분포표.loc[[0,9]].freq.to_numpy())

>>> 평균키 = (키1_8_sum + 키0_9_sum)/키_도수분포표.freq.sum()
>>> 평균키
165.4791901054746
  • 0번행과 9번행은 1~8번행까지와 구간의 패턴이 다르므로, 이를 분리하여, 원하는 값만 추출하여 평균을 구했다.
  • 위에서 숫자를 일일이 복사 붙여넣기한 것과 같은 결과가 나왔다.

 

2.2. 파이썬으로 산술 평균 구하기

  • 원시자료를 가지고 있는 경우, 위 같이 번거로운 과정 없이 아주 편하게 평균을 구할 수 있다.
>>> Rawdata.키.mean()
165.5272655521264

>>> np.mean(Rawdata.키.to_numpy())
165.52726555212743
  • Series.mean()은 pandas 함수로 평균을 구하는 것이다.
  • np.mean(array)는 numpy 함수로 평균을 구하는 것이다.
  • 실제 평균과 위에서 도수분포표를 이용해서 추론한 평균이 꽤 유사한 것을 알 수 있다.

 

 

 

 

 

3. 기타 산술 평균

3.1. 가중 평균(Weighted mean)

  • 서로 다른 집단에 대하여, 다른 가중치를 부여하여 평균을 내는 방법
  • 집단의 크기가 서로 다르거나, 다른 점수 배점을 가질 때, 사용하는 방법이다.
  • 예를 들어, A반은 10명, B반은 40명일 때, A반과 B반의 평균을 동일하게 생각하고 $\bar{X_A}$와 $\bar{X_B}$를 더하고 평균을 내면 안 된다.
  • 이 경우, A반은 전체에서 차지하는 비중인 $\frac{10}{50}$만큼 평균 $\bar{X_A}$ 곱해주고, B반은 전체에서 차지하는 비중인 $\frac{40}{50}$만큼 평균 $\bar{X_B}$에 곱해주고 이 둘을 더해줘야 한다.
  • 즉, A반의 평균이 $\bar{X_A} = 60$이고, B반의 평균이 $\bar{X_B} = 70$이라면, 두 반의 평균은 $\frac{60+70}{2}=65$이 아닌, $0.2\bar{X_A} + 0.8\bar{X_B}= 0.2 * 60 + 0.8 * 70 = 68$점이 된다.

3.2. 절삭 평균(Trimmed mean)

  • 이상치인 극단적으로 크거나 작은 값을 제거하고 평균을 내는 방법이다.
  • 예를 들어, A라는 마을의 실제 평균 월급은 250만 원인데, 그 동네에 빌 게이츠가 살아서 평균 월급이 1,000만 원이 나와버린다면, 그 평균은 실제 데이터가 모여 있는 곳을 보여준다고 할 수 없다.
  • 물론, 이상치를 제거한다면, 이상치가 제거된 것을 집단의 크기에도 반영해야 한다.

 

 

 

 

4. 기하 평균(Geometric mean)

  • 기하 평균은 $n$개의 양수 값을 모두 곱하고, $n$ 제곱근을 해준 것이다.
  • 기하 평균은 지금까지 우리가 다뤘던 변수들과 달리 곱셈으로 계산하는 값에서 사용된다.
  • 변수가 비율로 구성된 경우, 기하 평균을 사용하면 된다.
  • $n$ 개로 구성된 모집단의 관찰 값 $a_1, a_2, a_3, ..., a_n$이 있다고 할 때, 기하 평균은 다음과 같이 구한다.

$$(\prod_{i=1}^{n}a_i)^{\frac{1}{n}} = (a_1\cdot a_2 \cdot a_3\cdots a_n)^{\frac{1}{n}}=\sqrt[n]{a_1\cdot a_2 \cdot a_3\cdots a_n}$$


  • 앞서 보았던 산술평균은 합의 평균이고, 기하 평균은 곱의 평균이다.
  • 기하평균의 대상인 변수의 모든 관찰 값은 양수여야 한다(제곱근을 사용하므로).
  • 로그 항등식을 사용하여 기하평균 공식을 변환시키면, $f(n) = ln x$일 때의 일반화된 f-평균이 만들어진다.

$$ln(a_1\cdot a_2 \cdot a_3\cdots a_n)^{\frac{1}{n}} = \frac{lna_1 + lna_2 + lna3 + \cdots + lna_n}{n}$$


 

4.1 파이썬으로 기하평균 구하기

  • 아래와 같은 데이터가 있다고 가정해보자.
salary = [0.85, 1.1, 1.5, 0.95, 2.0, 1.05]
  • 해당 데이터는 월급 200만 원을 1로 놓고, 6명의 월급의 비율을 본 것이다.
  • 즉, $a_1$은 $200*0.85=170$만원을 월급으로 받고, $a_2$는 $200*1.1=220$만원을 월급으로 받는다는 의미다.
  • 위 데이터의 기하 평균은 다음과 같다.
>>> (0.85*1.1*1.5*0.95*2.0*1.05)**(1/6)
1.187064439031504

 

4.2. Numpy로 구하기

  • 반복문을 사용하는 방법 말고 기하평균을 Numpy로 구하는 방법은 크게 2가지가 있다.
  1. array의 모든 원소를 곱하고, 출력된 스칼라에 n 제곱근 씌우기
  2. array를 모두 로그 치환하고, 그에 대한 산술 평균을 구한 후, 지수로 원 상태로 만들어주기

4.2.1. 방법 1.

# 방법 1.
>>> salary_A = np.array(salary)
>>> np.prod(salary_A)**(1/len(salary_A))
1.187064439031504
  • np.prod(array): 배열의 모든 인자들을 곱한다.

4.2.2. 방법 2.

  • 자연로그의 평균을 구하고, 아래 로그의 성질을 사용하여, 기하 평균을 구하는 방법도 있다.

$$\log_xy = A \rightarrow x^A = y$$

# 방법 2
>>> np.exp(1) ** (np.mean(np.log(salary_A)))
1.1870644390315037
  • np.exp(1): 자연로그의 밑인 2.718281...이다.
  • np.log(array): array의 모든 원소를 자연로그로 변환시킨다.

 

4.3. statistics 라이브러리 사용하기

>>> import statistics as stat
>>> stat.geometric_mean(salary_A)
1.187064439031504
  • statistics 라이브러리는 굉장히 많은 수학적 통계 계산 함수를 제공한다.
  • 개인적으로는 statistics 함수를 사용하기보다는 numpy가 성능이 더 좋으므로, numpy를 사용하길 추천한다.

 

 

 

 

 

5. 조화 평균(Harmonic mean)

  • 조화 평균은 주어진 값들의 역수의 산술 평균의 역수다.
  • 평균 변화율을 구할 때 주로 사용한다.
  • $n$ 개로 구성된 모집단의 관찰 값 $a_1, a_2, a_3, ..., a_n$이 있다고 할 때, 조화 평균은 다음과 같이 구한다.

$$H = \frac{n}{\frac{1}{a_1} + \frac{1}{a_2} + \frac{1}{a_3} + \cdots + \frac{1}{a_n}}$$


  • 조화평균은 속도와 같은 변화율의 평균을 구할 때, 매우 유용하다.
  • 예를 들어, 전체 거리의 절반은 40km/h로 이동하고, 나머지 절반을 60km/h로 이동하였다면, 평균 속력은 산술 평균인 50km/h가 아닌 조화 평균인 48km/h가 된다.
  • 동일한 거리에 대하여 소모된 시간이 다르므로, 단순하게 산술 평균을 구한다면, 평균 속력을 구할 수 없다.
  • 위와 같은 경우엔, 시간의 차원에서 평균을 구해야하므로, 시간에 대하여 값을 바꿔주고, 평균을 구한 후, 다시 속력으로 바꿔보자.
  • 거리를 $S$라 가정하고, 속도를 $V$라고 가정 하자.

 

5.1. 변화율(Rate of change)

  • 두 변수의 변화 정도를 비율로 나타낸 것이다.
  • 미분에서 $\frac{dy}{dx}$라는 단어가 나오는데, 이는 변수 $x$에 대한 변수 $y$의 변화율을 의미한다.
  • 평균변화율(Average rate of change):
    어떤 함수 $f(x)$가 있다고 할 때, 두 점 $A(a, f(a)), B(b, f(b))$에 대하여(단, $a<b$이다.), 두 점을 이어 만든 직선의 기울기를 말한다.
  • 함수 $y=f(x)$에서 $x$의 값이 $a$부터 $a + \bigtriangleup x $까지 변한다고 하면, 아래 식을 $[a, a+\bigtriangleup x]$에서의 $y$의 평균변화율이라 한다.

$$\frac{\bigtriangleup y}{\bigtriangleup x} = \frac{f(a+\bigtriangleup x) - f(a)}{\bigtriangleup x}$$

 

5.2. 파이썬으로 조화 평균을 구해보자

V_array = np.array([20, 30, 50, 30, 60, 40, 80]) 
  • 다음과 같은 속도 데이터가 있다고 가정해보자.
  • 조화 평균을 사용하여, 평균 속력을 구해보자.

5.2.1.  Numpy로 구해보자.

  • 조화 평균은 역수 평균의 역수이므로, numpy의 Broadcast를 사용하면 쉽게 구할 수 있다.
>>> 1/(np.mean(1/V_array))
36.68122270742358

5.2.2. statistics 라이브러리 사용하기

>>> stat.harmonic_mean(V_array)
36.68122270742358

 

 

 

 

 

6. 기하 평균과 조화 평균의 주의사항

  • 0인 표본 값이 존재하는 경우, 사용할 수가 없다.
    • 기하평균은 곱의 평균이므로, 원소에 0이 있는 경우 곱하여 0이 된다.
    • 조화 평균은 역수의 평균의 역수인데, 0의 역수는 무한대로 발산한다.
  • 표본 값이 모두 양수여야 한다.
    • 기하평균은 비율, 배수에 대한 것인데, 음수가 나올 수가 없다.
    • 조화수열의 대상인 변화율의 음수는 벡터로써 방향이 반대를 의미한다.
  • 변수가 비율 혹은 배수이지만, 각 표본 값이 독립적일 때 사용할 수 있다.
    • 표본 값끼리 곱했을 때, 어떠한 의미도 갖지 않아야 서로 독립적이라 할 수 있다.

 

728x90
반응형
728x90
반응형

중심경향치(Center Tendency)


◎ 중심경향치: 관찰된 자료들이 어디에 집중되어 있는지를 나타낸다.


 통계학은 기본적으로 데이터가 어디에 모이고, 얼마나 흩어지는지를 통해서 데이터의 성격을 파악한다. 중심경향치는 데이터가 어디에 모이는지를 보는 것으로, 최빈값, 중앙값, 평균 등의 다양한 지표를 이용하여, 데이터가 모인 곳을 찾아낸다.

 그렇다면, 그 데이터가 모이고 흩어진다는 것이 대체 무슨 말일까? 이를 알기 위해, 이전 포스트에서 학습했던 내용을 바탕으로 이를 눈으로 확인해보자.

 

 

 

 

0. 데이터가 모이고 흩어진다는 것은 무엇일까?

  • 이전 포스트에서 사용했던 데이터를 가지고 오고, 모든 변수들을 히스토그램으로 시각화해보자.

Data_for_study.csv
3.39MB

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
Rawdata = pd.read_csv("Data_for_study.csv")
plt.rc('font', family='NanumGothic')
Rawdata.hist(figsize=(16,25), layout=(5,3), grid=False,density=True)

plt.show()

  • 위 코드는 pandas와 matplotlib.pyplot 두 가지를 사용하여, DataFrame 내에 있는 변수들을 시각화해주며, 히스토그램은 그 변수가 무엇이든 간에, 그 변수의 빈도를 이용해 그래프를 그린다. 또한, bins 파라미터를 통해, 키, 몸무게 같은 비율 척도는 실제 형태보다 단순화시켜, 모든 변수들의 추이를 쉽게 파악할 수 있다.
  • 위 히스토그램들을 보면, "주중_인터넷이용시간"은 주로 0 ~ 100 사이에 가장 많은 데이터가 모여 있으며, 흩어진 정도는 그리 크지 않다는 것을 알 수 있다.
  • 이러한 변수별 데이터가 어디에 모여있는지를 하나의 값으로 확인할 수 있는 방법이 바로 중심경향치다.

 

 

 

 

1. 최빈값(Mode)


◎ 최빈값(Mode): 빈도수가 가장 큰 관찰값


  • 도수분포표에서 가장 값이 많이 모여 있는 관찰 값을 의미한다.
  • 양적 자료, 질적 자료에서 모두 사용되나, 일반적으로 질적 자료에서 더 자주 사용된다.
  • 위에서 불러온 데이터에서 명목변수: "흡연경험", 등간변수(리커트 5점 척도): "스트레스인지", 비율 변수: "몸무게"에 대하여 최빈값을 구해보자.

 

1.1. 도수분포표를 사용하여 최빈값 구하기

  • 최빈값을 구하는 방법은 도수분포표를 구하고, 가장 빈도수가 높은 관찰 값을 선택하는 방법이 있다.
  • 연속형 변수를 구간 화하는 것은 꽤 귀찮은 일이므로, 20개 이상의 관찰 값을 갖는 경우, 10개의 구간을 갖는 변수로 변환하여 도수분포표를 출력하는 함수를 만들었다.
def make_freq_table(data, column):
    """
    -------------------------------------------------------------------------------
    지정된 변수의 관찰값이 20개보다 많은 경우, 10개의 등급을 가진 데이터를 반환한다.
    -------------------------------------------------------------------------------
    Input: DataFrame, str
    Output: DataFrame
    """
    # array 생성
    target_array = data[column].to_numpy()

    # class의 수가 20개보다 많은 경우 10개로 줄인다.
    class_array = np.unique(target_array)

    if len(class_array) > 20:

        min_key = class_array.min()
        max_key = class_array.max()
        split_key = np.linspace(min_key, max_key, 10)

        a0 = str(round(split_key[0], 2)) + " 이하"
        a1 = str(round(split_key[0], 2)) + " ~ " + str(round(split_key[1], 2))
        a2 = str(round(split_key[1], 2)) + " ~ " + str(round(split_key[2], 2))
        a3 = str(round(split_key[2], 2)) + " ~ " + str(round(split_key[3], 2))
        a4 = str(round(split_key[3], 2)) + " ~ " + str(round(split_key[4], 2))
        a5 = str(round(split_key[4], 2)) + " ~ " + str(round(split_key[5], 2))
        a6 = str(round(split_key[5], 2)) + " ~ " + str(round(split_key[6], 2))
        a7 = str(round(split_key[6], 2)) + " ~ " + str(round(split_key[7], 2))
        a8 = str(round(split_key[7], 2)) + " ~ " + str(round(split_key[8], 2))
        a9 = str(round(split_key[8], 2)) + " 이상"
        new_index = [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]


        target_array= np.where(target_array <= split_key[0], 0,
                               np.where((target_array > split_key[0]) & (target_array <= split_key[1]), 1,
                                        np.where((target_array > split_key[1]) & (target_array <= split_key[2]), 2,
                                                 np.where((target_array > split_key[2]) & (target_array <= split_key[3]), 3,
                                                          np.where((target_array > split_key[3]) & (target_array <= split_key[4]), 4,
                                                                   np.where((target_array > split_key[4]) & (target_array <= split_key[5]), 5,
                                                                            np.where((target_array > split_key[5]) & (target_array <= split_key[6]), 6,
                                                                                     np.where((target_array > split_key[6]) & (target_array <= split_key[7]), 7,
                                                                                              np.where((target_array > split_key[7]) & (target_array <= split_key[8]), 8, 9)))))))))


    # 도수분포표 생성
    freq_table = pd.DataFrame(pd.Series(target_array).value_counts(), columns = ["freq"])
    freq_table.index.name = column

    freq_table.sort_index(inplace = True)
    freq_table["ratio"] = freq_table.freq / sum(freq_table.freq)
    freq_table["cum_freq"] = np.cumsum(freq_table.freq)
    freq_table["cum_ratio"] = np.round(np.cumsum(freq_table.ratio), 2)
    freq_table["ratio"] = np.round(freq_table["ratio"], 2)

    if "new_index" in locals():
        freq_table.index = new_index
        freq_table.index.name = column

    return freq_table
  • np.linspace(start, end, num): start부터 end까지 num개를 일정한 간격으로 자르는 함수로, 아주 간편하게, 연속형 데이터를 범주화할 수 있다.
  • 흡연경험의 도수분포표
make_freq_table(Rawdata, "흡연경험")

  • 명목 변수인 흡연경험의 최빈값은 1.0인 것을 알 수 있다. 청소년건강행태조사 이용지침서 참고 시, "없다"가 88%로 가장 많이 등장하였다.
make_freq_table(Rawdata, "스트레스인지")

  • 등간 변수(리커트 척도)인 스트레스인지의 최빈값은 3.0인 것을 알 수 있다. 청소년건강행태조사 이용지침서 참고 시, "조금 느낀다"가 가장 많이 등장하였다.
make_freq_table(Rawdata, "몸무게")

  • 비율 변수인 몸무게에서 제일 많이 등장한 등급(Class)는 45.87 ~ 56.3 kg인 것을 알 수 있다. 표본집단인 중·고등학생 중 36%가 해당 구간에 존재한다.

 

1.2. 파이썬을 이용하여 최빈값 구하기

  • 도수분포표를 일일이 구하고, 최빈값을 구하는 일은 꽤 번거로운 일이다.
  • 데이터 분석에서 기본적으로 사용되는 라이브러리 중 하나인 pandas는 다양한 기본 함수를 제공하여, 이러한 문제를 쉽게 해결할 수 있게 해 준다.
  • Series.mode(): 최빈값을 출력한다.
>>> 흡연경험_최빈값 = Rawdata.흡연경험.mode()
>>> 흡연경험_최빈값
0    1.0
dtype: float64


>>> 스트레스인지_최빈값 = Rawdata.스트레스인지.mode()
>>> 스트레스인지_최빈값
0    3.0
dtype: float64


>>> 몸무게_최빈값 = Rawdata.몸무게.mode()
>>> 몸무게_최빈값
0    60.0
dtype: float64
  • Series.mode()는 Series로 결과를 출력한다.
  • 양적 변수라 할지라도, 바로 최빈값을 찾는 경우, 굳이 도수분포표를 만드는 수고를 할 필요가 없으므로, 구간을 만드는 수고를 하지 않아도 된다.
  • 이번에는, 최빈값에 해당하는 빈도수를 출력해보자.
# 최빈값과 최빈값 도수 출력
def mode_value_printer(data, column):
    
    mode_ = data[column].mode().values[0]
    freq =len(data[data[column] == mode_])
    
    print(f"{column} - 최빈값: {mode_}, 도수: {freq}")
>>> mode_value_printer(Rawdata, "흡연경험")
흡연경험 - 최빈값: 1.0, 도수: 48995

>>> mode_value_printer(Rawdata, "스트레스인지")
스트레스인지 - 최빈값: 3.0, 도수: 22915

>>> mode_value_printer(Rawdata, "몸무게")
몸무게 - 최빈값: 60.0, 도수: 2350
  • 보시다시피 pandas 기본 함수를 사용하면, 아주 쉽게 최빈값과 그에 해당하는 도수를 찾을 수 있다.
  • 그러나, 양적 변수, 그중에서도 관찰 값이 매우 많은 변수는 범주화를 시키는 것과, 단순하게 가장 많이 등장한 관찰 값을 찾는 것이 다른 결과를 가져온다.
  • 때문에 양적 변수에서는 중심경향치를 확인하고자 할 때, 최빈값보다는 평균, 중위수와 같은 다른 값을 추출하는 경우가 더 많다(물론, 연구자의 의도에 따라 최빈값 역시 필요할 수 있으므로, 절대 양적 변수에 최빈값을 사용하지는 않는다고 생각해선 안된다).

 

 

 

 

2. 중앙값(Median)


◎ 중앙값(Median): 수치로 된 자료를 크기 순서대로 나열할 때, 가장 가운데에 위치하는 관찰값을 말한다.

$$Md = \frac{(n+1)}{2}$$


  • 중앙값은 순서, 일정한 간격을 가지고 있는 양적 변수에 대해서만 사용 가능하며, 말 그대로 한 변수 내 모든 관찰값들의 중앙에 있는 값을 가리킨다.
  • 중앙값에서 이슈라고 할 수 있는 것은 관찰값의 수가 짝수인지 홀수인지로, 아래 예시를 보자.

$$ A = {1, 3, 4, 7, 8, 10, 11, 15, 16}$$

  • 위 예시 같이 집합 내 원소의 수가 홀수인 경우에는 그냥 $\frac{9+1}{2}=5$에 있는 관찰값을 중앙값으로 하면 되지만, 짝수인 경우는 조금 다르다.

$$ B = {2, 4, 6, 7, 9, 10} $$

  • 위 예시 같이 집합 내 원소의 수가 짝수인 경우에는 $\frac{6+1}{2} = 3.5$가 되어, 3.5번째에 있는 관찰값을 중앙값으로 사용해야 하나, 3.5번째 관찰값은 존재할 수 없다.
  • 이 때는, 3번째 관찰값인 6과 4번째 관찰값인 7의 평균을 중앙값으로 사용한다. 즉, $\frac{6+7}{2} = 6.5$가 중앙값이 된다.

 

2.1. 도수분포표를 이용하여 연속형 데이터의 중앙값 구하기

  • 중앙값은 관찰값들의 중앙에 있는 값이므로, 도수분포표를 사용하지 않고 구할 수 있고, 그것이 정석이다.
  • 그러나, 항상 모든 관찰값들을 알 수 있는 것이 아니고, 때에 따라서는 도수분포표를 사용해서 중앙값을 유추해야할 필요도 있다.
    (물론, 원시자료를 손 델 수 있다면, 굳이 그럴 필요는 없지만!)
  • 이번에는 범주화된 연속형 데이터의 도수분포표를 이용해서 중앙값을 구해보자.
  • 위에서 만든 make_freq_table함수를 이용해서 키에 대한 도수분포표를 만들어보자.
make_freq_table(Rawdata, "키")

  • 총데이터의 양은 55748개이며, 55748의 중앙값은 $\frac{55748+1}{2} = 27874.5$이다. 즉, 27,874.5번째에 있는 값이 있는 구간이 중앙값이다.
  • 누적빈도를 볼 때, 27,874.5는 162.67 ~ 169.33 구간에 존재하므로, 중앙값이 있는 구간은 162.67 ~ 169.33임을 알 수 있다.
  • 이 구간 안에서 비율을 사용해서 중앙값을 유추해보자

  • 위 방법처럼 관찰 값의 비율과 빈도의 비율을 이용하면, 중위수를 유추해낼 수 있다.
  • 실제 중위수랑 비교해보자.
>>> Rawdata.키.median()
165.0
  • 실제 중위수와 도수분포표를 사용해서 유추한 중위수가 상당히 유사한 것을 알 수 있다.

 

2.2. 파이썬을 이용하여 중위수 구하기

  • 파이썬을 이용해 중위수를 구하는 것은 정말 단순하다.
>>> Rawdata.스트레스인지.median()
3.0

>>> Rawdata.몸무게.median()
57.0
  • Series.median()을 사용하면, 중위수를 구할 수 있다.
  • numpy 함수를 사용하는 경우는 다음과 같다.
>>> np.median(Rawdata.스트레스인지.to_numpy())
3.0

>>> np.median(Rawdata.몸무게.to_numpy())
57.0
  • np.median(array)를 사용해서 중위수를 구하면 된다.

 

 

 

 지금까지 최빈값과 중앙값을 구해보았다. 다음 포스트에서는 가장 대표적인 중심경향치인 평균에 대해 자세히 알아보도록 하겠다.

728x90
반응형
728x90
반응형

도수분포표와 시각화

 앞서 도수분포표에서 봤듯, 도수분포표는 수집한 데이터의 분포를 알기 위해 사용한다. 그러나 여전히 숫자만으로 데이터를 파악하기 때문에 데이터의 분포를 명확하게 이해하기 어려울 수도 있다. 도수분포표를 시각화한다면, 보다 쉽게 데이터의 분포를 파악할 수 있다.

  • 도수분포표의 시각화이므로, 들어간 데이터의 도수(빈도)를 시각화 하는 것이다.
  • 파이썬으로 도수분포표를 시각화하는 방법은 크게 두가지가 있다.
  1. 범주화된 데이터를 사용해서 히스토그램을 만들기
  2. 도수분포표 생성 후, 도수분포표를 기반으로 그래프 그리기
  • 개인적으로 추천하는 방법은 도수분포표를 먼저 생성하고, 그래프를 그리는 것으로, 도수분포표 연산이 한 번 이루어지고 나면, 나머지 과정은 자원을 거의 먹지 않는다.
  • 도수분포표만 만들면, 이를 이용해서 히스토그램(막대그래프 사용), 도수분포다각형, 누적도수분포곡선 3가지를 모두 쉽게 그릴 수 있다.

 

 

 

 

1. 히스토그램

  • 히스토그램은 가장 대표적인 도수분포표의 시각화 방법이다.
  • 위에서 설명한 파이썬으로 도수분포표 시각화를 하는 첫 번째 방법으로, 원본 데이터(범주화가 된)를 사용해서 히스토그램을 그리는 것이다.
  • 히스토그램은 막대그래프로 한 변수를 구성하는 각 집단의 빈도를 이용하여, 막대 그래프를 그리는 것이다.
  • 이전 데이터에서 사용했던, 청소년건강행태조사 2019년 데이터에서 일부 변수만 추려낸 데이터를 사용해보자.

Data_for_study.csv
3.39MB

  • "건강인지"를 히스토그램으로 나타내보자.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
Rawdata = pd.read_csv("Data_for_study.csv")
# 한글 사용
plt.rc('font', family='NanumGothic')

# 전체 그래프 크기
fig = plt.figure(figsize=(8, 6))

# 히스토그래프 그리기
plt.hist(Rawdata.건강인지.to_numpy(), bins=9)

# x축 ticks 지정
plt.xticks(np.arange(1, 6), labels=["매우 좋음", "좋음", "보통", "나쁨", "매우 나쁨"])
plt.tick_params(axis="x", direction="in", labelsize = 12, pad = 20)

# title, xlabel, ylabel 지정
plt.title("건강인지 히스토그램", fontsize = 30, pad = 30)
plt.xlabel('건강인지', fontsize = 20, loc = 'center', labelpad = 20)
plt.ylabel('도수', fontsize = 20, rotation = 0, loc='center', labelpad = 30)

plt.show()

  • plt.hist(density=True)로 지정해주면, 빈도가 아닌, 비율로 나타낼 수도 있다.
  • 그러나, 이 비율은 히스토그램 전체를 1로 하는 비율이 아닌, 최대 빈도를 1로 하는 비율이다.
fig = plt.figure(figsize=(8, 6))

plt.hist(Rawdata.건강인지.to_numpy(), bins=9, density=True)
plt.xticks(np.arange(1, 6), labels=["매우 좋음", "좋음", "보통", "나쁨", "매우 나쁨"])
plt.tick_params(axis="x", direction="in", labelsize = 12, pad = 20)

plt.title("건강인지 히스토그램", fontsize = 30, pad = 30)

plt.xlabel('건강인지', fontsize = 20, loc = 'center', labelpad = 20)
plt.ylabel('도수', fontsize = 20, rotation = 0, loc='center', labelpad = 30)


plt.show()

  • 입력된 데이터는 숫자지만, 실제로는 문자인 Factor이므로, label을 문자로 입력하였다.
>>> Rawdata.건강인지.to_numpy()
array([1., 1., 2., ..., 4., 3., 3.])
  • 실제 정의에 맞게 하려면, 다음과 같이 숫자를 원래 형태인 문자로 바꿔주고, 문자 배열에 대한 도수를 히스토그램으로 그려야 한다.
건강인지 = Rawdata.건강인지.to_numpy()
건강인지 = np.where(건강인지==1, "매우 좋음",
                np.where(건강인지==2, "좋음",
                         np.where(건강인지==3, "보통",
                                  np.where(건강인지==4, "나쁨", "매우 나쁨"))))

 

 

 

 

2. 도수분포다각형

  • 도수분포다각형은 히스토그램의 각 중간점을 이어서 그린 것으로, 데이터가 연속적인 경우에 사용한다.
  • 도수분포다각형을 사용하면, 분포의 윤곽이 보다 명확하게 보이며, 빈도의 증감을 보다 명확히 볼 수 있다.
  • 또한, 서로 다른 집단에 대한 도수분포를 같은 그림 위에서 비교할 수 있다는 장점이 있다.
  • 도수분포다각형, 누적도수분포곡선은 도수분포표를 기반으로 그리는 것이 훨씬 쉽다(히스토그램 역시, 이미 생성된 도수분포표를 기반으로 막대그래프로 그리는 것이 추가 연산 시간이 없으므로 쉽다).
  • 이전 포스트에서 만들었던, 16세 남성의 키와 16세 여성의 키를 10cm 간격으로 범주화한 도수분포표를 대상으로 해서 만들어보도록 하자.
  • 총합은 도수분포표를 이해하기 좋게 만든 것이므로, 제거하고, 필요한 각 클래스별 값만 유지하겠다.
def cat_height(array):
    cat_array = np.where(array<=140, "140 이하",
                     np.where((array>140) & (array<=150), "140~150",
                              np.where((array>150) & (array<=160), "150~160",
                                       np.where((array>160) & (array<=170), "160~170",
                                                np.where((array>170) & (array<=180), "170~180",
                                                         np.where((array>180) & (array<=190), "180~190", "190 이상"))))))
    return cat_array
    
    
def Freq_table(array):

    freq_table = pd.DataFrame(pd.Series(array).value_counts(), columns=["freq"])
    freq_table.sort_index(inplace = True)
    freq_table["ratio"] = freq_table.freq / sum(freq_table.freq)
    freq_table["cum_freq"] = np.cumsum(freq_table.freq)
    freq_table["cum_ratio"] = np.round(np.cumsum(freq_table.ratio), 2)
    freq_table["ratio"] = np.round(freq_table["ratio"], 2)

    return freq_table
    
남자_16세_키 = Rawdata[(Rawdata["연령"] == 16) & (Rawdata["성별"] == 1.0)]["키"].to_numpy()
여자_16세_키 = Rawdata[(Rawdata["연령"] == 16) & (Rawdata["성별"] == 2.0)]["키"].to_numpy()

M_DF = Freq_table(cat_height(남자_16세_키))
F_DF = Freq_table(cat_height(여자_16세_키))
fig = plt.figure(figsize=(8, 6))

plt.plot(F_DF.index, F_DF.ratio, label = "Female, 16 years old")
plt.plot(M_DF.index, M_DF.ratio, linestyle = "--", label = "Male, 16 years old")

plt.title("16세 남성 & 여성 키 도수분포다각형",fontsize = 20, pad = 20)
plt.xlabel("키", fontsize = 15)
plt.ylabel("비율", fontsize = 15, rotation = 0, labelpad = 30)
plt.legend(loc="upper right")

plt.show()

  • 생성된 두 집단의 도수분포표를 상대적으로 비교하기 위해, 상대 빈도인 비율을 사용하여 그래프를 그렸다.
  • 도수분포다각형이 히스토그램의 꼭짓점을 연결한 것임을 보기 위해 히스토그램도 뒤에 연하게 그려보자.
fig = plt.figure(figsize=(8, 6))


plt.plot(F_DF.index, F_DF.ratio, label = "Female, 16 years old")
plt.plot(M_DF.index, M_DF.ratio, linestyle = "--", label = "Male, 16 years old")

plt.bar(F_DF.index, F_DF.ratio, alpha = 0.4, color = "blue")
plt.bar(M_DF.index, M_DF.ratio, alpha = 0.4, color = "yellow")

plt.title("16세 남성 & 여성 키 도수분포다각형",fontsize = 20, pad = 20)
plt.xlabel("키", fontsize = 15)
plt.ylabel("비율", fontsize = 15, rotation = 0, labelpad = 30)
plt.legend(loc="upper right")

plt.show()

  • 동일한 비율을 사용하기 위해 plt에서 histogram 함수가 아닌 막대그래프인 bar를 가지고 왔다.
  • 히스토그램과 막대그래프는 본질이 다르지만, 도수분포표를 사용해서 그린다면 히스토그램과 막대그래프는 동일한 결과를 가지고 온다.
    (히스토그램은 데이터가 한 차원만 들어가고, 그 빈도로 그래프를 그린다. 막대그래프는 두 차원의 데이터가 필요하며, 그 두 차원의 데이터를 이용해서 그래프를 그린다)
  • 가지고 있는 전체 데이터를 이용해서 그래프를 그린다면 히스토그램을 사용하고, 이미 도수분포표를 만들었다면, 막대그래프를 그리길 추천한다.

 

 

 

 

3. 누적도수분포곡선

  • 누적도수분포곡선은 위에서 도수분포다각형을 그렸던 방법에서, y축에 들어가는 데이터만 누적 도수로 바꾸면 된다.
  • 이번에도 두 집단을 비교하기 쉽도록, 비율로 구해보도록 하겠다.
fig = plt.figure(figsize=(8, 6))


plt.plot(F_DF.index, F_DF.cum_ratio, label = "Female, 16 years old")
plt.plot(M_DF.index, M_DF.cum_ratio, linestyle = "--", label = "Male, 16 years old")

plt.bar(F_DF.index, F_DF.cum_ratio, alpha = 0.4, color = "blue")
plt.bar(M_DF.index, M_DF.cum_ratio, alpha = 0.4, color = "yellow")

plt.title("16세 남성 & 여성 키 누적도수분포곡선",fontsize = 20, pad = 20)
plt.xlabel("키", fontsize = 15)
plt.ylabel("비율", fontsize = 15, rotation = 0, labelpad = 30)
plt.legend(loc="lower right")

plt.show()

 

 

 

 지금까지 파이썬을 사용해서 도수분포표의 시각화를 해보았다. 개인적으로는 도수분포표를 먼저 구하고, 그 도수분포표를 바탕으로 시각화를 진행하길 바란다.

728x90
반응형
728x90
반응형

도수분포표(Frequency Distribution Table)


◎ 도수분포표: 수집된 데이터를 분류한 후, 각 분류에 해당하는 데이터의 빈도, 비율 등으로 정리한 표를 말한다.


 앞서 통계학은 크게 기술통계학(Descriptive statistics)과 추론통계학(Inferential statistics) 이 두 가지로 나뉘며, 이 둘은 별개의 존재가 아니라, 기술통계학 > 추론통계학순으로 순차적으로 이루어진다고 하였다.

 기술통계학은 말 그대로 데이터가 가지고 있는 정보를 기술(Describe)하는 것이며, 도수분포표는 데이터의 각 범주별 빈도수와 비율을 이용하여, 데이터를 설명하는 방법으로 기술통계학의 기초가 되는 기법이다.

 백 마디 말보다, 한 번 실제 만들어보는 것이 가장 좋은 방법이니, 실제로 도수분포표를 만들어보고, 도수분포표가 어떻게 생겼고, 도수분포표를 이용해서 무엇을 할 수 있기에 기술통계학의 기초가 되는 것인지 알아보도록 하자.

  • 도수분포표를 학습할 때, 집단을 잘 구분하는 것이 중요하다.
  • 한 변수 안에는 $m$개의 데이터가 존재하는데, 이 $m$개의 데이터를 중복을 제거하면 $n$개의 데이터가 남게 된다($m$ ≥ $n$).
  • 이 중복이 없는 $n$의 데이터는 한 원소 안의 집단(Group), 등급(Class) 두 가지 용어로 부를 수 있는데, 본 포스트에서는 이해하기 쉽도록, 선택된 군은 집단(Group)으로, 한 변수 안의 중복이 제거된 데이터의 군은 등급(Class)라 부르겠다.

 

 

 

 

1. Python을 사용하여, 기본적인 도수분포표를 만들어보자.

1.1. 데이터 가지고 오기

 이전 포스트(참고: "통계 분석을 위한 데이터 준비")에서 생성한 데이터를 기반으로 통계 분석을 진행하도록 하겠다. 해당 데이터는 청소년건강행태조사 2019년 데이터에서 대표적인 16개 변수만 선택하고, 간단하게 결측값을 처리한 데이터다. 보다 상세한 설명이 필요한 경우 위 참고를 보길 바란다.

Data_for_study.csv
3.69MB

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
  • 데이터 분석을 할 때, 기본적으로 사용하는 라이브러리다.
  • pandas는 DataFrame을 이용해, 데이터를 관리하는 모든 과정을 굉장히 편하게 해 준다.
  • numpy는 빠른 수학 연산에 필수인 라이브러리다.
  • matplotlib.pyplot은 시각화에 필수인 라이브러리다.
Rawdata = pd.read_csv("Data_for_study.csv")
Rawdata
  • pd.read_csv("파일이름.csv"): csv 파일을 DataFrame으로 불러온다.

  • 변수(Column)의 수는 총 14개이며, 55,748개의 대상이 들어가 있는 데이터가 불러와졌다.

 

1.2. 질적 변수 도수분포표 만들기

  • 출력된 위 데이터만으로 데이터가 어떻게 생겼고, 그 안에 숨어있는 정보를 찾아내는 것은 불가능에 가깝다.
  • 위 데이터를 가장 쉽게 정리하는 방법이 바로 도수분포표(Frequency distribution table)이다.
  • 성별에 대한 도수분포표를 만들어보겠다.
>>> Rawdata.성별.value_counts()
1.0    29059
2.0    26689
Name: 성별, dtype: int64
  • value_counts(): 시리즈로 빈도표를 출력한다
  • 1은 남자, 2는 여자이므로, 총 55,748명 중 남자가 29,059명, 여자가 26,689명임을 알 수 있다.
  • 비율을 추가해보자.
성별_빈도표 = pd.DataFrame(Rawdata.성별.value_counts())
성별_빈도표.columns = ["freq"]
성별_빈도표["ratio"] = np.round(성별_빈도표.freq/sum(성별_빈도표.freq),2)
성별_빈도표
  • pd.DataFrame.columns: DataFrame의 컬럼명을 조작한다.
  • np.round(array, n): array의 값들을 n의 자리에서 반올림한다.

  • 대한민국의 중, 고등학생을 모집단으로 하는 데이터의 표본집단에서 남성이 차지하는 비중은 52%, 여성이 차지하는 비중은 48% 임을 쉽게 알 수 있다.

 

1.3. 양적 변수 도수분포표 만들기

  • 이번엔 동일한 방법으로 양적 변수인 키에 대해 도수분포표를 만들어보겠다.
키_빈도표 = pd.DataFrame(Rawdata.키.value_counts())
키_빈도표.columns = ["freq"]
키_빈도표["ratio"] = np.round(키_빈도표.freq/sum(키_빈도표.freq),2)
키_빈도표

  • 데이터를 보기 쉽게 만드려고 했는데, 여전히 보기가 어렵다.
  • 키와 같은 양적 변수는 들어갈 수 있는 값이 매우 다양하여 등급(Class)이 많기 때문에 이를 바로 도수분포표로 만들면, 여전히 보기 어렵다. 이를 범주화(Categorization)시켜 단순화해보자.
>>> 키_array = Rawdata.키.to_numpy()
>>> print("min:", 키_array.min())
>>> print("max:", 키_array.max())
min: 136.0
max: 196.0
  • DataFrame.column.to_numpy(): DataFrame의 특정 열 column을 numpy의 array로 변환시킨다.
  • array.min(): 배열의 최솟값
  • array.max(): 배열의 최댓값
  • 최솟값이 136.0cm, 최댓값이 196.0cm이므로, "140 이하", "140~150", "150~160", "160~170", "170~180", "180~190", "190 이상"으로 데이터를 범주화해보자.
키_범주 = np.where(키_array<=140, "140 이하",
                np.where((키_array>140) & (키_array<=150), "140~150",
                         np.where((키_array>150) & (키_array<=160), "150~160",
                                  np.where((키_array>160) & (키_array<=170), "160~170",
                                           np.where((키_array>170) & (키_array<=180), "170~180",
                                                    np.where((키_array>180) & (키_array<=190), "180~190", "190 이상"))))))
                                                    
키_도수분포표 = pd.DataFrame(pd.Series(키_범주).value_counts(), columns=["freq"])
키_도수분포표.sort_index(inplace=True)
키_도수분포표
  • np.where(조건, a, b): 조건에 해당하는 경우 a로 해당하지 않는 경우 b를 반환
  • DataFrame.sort_index(): index로 정렬함.

  • 비율을 추가해보자.
키_도수분포표["ratio"] = np.round(키_도수분포표.freq / sum(키_도수분포표.freq), 2)
키_도수분포표

 

1.4. 누적 빈도, 누적 비율 추가

  • 이번에는 빈도(freq)와 비율(ratio)을 첫 집단부터 차근차근 누적시키는 누적 빈도(Cumulative frequency)와 누적 비율(Cumulative ratio)을 보자.
키_도수분포표["cum_freq"] = np.cumsum(키_도수분포표.freq)
키_도수분포표["cum_ratio"] = np.cumsum(키_도수분포표.ratio)
키_도수분포표

  • np.cumsum(array): array를 주어진 순서대로 누적합

 

 

 

 

2. 도수분포표의 개념 정리

 위에서 만든 도수분포표를 기반으로, 도수분포표의 개념을 정리해 보자.

  • 질적 변수는 일반적으로 구성하고 있는 등급(Class)의 수가 그리 많지 않기 때문에 바로 도수분포표를 생성해도 가시성이 높다. 물론, 질적 변수 역시 구성하고 있는 등급(Class)의 수가 매우 많다면, 재 범주화하여, 그 등급(Class)의 수를 줄여야한다.
    예) 읍, 면, 동 단위로 지역명이 들어가 있는 변수는, 이를 시 단위로 재범주화 할 수 있음
  • 양적 변수로 구성된 데이터는 중복을 제거하더라도, 구성하고 있는 등급(Class)가 매우 많아 도수분포표로 만들더라도, 가시성이 매우 떨어지므로, 변수의 성격에 따라 그 변수의 데이터 분포를 가장 잘 보여줄 수 있는 구간으로 데이터를 범주화시켜 도수분포표를 만든다.

 

  • 각 등급(Class)에서 관찰된 객체의 수를 빈도수 또는 도수(Frequency)라고 하며, $f$로 나타낸다.
  • 각 변수를 구성하는 데이터의 빈도, 비율 등을 파악하기 때문에 이 과정을 빈도 분석(Frequency Analysis)라 하며, 출력된 도수분포표를 빈도표라고도 한다.
  • 빈도 분석을 통해 생성하는 도수분포표 자체도 통계 분석에서 목적이 될 정도로 중요하지만, 일반적으로는 데이터의 형태를 파악하는 기초 자료로 생성하는 경우가 많다.

 

  • 누적 빈도(Cumulative frequency):
    어떤 등급(Class)에 해당하는 빈도를 포함해, 그 이하 또는 그 이상에 있는 모든 빈도를 합친 것
  • 누적 빈도를 사용하게 되면, 특정 등급(Class)에 있는 대상이 전체 데이터에서 차지하는 위치를 알 수 있다. 위 도수분포표를 보면, 중·고등학생 전체 집단에서 키가 170~180에 있는 집단이 전체 대상에서 96%에 위치하고 있음을 알 수 있다.
  • 누적 빈도는 질적 변수에 대해서는 사용하지 않는 것을 추천한다. 양적 변수는 데이터에 순서가 있고, 값과 값 사이의 간격이 일정하므로, 누적 빈도를 통해 대상 등급(Class)의 객관적인 위치를 알 수 있다. 그러나, 명목 변수는 순서가 없고, 순서가 존재하는 서열 변수라 할지라도, 간격이 일정하지 않기 때문에, 대상 등급(Class)이 전체 등급의 어디에 위치하는지 알 수 없다.

 

 

 

 

3. 상대 빈도(Relative frequency) = 비율(Ratio)

  • 위에서 생성한 키에 대한 도수분포표는 표본 집단인 중·고등학교에 재학 중인 청소년을 대상으로 한 것이다.
>>> print("만연령 min:", Rawdata.연령.min())
>>> print("만연령 max:", Rawdata.연령.max())
만연령 min: 12.0
만연령 max: 18.0
  • 대상 집단의 연령 범위는 만 12세~18세이며, 성별이 남, 녀 두 가지가 들어 있기 때문에 단순하게 위 도수분포표를 보고, 해당 집단의 특성을 파악한다면 아래와 같은 정보 전달의 오류가 발생할 위험이 있다.
  • 키 170cm는 12세 여성이란 집단에서는 굉장히 큰 키이지만, 18세 남성이란 집단에서는 그리 큰 키가 아니다. 위 도수분포표는 만 12세 ~ 18세 중·고등학생 표본집단을 대상으로 하였기 때문에 위 도수분포표만으로는 둘을 같게 볼 여지가 있다.
    (물론, 대상을 만 12~18세라고 미리 설명해놨다면, 이런 문제는 발생하지 않는다.)
  • 보다 정밀한 데이터 파악을 위해선, 연구자의 의도를 가장 잘 보여줄 수 있는 도수분포표(빈도표) 생성이 필요하다.
  • 이번에는 만 16세인 사람으로 한정하여, 남성과 여성의 키를 보도록 하자.
def cat_height(array):
    cat_array = np.where(array<=140, "140 이하",
                     np.where((array>140) & (array<=150), "140~150",
                              np.where((array>150) & (array<=160), "150~160",
                                       np.where((array>160) & (array<=170), "160~170",
                                                np.where((array>170) & (array<=180), "170~180",
                                                         np.where((array>180) & (array<=190), "180~190", "190 이상"))))))
    return cat_array
    
    
def Freq_table(array):

    freq_table = pd.DataFrame(pd.Series(array).value_counts(), columns=["freq"])
    freq_table.sort_index(inplace = True)
    freq_table["ratio"] = freq_table.freq / sum(freq_table.freq)
    freq_table["cum_freq"] = np.cumsum(freq_table.freq)
    freq_table["cum_ratio"] = np.round(np.cumsum(freq_table.ratio), 2)

    # 반올림 및 총합 생성
    freq_table.loc["총합"] = [sum(freq_table.freq), sum(freq_table.ratio), "", ""]
    freq_table["ratio"] = np.round(freq_table["ratio"], 2)

    return freq_table
  • 위에서 만들었던, 양적 변수의 범주화(키)와 도수분포표를 출력하는 코드들을 정리하여 별 개의 함수로 만들어놓았으며, 추가로 총합이 계산되도록 코드를 추가하였다.
  • 이러한 코드 함수화를 통해, 코드의 재활용성, 가시성, 유지보수의 용이함 등의 이점을 얻을 수 있다.
남자_16세_키 = Rawdata[(Rawdata["연령"] == 16) & (Rawdata["성별"] == 1.0)]["키"].to_numpy()
여자_16세_키 = Rawdata[(Rawdata["연령"] == 16) & (Rawdata["성별"] == 2.0)]["키"].to_numpy()
Freq_table(cat_height(남자_16세_키))

Freq_table(cat_height(여자_16세_키))

  • 상대 빈도(relative frequency)는 비율(ratio)과 동일하다.
  • 상대 빈도 즉, 비율을 사용하면, 서로 다른 집단에 대하여, 각 범주별 차지하는 비중을 알 수 있게 되므로, 서로 다른 집단을 비교하는데 매우 유용하다.
  • 위 표를 하나로 합쳐보자.
# 성별에 따른 변수명 구분을 위해 column 앞에 특정 문자를 붙여줌
M_DF = Freq_table(cat_height(남자_16세_키))
M_DF = M_DF.add_prefix("M_")
F_DF = Freq_table(cat_height(여자_16세_키))
F_DF = F_DF.add_prefix("F_")

# 병합 및, 결측값은 0으로 채운다.
T_DF = pd.concat([M_DF, F_DF], axis=1).sort_index()
T_DF.fillna(0, inplace=True)

T_DF

  • 위 표를 보면, 남성(M)과 여성(F)의 도수분포표를 비율(ratio)을 이용해서, 두 집단의 규모 차이를 무시하고 비교할 수 있다.
  • 만 16세 남성의 59%는 170~180cm에 존재하며, 만 16세 여성의 50%는 160~170cm에 존재한다는 것을 알 수 있다.

 

 

 

 지금까지 기술통계학의 가장 기초가 되는 빈도 분석(Frequency analysis)의 도수분포표(Frequency distribution table)에 대해 알아보았다.

 빈도 분석은 모든 데이터 분석의 기반이 되며, 데이터의 분포를 파악하고, 연구자의 의도를 대상에게 전달하는 데 있어, 작성하기도 쉽고, 이해하기도 쉬우므로, 강력한 영향을 미친다.

 변수의 수가 무수히 많고, 하나하나의 변수를 구성하는 집단 역시 매우 많기 때문에, 모든 빈도를 보여주는 것보다, 연구자의 의도가 가장 잘 담겨 있는 대상에 대한 도수분포표를 보여주는 것이 매우 중요하며, 도수분포표를 생성하기 전에 자신이 전달하고자 하는 바가 무엇인지? 자신이 전달하고자 하는 바에서 대상 집단이 어떻게 되는지를 명확히 하도록 하자.

728x90
반응형

'Python으로 하는 기초통계학 > 기본 개념' 카테고리의 다른 글

중심경향치(1) - 최빈값, 중앙값  (0) 2021.03.03
도수분포표와 시각화  (0) 2021.03.02
통계 분석을 위한 데이터 준비  (0) 2021.03.01
변수(Variable)  (0) 2021.03.01
통계학이란?  (0) 2021.02.26
728x90
반응형

 처음 통계학을 접하게 되었을 때, 변수(Variable)가 무엇인지 헷갈리는 경우가 꽤 많다. 학교에서 데이터 분석 강의를 하거나, 주변인들이 데이터 분석에 대해 질문을 해올 때, "변수라는 용어를 많이 사용하는데 대체 그 변수가 구체적으로 무엇이냐?"라는 질문을 종종 해온다.

 해당 파트에서 학습할 변수는 분포와 함께 데이터 분석에 있어, 상식으로 사용되는 개념이므로, 꼭 숙지하고 넘어가도록 하자.

 

 

변수(Variable)


 "변수(Variable)"는 우리가 관심 있는 대상이 가지고 있는 속성(Attribute)이다.


 위 한 줄이 가장 쉽게 변수를 설명할 수 있는 말인데, 막연하게 느껴질 수 있으므로, 좀 더 자세히 설명해보도록 하겠다. 이전 포스트("통계학이란? - 1.모집단과 표본집단")에서 "연구자가 관심 있는 대상""모집단"이라고 했다.

 이 모집단이 가지고 있는 속성(Attribute)이 바로 변수다. "속성(Attribute)"은 연구자가 정의할 수 있는 대상이 가지고 있는 성질이며, 동시에 대상을 특정 혹은 정의할 수 있는 개념이다.

 

예시를 통한 설명

  • 당신이 "사람"이라는 대상에 대해 관심이 있다고 가정해보자. 그럼 사람은, 성별, 연령, 국적, 키, 몸무게, 거주지, 최종 학력 등의 속성을 가지고 있다고 할 수 있다.
  • 만약 당신이 특정 속성을 갖는 사람을 찾고 싶다고 해보자. 성별이 여성, 연령이 24살이며 한국 국적을 갖고 있는 사람을 찾는다고 하면, 꽤 광범위하므로 찾기 쉽지 않을 것이다.
  • 여기에 변수를 하나하나 추가해보자. 키가 153cm, 몸무게 54kg, 대전광역시 거주, 대학교 졸업, 원무과에서 근무함.
  • 이런 식으로 변수가 하나하나 추가될수록 특정 개체를 쉽게 설명할 수 있게 된다. 우리는 우리가 관심 있는 대상을 이러한 변수들을 통해, 그들의 속성을 구체화시키고, 그들 개개인을 구분할 수 있다.
  • 모집단이 연구자의 관심 집단이 바뀌면, 바뀌듯이 변수 역시 모집단에 종속되어 변한다.

 

변수와 개인정보

  • 변수를 통해 개인을 특정할 수 있다고 하였는데, 변수에 따라 그 정도가 바뀌게 된다.
  • 단 하나로 대상을 특정할 수 있는 변수가 있으며, 3개 이상의 변수가 동시에 사용되어 대상을 특정할 수 있는 변수도 있다.
  • 예를 들어, 주민등록번호, 휴대폰 번호와 같은 변수는 아주 강력하게 특정 객체를 지목하게 한다.
  • 이름, 거주지, 연령과 같이 함께 사용되어, 강력하게 특정 객체를 지목하는 변수도 있다.
  • 이는 RDB의 Primary key, Super key와 유사한 개념이다.
  • 때문에 주민등록번호, 휴대폰 번호, 이름 같이 강력한 변수는 아예 데이터에 넣지 않거나, 만약 데이터에 들어가 있는 경우, 그 관리 수준이 상당히 엄중하다. 

 

 

 

 

 

 

1. 변수의 종류

  • 변수는 크게 "질적 변수(Qualitative variable)", "양적 변수(Quantitative variable)" 둘로 나뉜다.
  • 변수의 종류에 따라 접근하는 통계 분석 방법이 바뀌므로, 정확히 변수의 종류를 인식하는 것은 필수다.

 

 

 

 

2. 변수와 척도

  • 척도는 어떠한 현상을 측정하기 위해 만든 도구를 의미한다.
  • 연구자가 관심 있는 대상인 모집단이 존재하고, 그 모집단이 가지고 있는 속성인 변수가 존재하는데, 이 변수를 어떠한 도구를 이용해서 측정할 것인가를 이야기한다.
  • 척도는 위 변수를 측정하는 방법으로써 1:1로 대응되어 존재한다.
    (이산형 변수는 등간 변수라고도 부르며, 연속형 변수는 비율 변수라고도 부르므로, 변수의 이름과 척도의 이름은 동일하다.)

  • 변수와 헷갈리기 꽤 쉬운 개념으로, 척도는 종종 변수와 혼용되어 지칭되기도 한다.
  • 일반적으로, 명목 변수는 명목 척도로, 서열 변수는 서열 척도로, 등간 변수는 등간 척도로, 비율 변수는 비율 척도로 측정하기 때문에 이를 혼용하여 지칭해도 정보가 잘못 전달되거나 하는 문제가 발생할 가능성은 크지 않다.
  • 그러나, 변수와 척도는 동일한 개념은 아니기 때문에 주의할 필요는 있는데, 위 사진에서 보듯, 상위 척도를 이용하여, 보다 하위 레벨의 변수를 측정할 수도 있기 때문이다.
  • 예를 들어, 길이와 같은 연속형 변수를 1m보다 작다, 크다와 같이 이분화시켜 명목형 척도로 측정할 수 있으며, 10 cm 이하, 10cm ~ 1m 사이, 1m 이상 과 같은 서열 척도로 측정할 수도 있다.
  • 그러나, 하위 수준의 변수를 보다 높은 수준의 척도로는 측정할 수 없다(성별과 같은 명목 척도를 연속형 척도로 측정할 수는 없다).

 

 

 

 

3. 질적 변수(Quantitative Variable)

  • 범주형 변수(Categorical Variable)이라고도 하며, 말 그대로 변수 안에 있는 데이터들이 범주화되어 있다는 뜻이다.
  • 즉, 변수 안에 N개의 집단이 존재하며, 그 집단을 숫자로 나타낸다 할지라도 그 숫자는 데이터의 양을 줄이기 위한 목적이지, 그 숫자엔 숫자로써의 의미가 존재하지 않는다.
  • 즉, 문자로 나타낼 수 있는 변수를 의미한다.

 

3.1. 명목 변수(Nominal Variable)

  • 완전히 서로 관련 없는 문자들로 이루어진 변수를 의미한다.
  • 이를 쉽게 데이터화 하기 위해 숫자로 나타낸다 할지라도, 그 숫자에 대해선, 서로 구분하는 의미만 존재하지, 숫자가 가진 그 어떠한 정보도 존재하지 않는다.
  • 예를 들어, 성별의 남자를 1로, 여자를 2로 표기한다 할지라도, 여기에는 "남자는 1등 여자는 2등이다.", "여자가 남자보다 2배 더 우월하다."와 같은 의미는 전혀 존재하지 않는다.
  • 토트넘 축구 선수인 "손흥민의 등번호 7번"과 주장인 "위고 요리스의 등번호 1번"에는 그 어떠한 숫자적 의미가 존재하지 않는다.
  • 야구의 4번 타자와 같은 특정 숫자에 상징성이 있을 수는 있으나, 등번호를 늘여놓았을 때, 그 순서에 일정한 방향을 가진 서열이 존재하지 않기 때문에, 부여된 숫자는 단순히 객체를 구분하는 역할만 한다.

 

3.2. 서열 변수(Ordinal Variable)

  • 명목 척도 중에 순서의 개념이 존재하는 변수를 의미한다.
  • 예를 들어, 최종 학력은 "무학", "초등학교", "중학교", "고등학교", "대학교", "대학원"과 같이 명목형 척도로 측정되지만, 순서가 존재하기 때문에, 이를 숫자로 만들었을 때, 그 숫자에 아무런 의미가 존재하지 않는다고 할 수는 없다.
  • 즉, 숫자의 개념 중 순서의 개념이 존재하는 변수이다.
  • "무학 = 0, 초등학교 = 1, 중학교 = 2, 고등학교 = 3, 대학교 = 4, 대학원 = 5"로 나타낸다고 할 때, 이를 늘어놓으면, 5가 2보다 뒤에 있다라고는 할 수 있지만, "대학원(5) - 고등학교(3) = 중학교(2)"라고 할 수는 없다.

 

 

 

 

4. 양적 변수(Qualitative Variable)

  • 단순하게 연속형 변수(Continuous)라고 지칭하는 경우도 종종 있는데, 이 경우, 양적 변수를 구성하는 이산형 데이터와 연속형 데이터를 구분하기 어려워질 수 있으므로, 그냥 양적 변수라고 하길 추천한다.
  • 데이터를 숫자로 나타냈을 때, 숫자 그 자체인 경우다.
  • 그 숫자를 이산형으로만 나타낼 수 있는가, 연속형으로도 나타낼 수 있는가에 따라 이산형 변수(등간 변수)와 연속형 변수(비율 변수)가 나뉜다.

 

4.1. 등간 변수(Interval Variable)

  • 이산형으로만 나타낼 수 있는 숫자로, 각 숫자 사이가 일정하며, 그 사이에 그 어떠한 값도 존재하지 않는 데이터를 의미한다.
  • 이산형이라는 말은 숫자가 연속되지 않고 일정한 거리로 떨어져 있다는 소리로, 이해하기 쉽게 이야기하면 소수점이 존재하지 않는 경우라고 할 수 있다(물론 이는 이해하기 쉬운 예시이지 온도와 같이 소수점을 갖는 등간 변수 역시 존재하므로, 등간 변수에는 절대 소수점이 등장하지 않는다고 생각해서는 안된다).
  • 예를 들어, 남극에 있는 펭귄 수는 이산 되어 있는 숫자다. 펭귄이 반마리만 있는 경우, 이미 죽은 펭귄이므로, 이를 펭귄 0.5마리라고 할 수는 없다. 
  • 이글루 안에 펭귄 5마리가 있을 때, 이 이글루 안에 펭귄을 2마리 더 넣어 7마리로 만들 수 있고, 펭귄 3마리를 다시 빼서 4마리로 만들 수도 있으므로, 가감(더하기 빼기)이 가능하다.
  • 그러나, 펭귄 5마리에게 펭귄 2마리를 곱하거나 나눈다는 것은 불가능하며, 펭귄 1마리를 2로 나누겠다는 소리는 애초에 단위가 다르기 때문에 시도해서도 안되며, 펭귄을 죽이겠다는 소리이므로, 이런 상상은 하지도 말자.
  • 등간 변수와 비율 변수는 꽤 구분하기 어려운 개념인데, 대표적인 등간 변수인 온도는 36.2˚와 같이 소수점이 있는 경우도 존재하기 때문이다.
  • 온도는 절대적인 기준을 갖는 것이 아닌, 일정한 간격을 가지고 상대적으로 존재하는 것이기 때문에 36˚보다 18˚가 두 배 더 춥다고 할 수는 없다.

 

4.2. 비율 변수(Ratio Variable)

  • 연속형 숫자로 나타낼 수 있는 데이터로, 정수 사이에 수많은 값이 존재한다.
  • 170 cm와 171cm 사이에는 170.5, 170.05, 170.005와 같이 소수점으로 나타낼 수 있는 수많은 숫자가 존재한다.
  • 이를 비율 변수라고 부르는 이유는 측정된 데이터를 비율로 계산이 가능하기 때문으로, 이러한 비율 변수는 절대적인 기준이 존재하기 때문에 곱하고 나눌 수 있다.
  • 이 절대적인 기준이라는 것은 이 속성이 존재하지 않을 수 있는 절대 영점(Absolute Zero Point)이 존재한다는 소리로, 길이나 무게는 0이 되는 순간, 대상에게 있어 그 속성의 값이 "없다"가 될 수 있으나, 온도는 존재하지 않는다는 개념이 존재하지 않는다.
  • 비율 변수는 절대적인 기준이 존재하기 때문에 더하기, 빼기, 곱하기, 나누기가 모두 가능하다.
  • 비율 변수는 통계 분석에 있어 가장 편리한 대상으로, 모든 척도로 측정할 수 있기 때문에, 하위 변수로 쉽게 변환할 수 있다. 그 덕에 모든 통계 분석 기법의 대상이 될 수 있다.

 

 

 

 

5. 정리

  • 변수는 대상 집단(모집단)이 가지고 있는 속성이며, 이 변수는 크게 질적 변수(명목 변수, 서열 변수), 양적 변수(이산형 변수, 연속형 변수)로 나뉜다.
  • 변수를 측정하는 도구는 척도이며, 상위 변수는 하위 변수로 그 수준을 바꿀 수 있으며, 그로 인해 하위 척도로도 상위 변수를 측정할 수 있다.
  • 변수를 나누는 기준을 정리한 표는 다음과 같다.
변수 순서 더하기, 빼기 곱하기, 나누기 절대영점
명목 변수 X X X X
서열 변수 O X X X
등간 변수 O O X X
비율 변수 O O O O
  • 위 기준만으로 나누기 애매한 경우도 종종 존재하기 때문에, 이를 보다 단순화시킨 질적 변수, 양적 변수로 이분화시켜 변수를 구분하는 경우가 많다.
  • 변수의 종류에 따라 사용할 수 있는 통계 분석 기법이 크게 달라지기 때문에 변수의 종류가 무엇인지 판단하는 능력은 통계 분석을 위해 필수로 가지고 있어야 하는 기술이다.
728x90
반응형

'Python으로 하는 기초통계학 > 기본 개념' 카테고리의 다른 글

중심경향치(1) - 최빈값, 중앙값  (0) 2021.03.03
도수분포표와 시각화  (0) 2021.03.02
도수분포표  (0) 2021.03.02
통계 분석을 위한 데이터 준비  (0) 2021.03.01
통계학이란?  (0) 2021.02.26
728x90
반응형

통계학이란?


"통계학이란 불확실한 상황에서 현명한 의사결정을 하기 위한 이론과 방법의 체계이며, 통계학은 자료의 수집·분류·분석과 해석의 체계를 갖는다."
 W.Allen Walls and Harry V.Roberts, Statistics: A New Approach(Glence, Ill., Free Press, 1956), p. 3.
(박정식, 윤영선, 박래수(2010) 현대통계학 제5판 참고)

"통계학은 실증적인 뿌리를 가지고 있으며 실질적 활용에 초점을 맞추고 있기 때문에, 순수수학과 구분되는 응용수학의 일종으로 여겨진다. 통계학의 방법을 통해, 실제 수치들을 왜곡하여 해석하는 것을 막고 연구를 바탕으로 합리적인 의사결정을 할 수 있다."
 Moore, David(1992). <Teaching Statistics as a Respectable Subject>. F. Gordon and S. Gordon. <Statistics for the Twenty-First century>. Washington, DC: The Mathematical Association of America. 14-25쪽. ISBN 978-0-88385-078-7.
(Wikipidia 통계학 참고)


  • 통계학은 Data를 다루는 학문으로, 연구자가 관심 있는 대상을 나타낼 수 있는 다량의 Data를 수집하는 것부터, 그 Data의 모양을 파악하고, 자신의 연구 모델에 맞게 Data를 체계화시켜, 그 안에 숨어 있는 패턴을 찾아내는 모든 과정에 대한 학문이라고 할 수 있다.
  • 통계학은 머신러닝, 딥러닝을 비롯한 데이터를 다루는 각종 학문의 근간이 되므로, 통계학을 제대로 이해하지 못한다면, 다른 학문들의 원리를 제대로 이해할 수 없다.
  • 통계학은 기본적으로 데이터가 어디에 모여 있고, 얼마나 흩어져 있는지를 통해서 데이터를 파악한다.

 

 

 

 

1. 모집단과 표본집단


 모집단(Population): 연구자의 관심 대상이 되는 모든 개체의 집합으로, 연구 대상이 되는 데이터의 전체를 가리킨다.

◎ 표본집단(Sample): 모집단에서 추출해낸 개체의 집합이다.


  • 모집단과 표본집단 예시 1)
    • 연구자가 사람의 발 크기와 키에 대해 어떠한 경향성(Pattern)이 존재할 것이라고 생각했다고 해보자. 이를 확인하고자 한다면, 전 세계에 있는 모든 사람들(모집단)을 대상으로, 데이터를 모아야 할 것이다.
    • 그러나, 이는 막대한 비용과 시간이 소모되기 때문에 불가능한 일이다. 때문에 연구자는 인종, 연령, 성별 등 다양한 변수들을 고려하여, 모집단을 대표할 수 있는 표본집단(Sample)을 추출하여, 모집단을 추정한다.

 

  • 모집단과 표본집단 예시 2)
    • 참치 통조림을 만드는 공장에서 제품에 이상이 있는지 확인하기 위해, X-ray를 비롯한 다양한 도구를 이용해서 전수 조사하였으나, 실제로 제품을 열어서 확인해보는 것이 가장 정확한 결과를 가져온다고 가정해보자.
    • 모든 통조림을 열어서 확인해보는 것이 품질이 떨어지는 제품이 얼마나 발생하는지 알 수 있겠지만, 그렇게 했다간 통조림을 팔 수 없게 될 것이다. 때문에 모집단인 모든 통조림에서 통조림을 일부만 추출(표본집단)해서 모집단을 추정하게 된다.

 

  • 모집단과 표본집단 예시 3)
    • 당신이 통계 유치원 선생님이고, 기린반 어린이 30명과 해바라기반 어린이 25명과 함께 학예회 준비로 동요를 부르려고 하는데, 아이들이 뽀로로 주제가와 핑크퐁 아기 상어 중 무엇을 더 좋아할지를 몰라 이에 대해 고민하고 있다고 가정하자.
    • 당신은 기린반 어린이와 해바라기반 어린이들을 대상으로 선호하는 캐릭터에 대해 조사를 할 수 있다. 이 경우 당신의 관심 대상인 기린반, 해바라기반 어린이들은 55명으로 매우 적기 때문에 모집단 전체에 대해 조사를 할 수도 있다.

 

  • 모집단은 연구자의 마음에 따라 그 규모가 크게 달라지기 때문에, 예시 3)처럼 모집단의 규모가 작다면, 모집단 전체를 대상으로 분석을 할 수 있다. 즉, 반드시 표본집단을 통해서 통계 분석을 진행하는 것은 아니다.
  • 그러나, 모집단이 작은 경우만 존재하지는 않기 때문에, 모집단을 가장 잘 대표할 수 있는 표본집단을 뽑아, 통계적 기법을 통해 모집단의 성격을 추정하는 것이 현대 통계학의 주류다.

 

 

 

 

2. 모수와 통계량


 모수(Parameter): 모집단의 특성을 수치로 나타낸 것이다.

 통계량(Statistic): 표본의 특성을 수치로 나타낸 것이다.


  • 대전 여자 중학생의 평균 팔 굽혀 펴기 횟수를 알고 싶다고 가정해보자.
    • 대전에 사는 여자 중학생들의 평균 팔 굽혀 펴기 횟수를 알기 위해, 완전 무작위로 각 중학교의 학년별 한 반의 여중생들을 대상으로 평균 팔 굽혀 펴기 횟수를 구했다.
    • 모집단인 대전에 사는 모든 여자 중학생의 평균 팔 굽혀 펴기의 횟수(모수)와 표본집단의 평균 팔 굽혀 펴기 횟수(통계량)가 같다고 할 수 있을까?
    • 우연히 샘플로 추출된 여중생들이 팔 굽혀 펴기를 유난히 잘하는 사람들이어서, 모수보다 통계량이 더 클 수도 있고, 반대로 우연히 운동을 너무 싫어하는 사람들이 뽑혀서 통계량이 모수보다 더 작을 수도 있다.
    • 즉, 모수와 통계량은 같은 값이 아니다.

 

  • 모집단의 특성을 나타내는 모수를 구하는 것이 가장 정확하겠으나, 앞서 봤듯 모수를 구하지 못하는 상황에서는 표본집단을 통해 모수를 추정해야 하고, 이때 표본집단의 특성을 나타내는 통계량을 이용하게 된다.
  • 모수나 통계량은 앞서 말한 평균뿐만이 아니라, 각 집단을 나타낼 수 있는 다른 특성인 중위수, 최빈값, 최솟값, 최댓값, 분산, 표준편차 등도 다양한 지표들을 포함하는 개념이다.
  • 모수는 그리스 문자($\mu,\ \sigma^2, \sigma$)로 표기하고, 통계량은 영어 알파벳($\bar{X}, S^2, S$)으로 표기하는 것이 관례다.
  • 단, 모집단의 크기인 개체의 양은 $N$으로, 표본집단의 크기는 $n$으로 표기하는 것이 관례다.

 

 

 

 

3. 기술통계학과 추론통계학


◎ 기술통계학(Descriptive statistics): 데이터를 정리하고 요약하여, 데이터의 특성을 찾아 서술하는 통계학이다. 

◎ 추론통계학(Inferential statistics): 모집단으로부터 추출한 표본집단의 특성(통계량)을 기반으로, 모집단 특성(모수)을 추측해내는 통계학이다.


  • 기술통계학(Descriptive statistics)과 추론통계학(Inferential statistics)은 별개의 것이 아니며, 서로 연결되어 순차적으로 진행된다.
  • 데이터를 분석하는 과정은 연구설계부터 자료수집, 자료 정리, 자료해석을 통해 모집단 또는 표본집단의 특성을 파악하는 기술통계학을 우선 실시한다.
  • 표본을 대상으로 한 경우 표본에서 얻어진 통계량을 기초로 추론통계학을 실시해 모집단의 특성인 모수를 추정하게 된다.
  • 즉, 기술통계량은 모집단, 표본집단 모두를 대상으로, 데이터의 특성(모수, 통계량)을 찾아내고, 대상 집단이 표본집단인 경우 추론통계학을 실시하여, 모수를 추정하게 된다.

 

  • 기술통계학과 추론통계학의 예시)
    • 기술통계학
      우리나라 남성들의 평균 키를 알기 위해, 모집단인 우리나라의 모든 남성들의 신장 Data를 수집하거나, 이는 비효율적이므로 일부를 표본집단으로부터 신장 Data를 추출하여 표본집단의 평균 키나 키의 표준편차를 구하여, 데이터의 특성을 파악한다.
    • 추론통계학
      표본집단에서 구해진 통계량인 평균 키, 키의 표준편차를 기반으로 모집단인 우리나라 모든 남성들의 평균 키(모수)를 추정한다.

 

 

 

 

4. 모수통계학과 비모수통계학


◎ 모수통계학(Parametric statistics): 모집단의 분포에 대한 가정이 필요하며, 연속형 척도를 대상으로 한다.

◎ 비모수통계학(nonParametric statistics): 모집단에 대한 가정이 필요하지 않으며, 질적 자료나 양적 데이터라 할지라도 빈도수와 같은 비연속적인 데이터를 대상으로 한다.


  • 모수통계학은 대상 집단의 모집단이 정규분포와 같은 분포를 따른다는 가정하에 진행된다.
  • 즉, 연구자가 관심 있는 대상인 모집단의 분포 모양이 정규분포의 형태를 그리면서, 연속형 데이터를 대상으로 할 때, 모수통계학을 사용하고, 그 외의 기법들은 비모수통계학이라고 생각하면 된다.
  • 추론통계학에서는 주로 비모수통계학보다 모수통계학을 사용하는데, 이는 모수통계학이 모수 추정에 있어 더 신뢰도가 높기 때문이다.
  • 그러나, 모집단에 대한 정보가 전혀 없거나 부정확하여, 모수통계학의 가정을 만족시키지 못한 상태라면 비모수통계학의 신뢰도가 더 높다.

 

  • 비모수통계학의 특징
    • 분포 무관(Distribution-free) 검정법이라고도 불리며, 말 그대로 모집단의 분포에 상관없이 사용할 수 있다.
    • 범주형 척도 같은 비연속성 데이터라 할지라도 분석할 수 있다.
    • 계산 방법이 단순하여 빠르고 쉽게 통계량을 구할 수 있으며, 결과에 대한 해석과 이해가 쉽다.
    • 표본을 많이 추출하기 어려운 경우에도 사용할 수 있다.
728x90
반응형

'Python으로 하는 기초통계학 > 기본 개념' 카테고리의 다른 글

중심경향치(1) - 최빈값, 중앙값  (0) 2021.03.03
도수분포표와 시각화  (0) 2021.03.02
도수분포표  (0) 2021.03.02
통계 분석을 위한 데이터 준비  (0) 2021.03.01
변수(Variable)  (0) 2021.03.01

+ Recent posts