본문 바로가기

데이터/데이터 분석

[혼공] ch 4. 데이터 요약하기

1. 기술통계 구하기 

 

- 기술통계(descriptive statistics)는 자료의 내용을 압축하여 설명하는 방법을 말한다, 

- ns_book6.csv 파일을 데이터프레임으로 불러 온 후 처음 다섯 개 행을 출력

import pandas as pd

ns_book6 = pd.read_csv('ns_book6.csv', low_memory=False)
ns_book6.head()

 

 

- 판다스는 데이터프레임에서 기본적인 몇 가지 기술통계를 자동으로 추출해주는 describe() 메서드를 제공한다. 

ns_book6.describe()

 

 

- describe() 메서드는 기본적으로 수치형 열에 대한 요약 통계를 보여준다. 

 

count 누락된 값을 제외한 데이터 개수
mean 평균
std 표준편차
min 최솟값
50% 중앙값
25% 순서대로 늘어 놓았을 때 25% 지점
75% 순서대로 늘어 놓았을 때 75% 지점
max 최댓값

 

- 이상한 점은 도서권수 최솟값이 0이다. 

- 불리언 배열과 sum() 함수를 활용하면 도서권수가 0인 도서의 행 개수를 쉽게 카운트 할 수 있다. 

 

sum(ns_book6['도서권수']==0)

 

- 실제로 없는 도서 대출 데이터는 의미가 없다고 생각하여 제외 

ns_book7 = ns_book6[ns_book6['도서권수']>0]

 

 

- describe() 메서드는 기본적으로 데이터의 25%, 50%, 75%에 위치한 값을 보여준다. 

- 원하는 위치의 값을 보고 싶다면 percentiles 매개변수에 위치를 지정하면 된다. 

 

ns_book7.describe(percentiles=[0.3, 0.6, 0.9])

 

 

 

- 열의 데이터 타입이 수치가 아닌 다른 데이터 타입의 열의 기술 통계를 보고 싶다면 include 매개변수에 데이터 타입을 지정할 수 도 있다. 

 

ex) object 타입의 열에 대한 통계 

ns_book7.describe(include='object')

 

 

- count 행은 누락된 값을 제외한 데이터 개수를 나타내고, unique 행은 고유한 값의 개수를 나타낸다. 

- top 행은 가장 많이 등장하는 값을 나타낸다. 

- freq 행은 top 행에 등장하는 항목의 빈도수이다. 

 

1) 평균 구하기 

 

 

- 판다스 데이터프레임과 시리즈 객체는 평균을 계산하는 mean() 메서드를 제공한다. 

ns_book7['대출건수'].mean()

 

 

 

2) 중앙값 구하기 

 

- 중앙값(median)은 전체 데이터를 순서대로 늘어 놓았을 때 중앙에 위치한 값

- 판다스는 중앙값을 구하기 위한 메서드로 median() 메서드를 제공한다. 

ns_book7['대출건수'].median()

 

 

- 데이터가 홀수일 때는 중앙값을 결정하기 슆다. 정확히 가운데 놓은 값을 찾으면 된다. 

- 데이터가 짝수일 때는 가운데 두 개의 값을 평균하여 중앙값을 결정한다. 

 

temp_df = pd.DataFrame([1,2,3,4])
temp_df.median()

 

 

중복값 제거하고 중앙값 구하기 

 

- 같은 값의 대출건수를 모두 제외하고 중앙값을 계산할 수 있다. 

- drop_duplicates() 메서드를 사용해 '대출건수'열에서 중복된 값을 가진 행을 제거한 후 중앙값 구하기 

 

ns_book7['대출건수'].drop_duplicates().median()

 

 

 

3) 최솟값, 최댓값 구하기 

 

- 판다스에서는 각각 min() 메서드와 max() 메서드를 제공한다. 

 

ns_book7['대출건수'].max()

 

ns_book7['대출건수'].min()

 

 

4) 분위수 구하기 

 

- 분위수(quantile)은 데이터를 순서대로 늘어 놓았을 때 이를 균등한 간격으로 나누는 기준점 

- 사분위수(quartile)는 정렬된 데이터를 네 구간으로 나눈다. 

 

 

quantile() 메서드 

- 판다스에서 분위수 값을 계산할 때는 quantile() 메서드를 사용한다. 

- 하위 25%에 위치한 값을 출력하려면 0.25를 입력한다. 

 

ns_book7['대출건수'].quantile(0.25)

 

- quantile() 메서드에 여러 개의 분위수를 지정할 수도 있다. 

ns_book7['대출건수'].quantile([0.25,0.5,0.75])

 

 

- 이처럼 quantile() 메서드에 여러 개의 분위수를 지정하면 각 분위수에 해당하는 값을 담은 시리즈 객체를 반환한다. 

