호쌤
호쌤 Just For Fun

[Python 데이터 분석] 기술통계

크리에이티브 커먼즈 라이선스 ITPAPER(호쌤,쭈쌤)에 의해 작성된 ≪[Python 데이터 분석] 기술통계≫은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.
이 라이선스의 범위 이외의 이용허락을 얻기 위해서는 leekh4232@gmail.com으로 문의하십시오.

[Python 데이터 분석] 기술통계

기술통계란 자료를 그래프나 숫자등으로 요약하는 통계적 행위 및 관련 방법을 의미합니다.

데이터를 요약하고 시각화해서 잘 설명하는 것이 중점을 두며 데이터에 대해서 쉽게 설명하기 위해서 시각화를 많이 활용합니다.

기술 통계에서 기본적으로 사용하는 시각화 자료들은 박스플롯(상자그림), 도수분포표, 히스토그램이 있으며 이를 기반으로 사실을 객관적으로 확인하는 것을 중점으로 합니다.

#01. 기술통계 절차

  1. 데이터의 전체 크기와 형태
    • 행과 열의 수를 확인한다.
    • 10만건의 데이터 전체를 출력하는 것은 매우 부담이 큰 처리이므로 상위 n건, 하위 n건의 일부만을 확인한다.
  2. 수치로 표현되는 연속성 데이터의 경우 집단의 특성을 잘 나타내는 요약 통계량을 확인한다.
    • 평균, 중앙값, 표준편차, 범위(최대값~최소값), 사분위수 등을 확인한다.
    • 요약통계량을 상자그림으로 시각화하여 확인한다.
    • ex) 키, 몸무게, 성적
  3. 수치화 할 수 없는, 종류에 대한 데이터는 전체의 데이터 분포를 확인한다.
    • 구간별 자료의 개수를 나타내는 표(=도수분포표)를 산정한다.
    • 도수 분포표를 그래프로 표현한 히스토그램을 확인한다.
    • ex) 투표결과

#02. 필요한 패키지 및 샘플 데이터 준비

1) 패키지 참조하기

1
2
3
from pandas import DataFrame    # 모듈 참조
from pandas import read_csv     # 모듈참조
from matplotlib import pyplot   # 모듈 참조

2) 샘플 데이터 가져오기

기술통계 수치값, 상자그림 확인을 위해 학생 10000명의 자료를 가상으로 표현한 샘플 데이터

1
2
성적표csv = read_csv("http://itpaper.co.kr/demo/py/grade.csv", encoding="euc-kr")
성적표csv
▶ 출력결과
이름 학년 성별 국어 영어 수학 과학
0 철수 1 남자 98 NaN 88.0 64.0
1 영희 2 여자 88 90.0 62.0 72.0
2 민수 1 남자 92 70.0 NaN NaN
3 수현 3 여자 63 60.0 31.0 70.0
4 호영 4 남자 120 50.0 NaN 88.0

3) 성적표 데이터 전처리

1
2
3
4
5
6
7
8
9
10
현재인덱스 = list(성적표csv.index)
이름 = list(성적표csv['이름'])

indexDict = {}
for i, v in enumerate(이름):
    before = 현재인덱스[i];
    indexDict[before] = v

성적표 = 성적표csv.rename(index=indexDict)
성적표
▶ 출력결과
이름 학년 성별 국어 영어 수학 과학
철수 철수 1 남자 98 NaN 88.0 64.0
영희 영희 2 여자 88 90.0 62.0 72.0
민수 민수 1 남자 92 70.0 NaN NaN
수현 수현 3 여자 63 60.0 31.0 70.0
호영 호영 4 남자 120 50.0 NaN 88.0

예제에서 사용되지 않는 컬럼 삭제

1
2
성적표.drop(['이름', '성별', '학년'], axis=1, inplace=True)
성적표
▶ 출력결과
국어 영어 수학 과학
철수 98 NaN 88.0 64.0
영희 88 90.0 62.0 72.0
민수 92 70.0 NaN NaN
수현 63 60.0 31.0 70.0
호영 120 50.0 NaN 88.0

#03. 데이터의 전체 크기와 형태 확인

1) 데이터프레임의 전체 크기 조회

