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
반응형

파이썬(Python)

"Life is short! You need Python!!"

 알파고와 이세돌의 대국이 있었던 2016년 이후로, 전 세계에서 가장 핫한 키워드를 꼽으라면, 인공지능과 빅데이터일 것이다.

 인공지능 & 빅데이터 분야의 첨단을 달려가는 Data Scientist를 대상으로 2018년 캐글에서 조사한 Data Scientist들이 주로 사용하는 언어에서 압도적인 1위를 한 것은 Python인데, 대체 Python이 무엇이길래 이 빅데이터 시대에 그리도 인기가 좋은지 간략하게 알아보자.

(https://businessoverbroadway.com/2019/01/13/programming-languages-most-used-and-recommended-by-data-scientists/)

 

 

 크리스마스 주엔 연구실이 쉰다는 것을 잊고 출근한 귀도 반 로섬(Guido van Rossum)은 너무도 따분했고, 그 심심한 마음을 달래기 위해 만든 것이 그 유명한 파이썬이다. 심지어 이 이름마저도, 뱀과 아무 관련 없이, 제작자가 좋아하던 영국의 코미디 그룹인 몬티 파이썬에서 따온 것이라고 하니.

 한국으로 따지자면 설 연휴에 심심하다고 코빅이라는 프로그래밍 언어를 만들어버렸고, 그 언어가 20년이 지나 전 세계적으로 널리 쓰이는 언어가 된 것이나 다름없다.

 파이썬의 가장 큰 장점은 문법이 굉장히 쉽다는 것인데, 그 예시로 평소 R을 즐겨 사용했던 필자는, R로는 당신이 만든 코드를 상품화하기 힘들다란 말 한마디에, 파이썬을 공부한 첫날, 바로 파이썬으로 코드를 뒤집어엎는 것이 가능했을 정도로, 학습 난이도가 낮다는 것이다(물론 한 가지 언어를 다룰 수 있는 상황에서 새로운 언어를 익히는 것과 전혀 모르는 상태에서 익히는 것의 난이도는 천지차이다!).

 또, R과 달리 UTF-8 기반이기에, 한글을 대상으로 한 텍스트 마이닝이 R보다 편하고, 데이터 타입 변환도 자유로워 오류도 적으며, 서버에서 작업할 때, 한 계정당 한 명만 작업이 가능한 R과 달리, 파이썬은 주피터 노트북 등을 통해, 여러 명이 동시에 붙을 수 있으며, 완성된 파이썬 코드를 동시에 여러 개 실행하여, 손쉽게 병렬 실행을 할 수 있다는 장점이 존재한다.
(물론 이 병렬 실행에서 멀티 스레드 난이도는 크게 높지 않으나, py파일 하나당 1개의 코어만 점유한다는 한계점이 존재하기 때문에 마냥 쉽지만은 않다.)

물론 파이썬의 단점이 아예 없는 것은 아니다. 파이썬은 다른 컴파일 언어에 비해 느리고, 프로그래밍을 처음 해보는 사람에게 추천하는 쉬운 언어임에도 워낙 오래되었다 보니, 사용하고자 하는 패키지끼리 호환성 문제가 발생해 잘 돌아가던 코드가 안 돌아가는 일이 종종 발생하고, 몇몇 패키지는 세팅을 하다가 파이썬을 만지고 있는 시간보다 리눅스를 만지고 있는 시간이 더 긴 경우도 있다.

자! 파이썬에 대해선 여기까지 알아보도록 하고, 보다 자세한 내용은 위키피디아나 책을 참고하길 바란다. 이제부터 Data Scientist들에게 가장 사랑받는 언어인 파이썬에 대해 쭉! 학습해보도록 하자.

728x90
반응형

+ Recent posts