- 1,2,3,4,5 다섯 개의 숫자가 있을 때 90% 위치에 있는 값은 4.6이 나온다. 

pd.Series([1,2,3,4,5]).quantile(0.9)

 

 

- quantile() 메서드는 interpolation 매개변수에서 중간 값을 계산하는 방법을 결정한다. 위 코드는 interpolation 매개변수를 따로 지정하지 않아서 기본값으로 계산되었다. 

- 기본값은 'linear'로 양쪽 분위수에 비례하여 결정된다. 

- 두 지점 사이에 놓인 특정 위치의 값을 구하는 방법을 보간(interpolation)이라고 한다. 

 

백분위 구하기 

 

- '대출건수' 열의 값이 10보다 작은지 비교하여 불리언 배열을 만든다. 

borrow_10_flag = ns_book7['대출건수'] < 10

 

- 이렇게 변환한 borrow_10_flag 배열에서 True인 개수를 모두 헤아린 후 전체 데이터 개수로 나누면 10보다 작은 대출 건수의 비율을 얻을 수 있다. 

 

- 판다스에서 불리언 자료를 산술 연산하면 True는 1, False는 0으로 취급한다. 따라서 다음처럼 borrow_10_flag 배열에서 mean() 메서드를 호출하여 평균을 구하면 10보다 작은 값이 차지하는 비율을 간단히 얻을 수 있다. 

 

borrow_10_flag.mean()

 

- 10에 대한 백분위는 0.65 정도가 된다. quantile() 메서드의 백분위를 넣어 직접 확인해보면 기대했던 10이 출력된다. 

ns_book7['대출건수'].quantile(0.65)

 

 

5) 분산 구하기 

 

- 분산(variance)은 평균으로부터 데이터가 얼마나 퍼져있는지를 나타내는 통계량이다. 

- 데이터가 가운데 모여 있다면 분산이 작고 넓게 펴져 있다면 분산이 크다.

- 분산은 데이터의 각 값에서 평균을 뺀 다음 제곱한 후 평균처럼 샘플 개수로 나누어 구할 수 있다. 

 

- 데이터의 각 값에서 평균을 빼면 데이터가 서로 얼마나 멀리 떨어져 잇는지 알 수 있다. 또 제곱하면 음수가 되는 것을 막아서 평균을 중심으로 좌우의 값이 서로 상쇄되지 않도록 만들어 준다.

 

- 판다스에는 분산을 계산하는 var() 메서드가 있다. 

 

ns_book7['대출건수'].var()

 

 

 

6) 표준편차 구하기 

 

- 표준편차(standard deviation)는 분산에 제곱근을 한 것으로 수식 기호는 s를 사용한다. 

- 분산을 계산했다면 표준편차는 제곱근만 씌우면 되기 때문에 간단하다. 

 

 

- 판다스에서 표준편차를 계산할 때는 std() 메서드를 활용한다. 

ns_book7['대출건수'].std()

 

 

7) 최빈값 구하기 

 

- 최빈값(mode)는 데이터에서 가장 많이 등장하는 값을 의미한다. 

- 판다스에서 mode() 메서드는 최빈값을 계산한다. 

 

ns_book7['도서명'].mode()

 

- mode() 메서드는 텍스트뿐만 아니라 수치형에도 적용할 수 있다. 

- 남산도서관 대출 데이터에서 가장 많이 등장하는 연도가 무엇인지 알아보기 

ns_book7['발행년도'].mode()

 

2. 분포 요약하기 

 

1) 산점도 그리기 

 

 

- 산점도는 데이터를 화면에 뿌리듯 그리는 그래프이다. 

- 두 변수(variable) 혹은 두 가지 특성(feature)값을 직교 좌표계에 점으로 나타내는 그래프이다. 

- 2차원 데이터를 나타낼 때 수평축을 x축, 수직축을 y축이라고 한다. 

- 파이썬에서 그래프를 그리는 데 사용하는 대표적인 패키지는 맷플롯립(matplotlib)이다. 

 

import pandas as pd

ns_book7 = pd.read_csv('ns_book7.csv', low_memory=False)
ns_book7.head()

 

 

- 맷플롯립에서 제공하는 그래프 함수는 matplotlib.pyplot 패키지 아래에 있다. 

 

scatter() 함수 

- 산점도는 scatter() 함수로 그린다. 

- 첫 번째 매개변수 4개 포인트의 x축 좌표를 전달하고 두 번째 매개변수에 y축 좌표를 전달한다. 

- scatter() 함수를 호출한 다음에는 show() 함수를 호출하여 그래프를 출력한다. 

 

import matplotlib.pyplot as plt