조회 결과는 튜플 타입으로 리턴된다.

1
2
3
, = 성적표.shape
print("행의 크기 =", )
print("열의 크기 =", )
▶ 출력결과
1
2
행의 크기 = 5
열의 크기 = 4

2) 데이터의 일부만 확인하기

앞 부분의 2건만 확인

1
성적표.head(2)
▶ 출력결과
국어 영어 수학 과학
철수 98 NaN 88.0 64.0
영희 88 90.0 62.0 72.0

뒷 부분의 2건만 확인

1
성적표.tail(2)
▶ 출력결과
국어 영어 수학 과학
수현 63 60.0 31.0 70.0
호영 120 50.0 NaN 88.0

#04. 요약통계량 얻기

1) 요약 통계량을 이해하기 위한 통계학 개념

평균값

모든 값을 더한 후 개수로 나눈 값.

1, 2, 3, 4, 5, 100의 평균은 (1+2+3+4+5+100)/6 이므로 19.17이다.

평균은 특정 값이 다른 값들의 범위와 차이가 큰 경우 신뢰도가 떨어진다.

위의 데이터에서 100에 해당하는 값은 다른 값들에 비해 극단적으로 높다. 이러한 형태의 값을 극단치라고 한다.

중앙값

모든 값을 순서대로 정렬한 후 가운데 위치의 값.

평균의 신뢰도가 현저히 낮을 경우 데이터의 분포를 확인하기 위해 사용한다.

데이터의 수가 홀수개인 경우

모든 값을 순서대로 정렬한 후 가운데 위치의 값.

1, 2, 3, 4, 5의 중앙값은 3이다.

데이터의 수가 짝수개인 경우

모든 값을 순서대로 정렬한 후 가운데 두 값의 평균.

1, 2, 3, 4, 5, 6의 중앙값은 (3+4)/2이므로 3.5이다.

2) 사분위 수

데이터 표본을 4개의 동일한 부분으로 나눈 값.

사분위수는 데이터의 관측치가 아닌 계산된 값이다.

사분위수를 사용하여 데이터 집합의 범위와 중심 위치를 신속하게 평가할 수 있다.

이는 데이터를 이해하는 데 중요한 첫 번째 단계이다.

용어 설명
1사분위 수 데이터의 하위 25%가 이 값보다 작거나 같음.
2사분위 수 중위수 데이터의 50%가 이 값보다 작거나 같음. (=중앙값)
3사분위 수 데이터의 하위 75%가 이 값보다 작거나 같음.

반대로 말하면 데이터의 상위 25%는 3사분위 수 보다 크다.

예를 들어, 데이터가 7, 9, 16, 36, 39, 45, 45, 46, 48, 51인 경우

Q1 = 14.25
Q2 = 42
Q3 = 46.50
사분위간 범위 = 14.25 ~ 46.50 또는 32.25

사분위수를 정확하게 계산하려면 종종 두 관측치 사이를 보간해야 한다.

중위수와 사분위간 범위는 극단치의 영향을 받지 않기 때문에 평균 및 표준 편차보다 치우침이 많은 데이터의 중심 위치와 범위의 더 나은 측도가 될 수 있다.

3) 모든 항목에 대한 요약통계 결과 일괄 확인

요약 통계량을 표현하는 데이터프레임이 반환된다.

항목 의미
count 결측치(NaN)을 제외한 유효 데이터 수
mean 평균
min 최소값
25% 1사분위 수 (하위 25% 위치의 데이터)
50% 2사분위 수, 중앙값 (하위 50% 위치의 데이터)
75% 3사분위 수 (하위 75% 위치의 데이터, 상위 25%)
max 최대값

1사분위~3사분위 수 까지를 4분위수라고 묶어서 표현한다.

1
2
des = 성적표.describe()
des
▶ 출력결과
국어 영어 수학 과학
count 5.000000 4.000000 3.000000 4.000000
mean 92.200000 67.500000 60.333333 73.500000
std 20.474374 17.078251 28.536526 10.246951
min 63.000000 50.000000 31.000000 64.000000
25% 88.000000 57.500000 46.500000 68.500000
50% 92.000000 65.000000 62.000000 71.000000
75% 98.000000 75.000000 75.000000 76.000000
max 120.000000 90.000000 88.000000 88.000000