plt.scatter([1,2,3,4], [1,2,3,4])
plt.show()

 

 

- 남산도서관 대출 데이터를 사용해 산점도를 그리기

- 맷플롯립은 편리하게도 x축과 y축 값으로 데이터프레임의 열을 입력받을 수 있다. 

- 남산도서관 대출 데이터 중에서 '번호' 열의 값을 x축에 넣고 '대출건수' 열의 값을 y축에 넣어보겠다. 

 

plt.scatter(ns_book7['번호'], ns_book7['대출건수'])
plt.show()

 

 

- 대출건수(y축의 값)은 번호(x축의 값)을 따라 비교적 고르게 퍼져 있다. 

 

- '도서권수'와 '대출건수' 열의 산점도 

plt.scatter(ns_book7['도서권수'], ns_book7['대출건수'])
plt.show()

 

 

- 대부분의 도서가 1~2권이기 때문에 x축 0~10 범위인 왼쪽 아래 모서리 부분에 같은 값을 가진 데이터 포인트가 중첩되서 그려진다. 이럴 때는 산점도에 투명도를 주면 중첩된 데이터 포인트를 가늠하기 좋다. 

 

투명도 조절하기 

 

- 맷플롯립은 alpha 매개변수 0~1 사이의 값으로 투명도를 지정할 수 있다. 

plt.scatter(ns_book7['도서권수'], ns_book7['대출건수'], alpha=0.1)
plt.show()

 

 

 

- 도서권수가 대부분 작은 값이기 때문에 도서권수와 대출건수 사이의 관계를 파악하기 어렵다. 

- '도서권수' 열 대신에 '대출건수' 열을 '도서권수'열로 나눈 값을 사용 

- 도서권수 당 대출건수를 x축에 두고 대출건수를 y축에 놓는다. 

 

average_borrows = ns_book7['대출건수']/ns_book7['도서권수']
plt.scatter(average_borrows, ns_book7['대출건수'], alpha=0.1)
plt.show()

 

 

 

- 출력된 그래프를 보면 x축(도서권수 당 대출건수)이 증가함에 따라 y축(대출건수)가 증가하는 것을 뚜렷하게 볼 수 있다. 

- 두 특성 사이에는 '양의 상관관계가 있다'고 말할 수 있다. 

 

 

2) 히스토그램 그리기 

 

- 히스토그램은 수치형 특성의 값을 일정한 구간(bin)으로 나누어 구간 안에 포함된 데이터 개수를 막대 그래프로 그린것이다. 

- 구간 안에 속한 데이터 개수를 도수(frequency)라고 부른다. 

- 히스토그램은 하나의 특성에 대한 분포를 확인하기 좋다. 

 

plt.hist([0,3,5,6,7,7,9,13], bins=5)
plt.show()

 

 

hist() 함수 

 

- 맷플롯립으로 히스토그램으로 그릴 때는 hist() 함수를 사용한다. hist() 함수는 1차원 데이터를 입력받아 히스토그램을 그리며, 기본적으로 데이터를 10개의 구간으로 나눈다. 

- 8개의 정수로 이루어진 간단한 데이터를 사용한다. bins 매개변수를 5로 지정하여 5개의 구간으로 그리기 

 

plt.hist([0,3,5,6,7,7,9,13], bins=5)
plt.show()

 

 

- 히스토그램의 구간을 정확하게 확인하기 위해 넘파이에서 제공하는 histogram_bin_edges() 함수를 사용 

- 다섯 구간의 경곗값을 출력 

import numpy as np

np.histogram_bin_edges([0,3,5,6,7,7,9,13], bins=5)

 

 

- 랜덤한 실수 1000개 데이터를 만들어 히스토그램 그리기 

- randn() 함수는 표준정규분포를 따르는 랜덤한 실수를 생성할 수 있다. 

- seed() 함수를 사용하면 유사난수(pseudorandom number)를 생성할 수 있다. 

 

np.random.seed(42)
random_samples = np.random.randn(1000)

 

- random_samples 배열이 표준정규분포를 따르고 있는지 확인하기 위해 평균과 표준편차 계산 

print(np.mean(random_samples), np.std(random_samples))

 

 

- random_samples의 평균이 약 0.02, 표준편차가 약 0.98이므로 표준정규분포를 따르고 있다고 볼 수 있다. 

- 평균이 0, 표준편차가 1에 가까울수록 표준정규분포를 따른다고 볼 수 있다. 

- 히스토그램을 그려서 종 모양의 분포가 나오는지 확인해 보면, 다음과 같이 평균 0을 중심으로 볼록한 종 모양의 분포가 그려지는 것을 알 수 있다. 

 

plt.hist(random_samples)
plt.show()

 

 

- '대출건수'열의 히스토그램 