2) 특정 컬럼에 대한 확인

1
성적표['국어'].describe()
▶ 출력결과
1
2
3
4
5
6
7
8
9
count      5.000000
mean      92.200000
std       20.474374
min       63.000000
25%       88.000000
50%       92.000000
75%       98.000000
max      120.000000
Name: 국어, dtype: float64

3) 기술통계값들을 개별적으로 얻기

1
성적표.count()
▶ 출력결과
1
2
3
4
5
국어    5
영어    4
수학    3
과학    4
dtype: int64
1
성적표.mean()
▶ 출력결과
1
2
3
4
5
국어    92.200000
영어    67.500000
수학    60.333333
과학    73.500000
dtype: float64
1
성적표.max()
▶ 출력결과
1
2
3
4
5
국어    120.0
영어     90.0
수학     88.0
과학     88.0
dtype: float64
1
성적표.min()
▶ 출력결과
1
2
3
4
5
국어    63.0
영어    50.0
수학    31.0
과학    64.0
dtype: float64
1
성적표.std()
▶ 출력결과
1
2
3
4
5
국어    20.474374
영어    17.078251
수학    28.536526
과학    10.246951
dtype: float64
1
2
# 1사분위 수 (25% 위치의 값)
성적표.quantile(q=0.25)
▶ 출력결과
1
2
3
4
5
국어    88.0
영어    57.5
수학    46.5
과학    68.5
Name: 0.25, dtype: float64
1
2
# 2사분위 수, 중앙값 (50% 위치의 값)
성적표.quantile(q=0.5)
▶ 출력결과
1
2
3
4
5
국어    92.0
영어    65.0
수학    62.0
과학    71.0
Name: 0.5, dtype: float64
1
2
# 중앙값을 얻는 또 다른 방법
성적표.median()
▶ 출력결과
1
2
3
4
5
국어    92.0
영어    65.0
수학    62.0
과학    71.0
dtype: float64
1
2
# 3사분위 수 (75% 위치의 값)
성적표.quantile(q=0.75)
▶ 출력결과
1
2
3
4
5
국어    98.0
영어    75.0
수학    75.0
과학    76.0
Name: 0.75, dtype: float64
1
2
# 응용 - 상위 10%에 들기 위해 취득해야 하는 과목별 점수
성적표.quantile(q=0.9)
▶ 출력결과
1
2
3
4
5
국어    111.2
영어     84.0
수학     82.8
과학     83.2
Name: 0.9, dtype: float64

4) 상자그림

데이터의 요약 정보를 시각화 해 놓은 그래프로 데이터의 범위, 사분위 수 등을 확인할 수 있는 시각화 자료이다.

내부적으로 matplotlib 패키지의 pyplot 객체를 사용한다.

boxplot

pyplot 객체 기본 환경 설정

1
2
3
4
5
6
7
8
# 한글폰트, 그래픽 크기 설정
pyplot.rcParams["font.family"] = 'Malgun Gothic'  # 사용할 폰트이름 지정 (맑은고딕)
pyplot.rcParams["font.size"] = 14                 # 글자크기
pyplot.rcParams["figure.figsize"] = (12, 6)       # 그래프의 가로,세로 크기 (inch단위)

# 경고메시지 표시 안함.
import warnings
warnings.filterwarnings("ignore")

전체 데이터 프레임의 상자그림 생성

1
2
3
4
5
# 상자그림 생성
성적표.boxplot()

# 생성된 그래프 화면 표시
pyplot.show()
▶ 출력결과

png

특정 컬럼에 대한 상자그림 표시하기

두 개 이상의 컬럼을 한 번에 표시할 경우 ()안의 리스트에 컬럼이름을 나열한다.

1
2
3
4
5
# 상자그림 생성
성적표.boxplot(['영어'])

# 생성된 그래프 화면 표시
pyplot.show()
▶ 출력결과

png

#05. 히스토그램과 도수분포표

1) 히스토그램

자료가 가질 수 있는 범위를 몇 개의 구간으로 나누고 각 구간에 해당하는 값의 숫자 혹은 상대적 빈도를 표현하는 그래프