plt.hist(ns_book7['대출건수'])
plt.show()

 

 

 

구간 조정하기 

 

- 한 구간의 도수가 너무 커서 다른 구간에는 도수가 표시되지 않은 현상이 발생하면 y축을 로그 스케일로 바꾸어 해결할 수 있다 

- 로그 스케일(log scale)로 바꾼다는 것은 y축에 로그함수를 적용한다는 의미이다. 

 

 

- 맷플롯립에서 y축을 로그 스케일로 바꾸려면 다음 처럼 yscale() 함수에 'log'를 지정하면 된다. 

- 맷플롯립은 기본적으로 밑이 10인 로그함수를 사용 

 

plt.hist(ns_book7['대출건수'])
plt.yscale('log')
plt.show()

 

 

- hist() 함수는 기본 10개 구간을 사용한다. bins 매개변수에서 이를 100으로 바꾸면 데이터 분포를 조금 더 세밀하게 관찰할 수 있다. 

 

plt.hist(ns_book7['대출건수'], bins=100)
plt.yscale('log')
plt.show()

 

- 대출건수 0이 가장 많고 대출건수가 증가함에 따라 도수가 줄어든다. 

 

- '도서명'열에 apply() 메서드를 사용하여 파이썬의 len() 함수를 적용하면 title_len 변수는 각 도서명의 길이가 저장된 판다스 시리즈 객체가 된다. 이를 100개의 구간을 가진 히스토그램으로 그려보기 

 

title_len = ns_book7['도서명'].apply(len)
plt.hist(title_len, bins=100)
plt.show()

 

 

'

- y축에 로그 스케일을 적용했던 것처럼 x축에도 로그스케일을 적용할 수 있다. 이렇게 하면 x축을 따라 작은 값과 큰 값의 차이가 줄어들 것이다. y축에 로그 스케일을 적용하는 yscale() 함수와 비슷하게 xscale() 함수를 사용하면 된다. 

 

plt.hist(title_len, bins=100)
plt.xscale('log')
plt.show()

 

 

 

3) 상자 수염 그림 그리기 

 

- 상자 수염 그림은 최솟값, 세 개의 사분위수, 최댓값 이렇게 다섯 개의 숫자를 이용해 데이터를 요약하는 그래프를 그린다. 

 

상자수염 그리는 방법 

  1. 먼저 사분위수를 계산한다. 25%와 75% 지점을 밑면과 윗면으로 하는 직사각형을 그린다. 
  2. 중간값 즉, 50%에 해당하는 지점에 수평선을 긋는다. 
  3. 사각형의 밑면과 윗면에서 사각형의 높이의 1.5배만큼 떨어진 거리 안에서 가장 멀리 있는 샘플까지 수직선을 긋는다. 
  4. 이 수직선 밖에서 최솟값과 최댓값까지 데이터를 점으로 표시한다. 이 영역의 데이터를 이상치(outlier)라고 부른다. 

 

 

boxplot 함수

- 맷플롯립에서 상자 수염 그림은 boxplot() 함수로 그린다. 

- 한 개 이상의 데이터프레임 열을 전달하여 그래프를 그린다. 

 

temp = ns_book7[['대출건수','도서권수']]
plt.boxplot(temp)
plt.show()

 

 

- 상자 수염 그림을 조금 더 보기 좋게 y축을 로그 스케일로 바꾸기 

 

plt.boxplot(ns_book7[['대출건수','도서권수']])
plt.yscale('log')
plt.show()

 

 

 

상자 수염 그림 수평으로 그리기 

 

- boxplot() 함수의 vert 매개변수를 기본값 True에서 False로 바꾸면 되다. 

- x-y축이 바뀌므로 로그 스케일도 x축에 지정해야 한다. 히스토그램과 마찬가지로 xscale() 함수를 사용한다. 

 

plt.boxplot(ns_book7[['대출건수','도서권수']], vert=False)
plt.xscale('log')
plt.show()

 

 

 

수염 길이 조정하기 

 

- boxplot() 함수의 whis 매개변수에서 수염 길이를 조정할 수 있다. 

- 기본 값 1.5를 10으로 바꾸어서 IQR의 10배 범위 안에서 가장 멀리 떨어진 데이터까지 수염을 그리기 

 

plt.boxplot(ns_book7[['대출건수','도서권수']], whis=10)
plt.yscale('log')
plt.show()

 

 

- whis 매개변수는 백분율로도 지정할 수 있다. 

- 예를 들어 (10,90)으로 지정하면 10%, 90% 백분위수에 해당하는 데이터까지 수염을 그린다. 

 

plt.boxplot(ns_book7[['대출건수','도서권수']], whis=(0,100))
plt.yscale('log')
plt.show()