히스토그램 작성 과정

  1. 자료의 갯수와 구간(최대값, 최소값)을 확인한다.
  2. 자료를 몇 개의 구간으로 나눌지 분석가의 주관에 따라 결정한다.
    • 구간은 자료의 개수나 분포에 따라 달라져야 한다.
    • 각 구간별로 5개 이상의 값이 들어가도록 하는 것이 좋다.
    • 너무 많은 구간을 나누지 않도록 해야 한다. (일반적으로 5~15 사이의 값)
  3. Pyplot의 hist() 함수를 사용하여 히스토그램을 생성한다.
    1
    
     n, bins, patches = pyplot.hist(, 구간의_수)
    
    • n은 각 구간에 포함된 값의 갯수 혹은 빈도를 표현하는 리스트
    • bins는 각 구간별 경계값 리스트
    • patches는 각 구간을 그리는 matplot 객체 리스트 (사용안함)

2) 샘플데이터 가져오기

1
2
3
# 성적표 데이터
성적표10000건 = read_csv("http://itpaper.co.kr/demo/py/grade10000.csv", encoding="euc-kr")
성적표10000건
▶ 출력결과
이름 국어 영어 수학 과학
0 학생1 98.0 NaN 88.0 64.0
1 학생2 88.0 90.0 62.0 72.0
2 학생3 92.0 70.0 NaN NaN
3 학생4 63.0 60.0 31.0 70.0
4 학생5 100.0 50.0 NaN 88.0
... ... ... ... ... ...
9995 학생9996 63.0 60.0 55.0 70.0
9996 학생9997 21.0 50.0 55.0 88.0
9997 학생9998 98.0 90.0 88.0 64.0
9998 학생9999 88.0 90.0 62.0 72.0
9999 학생10000 92.0 70.0 75.0 85.0

10000 rows × 5 columns

3) 성적표 데이터 전처리

인덱스 이름 지정

1
2
3
4
5
6
7
8
9
10
11
현재인덱스 = list(성적표10000건.index)
이름 = list(성적표10000건['이름'])

indexDict = {}
for i, v in enumerate(이름):
    before = 현재인덱스[i];
    indexDict[before] = v

성적표df = 성적표10000건.rename(index=indexDict)
성적표df.drop(['이름'], axis=1, inplace=True)
성적표df
▶ 출력결과
국어 영어 수학 과학
학생1 98.0 NaN 88.0 64.0
학생2 88.0 90.0 62.0 72.0
학생3 92.0 70.0 NaN NaN
학생4 63.0 60.0 31.0 70.0
학생5 100.0 50.0 NaN 88.0
... ... ... ... ...
학생9996 63.0 60.0 55.0 70.0
학생9997 21.0 50.0 55.0 88.0
학생9998 98.0 90.0 88.0 64.0
학생9999 88.0 90.0 62.0 72.0
학생10000 92.0 70.0 75.0 85.0

10000 rows × 4 columns

4) 히스토그램 생성하기

자료의 갯수를 센다

1
2
count = 성적표df['영어'].count()
count
▶ 출력결과
1
9770

자료 내에서 최대/최소값을 찾는다.

1
2
3
4
max_value = 성적표df['영어'].max()
min_value = 성적표df['영어'].min()
print("최대값 = ", max_value)
print("최소값 = ", min_value)
1
2
최대값 =  98.0
최소값 =  1.0

몇 개 구간으로 나눌지 분석가의 주관에 따라 결정한다.

1
step = 5

히스토그램 그래프에 대한 한글 폰트, 글자크기, 그래픽 크기 설정

1
2
3
pyplot.rcParams["font.family"] = 'Malgun Gothic'
pyplot.rcParams["font.size"] = 20
pyplot.rcParams["figure.figsize"] = (25, 15)

데이터와 구간을 사용하여 히스토그램 작성하기

결측치(NaN)이 포함된 컬럼에 대한 처리 요청시 경고 메시지가 표시될 수 있다. (무시해도 좋다)

1
n, bins, patches = pyplot.hist(성적표df['영어'], bins=step)
▶ 출력결과
1
2
3
4
c:\python36\lib\site-packages\numpy\lib\histograms.py:829: RuntimeWarning: invalid value encountered in greater_equal
  keep = (tmp_a >= first_edge)
c:\python36\lib\site-packages\numpy\lib\histograms.py:830: RuntimeWarning: invalid value encountered in less_equal
  keep &= (tmp_a <= last_edge)

png

리턴값 확인

데이터의 구간 정보를 담고 있는 리스트
  • 1이상 20.4미만
  • 20.4이상 39.8미만
  • 39.8이상 59.2미만
  • 59.2이상 78.6미만
  • 78.6이상 98이하 (마지막 구간은 포함됨)
1
bins
▶ 출력결과
1
array([ 1. , 20.4, 39.8, 59.2, 78.6, 98. ])
각 구간별 빈도를 담고 있는 리스트

bins가 의미하는 구간별로 데이터의 수

1
n
▶ 출력결과
1
array([ 727., 1314., 3158., 2400., 2171.])
그래프를 표현하는데 사용되는 객체들에 대한 참조

사용안함

1
patches
▶ 출력결과
1
<a list of 5 Patch objects>

5) 히스토그램 보정하기

구간정보의 소수점 반올림 처리

jupyter에서는 bins 값이 소수점 첫자리까지만 표시되지만 python 콘솔에서 직접 확인하면 소수점 자리수가 매우 긴 값으로 구성되어 있음을 알 수 있다.

1
2
3
4
5
# bins 리스트의 원소들을 소수점 둘째 자리에서 반올림
for i, v in enumerate(bins):
    # round(값, 소수점자리) -> 지정된 자리수까지 남기라는 의미
    bins[i] = round(v, 1)
bins
▶ 출력결과
1
array([ 1. , 20.4, 39.8, 59.2, 78.6, 98. ])

pyplot을 활용한 히스토그램 구성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
pyplot.rcParams["font.family"] = 'Malgun Gothic'
pyplot.rcParams["font.size"] = 20
pyplot.rcParams["figure.figsize"] = (25, 10)

pyplot.hist(성적표df['영어'], bins=step)
pyplot.grid()
pyplot.xlabel('영어 점수 구간')
pyplot.ylabel('영어점수 구간별 학생 수')
pyplot.title('영어점수 히스토그램')

# x축의 좌표에 다른 내용을 출력
pyplot.xticks(bins, bins)

# 출력할 데이터 수 만큼 반복
for i, v in enumerate(n):
    txt = "%d명" % v
    print(txt)

    x = bins[i] + ((bins[i+1]-bins[i]) / 2)
    
    # 텍스트 출력 -> x좌표, y좌표, 내용, 글자크기, 색상, 텍스트가로정렬, 세로정렬
    pyplot.text(x, v, txt, fontsize=18, color='#ff0000', 
                horizontalalignment='left', verticalalignment='bottom')

pyplot.show()
▶ 출력결과
1
2
3
4
5
727명
1314명
3158명
2400명
2171명

png

6) 도수분포표 만들기

히스토그램을 생성하는 과정에서 리턴되는 값들이 도수분포표를 구성하는 정보에 해당한다.

Python에서 도수분포표를 한번에 생성하는 기능은 제공되지 않기 때문에 필요하다면 표를 생성하기 위한 로직을 직접 구현해야 한다.

1
2
3
4
5
idx = []
for i in range(0, len(bins)-1):
    k = "%0.1f~%0.1f" % (bins[i], bins[i+1])
    idx.append(k)
idx
▶ 출력결과
1
['1.0~20.4', '20.4~39.8', '39.8~59.2', '59.2~78.6', '78.6~98.0']
1
2
df = DataFrame(n, index=idx, columns=['빈도'])
df
▶ 출력결과
빈도
1.0~20.4 727.0
20.4~39.8 1314.0
39.8~59.2 3158.0
59.2~78.6 2400.0
78.6~98.0 2171.0
Rating:

크리에이티브 커먼즈 라이선스 ITPAPER(호쌤,쭈쌤)에 의해 작성된 ≪[Python 데이터 분석] 기술통계≫은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.
이 라이선스의 범위 이외의 이용허락을 얻기 위해서는 leekh4232@gmail.com으로 문의하십시오.

comments powered by Disqus