본문 바로가기
혼자 공부하는 데이터 분석

4장 데이터 요약하기

by chaechaekim 2023. 5. 29.

04-1 통계로 요약하기

 

기술통계: 자료의 내용을 압축하여 설명하는 방법

탐색적 데이터 분석: 데이터 시각화를 아우르는 데이터 분석 방법

 

기술통계 구하기

03-2절에서 만든 ns_book6.csv 파일 다운로드

import gdown
gdown.download('https://bit.ly/3736JW1', 'ns_book6.csv', quiet=False)

 

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

import pandas as pd

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

 

ns_book6 데이터프레임에서 describe() 메서드 호출

ns_book6.describe()

*describe() 메서드: 기본적으로 수치형 열에 대한 요약 통계

  • count: 누락된 값을 제외한 데이터 개수를 나타낸다.
  • mean: 평균을 구한다.
  • std: 표준편차를 구한다.
  • min: 최솟값을 구한다.
  • 50%: 중앙값을 구한다.
  • 25% 와 75%: 순서대로 늘어 놓았을 때 25% 지점과 75% 지점에 놓인 값이다.
  • max: 최댓값을 구한다.

 

불리언 배열과 sum() 함수를 활용하여 도서권수가 0인 도서의 행 개수를 카운트

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

 

실제로 없는 도서 대출 데이터 제외

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

 

describe() 메서드: 원하는 위치의 값을 보고 싶다면 percentiles 매개변수에 위치를 지정하면 된다.

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

 

object 타입의 열에 대한 통계

ns_book7.describe(include='object')

*다른 데이터 타입의 열의 기술 통계를 보고 싶다면 include 매개변수에 데이터 타입 지정

 

평균 구하기

평균: 비교적 쉽게 이해할 수 있는 통계량

 

range() 함수: 하나의 숫자를 입력할 경우 0부터 입력된 숫자 직전까지 반복할 수 있는 객체를 만들어준다.

x = [10, 20, 30]
sum = 0
for i in range(3):
    sum += x[i]
print("평균:", sum / len(x))

 

  • mean() 메서드
ns_book7['대출건수'].mean()

 

중앙값 구하기

  • median() 메서드

ns_book7 데이터프레임에서 '대출건수' 열을 선택

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

 

데이터 개수가 짝수이면 가운데 두 값을 평균하여 중앙값 결정

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

 

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

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

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

 

최솟값, 최댓값 구하기

판다스 min(), max() 메서드

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

 

분위수 구하기

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

사분위수: 순서대로 정렬된 데이터를 네 구간으로 나눈다.

25%: 제1사분위수

중앙값: 제2사분위수

75%: 제3사분위수

 

  • quantile() 메서드

하위 25%에 위치한 값 출력 → 0.25 입력

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

 

여러 개 분위수 지정

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

 

1,2,3,4,5 다섯 개 숫자가 있을 때 90% 위치에 있는 값 찾기

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

 

*quantile() 메서드는 interpolation 매개변수에서 중간 값을 계산하는 방법 사용

→ 위 코드는 따로 지정하지 않아서 기본값으로 계산되었다.

*보간: 두 지점 사이에 놓인 특정 위치의 값을 구하는 방법

 

  • 백분위 구하기

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

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

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

*판다스에서 불리언 자료를 산술 연산하면 True는 1, False는 0으로 취급한다.

 

mean() 메서드를 호출하여 평균을 구하면 10보다 작은 값이 차지하는 비율을 간단히 얻을 수 있다.

borrow_10_flag.mean()

 

quantile() 메서드에 백분위를 넣어 확인

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

 

분산 구하기

분산: 평균으로부터 데이터가 얼마나 퍼져있는지를 나타내는 통계량

  • var() 메서드

대출건수 분산 구하기

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

 

표준편차 구하기

표준편차: 분산에 제곱근을 한 것으로 수식 기호는 s를 사용

  • std() 메서드

대출건수 표준편차 계산

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

 

최빈값 구하기

최빈값: 데이터에서 가장 많이 등장하는 값을 의미

  • mode() 메서드

도서명에서 가장 많이 등장하는 값 찾기

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

 

수치형에도 적용 가능: 가장 많이 등장하는 연도 알아보기

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

 

데이터프레임에서 기술통계 구하기

수치형 열만 연산할 수 있기 때문에 해당 열에만 적용되도록 numeric_only 매개변수를 True로 지정

 

ns_book7 데이터프레임에서 mean() 메서드를 호출하면 수치형인 4개의 열에 대한 평균값 계산

ns_book7.mean(numeric_only=True)

*numeric_only 매개변수를 지정하지 않으면 모든 데이터 타입의 열에 대해 수행하기 때문에 시간이 매우 오래 걸린다.

 

loc 메서드로 '도서명'열부터 마지막 열까지에 대해 최빈값 찾기

ns_book7.loc[:, '도서명':].mode()

 

ns_book7 데이터프레임을 csv 파일로 저장

ns_book7.to_csv('ns_book7.csv', index=False)

 

넘파이 기술통계 함수

  • 평균 구하기

mean() 함수와 average() 함수 사용

import numpy as np

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

 

 average() 함수는 weights 매개변수에 가중치를 제공하면 가중 평균 계산

np.average(ns_book7['대출건수'], weights=1/ns_book7['도서권수'])

 

대출건수 열을 도서권수 열로 나누기

np.mean(ns_book7['대출건수']/ns_book7['도서권수'])

 

전체 대출건수를 모두 더한 다음 전체 도서권수로 나누기

ns_book7['대출건수'].sum()/ns_book7['도서권수'].sum()

 

  • 중앙값 구하기

median() 함수

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

 

  • 최솟값, 최댓값 구하기

min(), max() 함수

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

 

  • 분위수 구하기

quantile() 함수

# interpolation 매개변수가 numpy 1.22(python >= 3.8) 버전부터 method로 바뀜
np.quantile(ns_book7['대출건수'], [0.25,0.5,0.75])

 

  • 분산 구하기

var() 함수

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

*넘파이의 var() 함수는 n으로 나누기 때문에 판다스와 결과가 다르다.

*ddof 매개변수를 사용하여 자유도 차감값 지정

 

ns_book7['대출건수'].var(ddof=0)
np.var(ns_book7['대출건수'], ddof=1)

 

  • 표준편차 구하기

std() 함수

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

 

  • 최빈값 구하기

직접적으로 최빈값을 계산하는 함수 제공하지 않는다.

unique() 함수는 배열에서 고유한 값을 찾아준다.

return_counts 매개변수를 기본값 False에서 True로 바꿔 주면 고유한 값의 등장 횟수 반환

 

unique() 함수를 호출해 고유한 값과 등장 횟수 배열 얻기

values, counts = np.unique(ns_book7['도서명'], return_counts=True)

 

argmax() 함수를 사용하여 counts 배열에서 가장 큰 값의 인덱스 찾기

max_idx = np.argmax(counts)

 

values 배열에서 해당 인덱스의 값을 출력

values[max_idx]

 

정리

함수/메서드 기능
DataFrame.describe() 데이터프레임의 기술통계량을 출력한다.
Series.mean() 데이터에서 평균을 계산한다.
numpy.mean() 입력된 배열의 평균을 계산한다.
Series.median() 데이터에서 중앙값을 찾는다.
numpy.median() 입력된 배열의 중앙값을 찾는다.
Series.quantile() 데이터에서 분위수를 계산한다.

04-2 분포 요약하기

 

산점도 그리기

산점도: 데이터를 화면에 뿌리듯 그리는 그래프; 두 변수 혹은 두 가지 특성값을 직교 좌표계에 점으로 나타내는 그래프

맷플롯립: 파이썬에서 그래프를 그리는 데 사용하는 대표적인 패키지

# 맷플롯립 3.2.2 버전에서 상자 수염 그림을 그리는데 버그가 있습니다
# 코랩을 사용하시는 경우 matplotlib을 최신 버전으로 업데이트해 주세요.
!pip install -U matplotlib

 

ns_book7.csv 파일 다운

import gdown

gdown.download('https://bit.ly/3pK7iuu', 'ns_book7.csv', quiet=False)

 

판다스 데이터프레임으로 불러오기

import pandas as pd

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

 

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

import matplotlib.pyplot as plt

 

  • scatter() 함수

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

→ show() 함수 호출하여 그래프 출력

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

 

 

남산도서관 대출 데이터 중에서 '번호'열의 값을 x축에 넣고 '대출건수'열의 값을 y축에 넣기

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

첫 번째 매개변수에는 x축에 해당하는 '도서권수'열을 지정하고 두 번째 매개변수에는 y축에 해당하는 '대출건수'열 지정

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

  • 투명도 조절하기

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

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

*0에 가까울수록 투명하고 1에 가까울수록 불투명하게 그려진다.

*도서권수와 대출건수 사이의 관계란 도서권수가 많으면 대출건수도 많다던가, 도서권수가 적을수록 대출건수가 많다는 식

전자 양의 상관관계, 후자 음의 상관관계

 

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

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

→ 두 값은 양의 상관관계를 가질 것

 

'대출건수'열을 '도서권수'열로 나눈 값을 average_borrows 변수에 저장하고, 이 변수와 '대출건수'열을 차례대로 scatter() 함수에 전달

alpha 매개변수는 0.1로 지정

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

 

히스토그램 그리기

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

도수: 구간 안에 속한 데이터 개수

 

  • hist() 함수

: 1차원 데이터를 입력받아 히스토그램을 그리며, 기본적으로 데이터를 10개의 구간으로 나눈다.

 

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)

 

더 많은 데이터를 가상으로 만들어 히스토그램 그리기

원하는 샘플 개수를 전달하여 난수 생성

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

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

*seed() 함수: 유사난수를 생성할 수 있다.

 

1,000개 실수로 이루어진 random_samples 배열이 표준정규분포를 따르고 있는지 확인하기 위해 평균와 표준편차 계산

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

 

히스토그램 그려서 종 모양의 분포가 나오는지 확인 → 평균 0을 중심으로 볼록한 종 모양의 분포(전형적인 정규분포 형태)

plt.hist(random_samples)
plt.show()

 

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

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

 

  • 구간 조정하기

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

로그스케일로 바꾼다는 것은 다음 그림처럼 y축에 로그 함수를 적용한다는 의미

큰 값일수록 도수 크기가 많이 줄어들어 작은 값과의 차이가 줄어든다.

 

맷플롯립에서 y축을 로그 스케일로 바꾸려면 yscale() 함수에 'log' 지정

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

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

 

x축 구간을 세세하게 나눠보기

: hist() 함수는 기본 10개 구간 사용 → bins 매개변수에서 이를 100으로 바꾸면 데이터 분포를 더 세밀하게 관찰 가능

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

 

'도서명'열에 apply() 메서드를 사용하여 파이썬의 len() 함수를 적용하면 title_len 변수는 각 도서명의 길이가 저장된 판다스 시리즈 객체가 된다.

→ 100개 구간을 가진 히스토그램으로 그리기

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

 

x축에 데이터가 골고루 그려지도록 바꾸기

: xscale() 함수 사용

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

 

상자 수염 그림 그리기

: 최솟값, 3개의 사분위수, 최댓값 이렇게 5개의 숫자를 사용해 데이터를 요약하는 그래프를 그린다.

*상자 수염 그리는 방법

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

*IQR:제1사분위수와 제3사분위수 사이의 거리

 

  • boxplot() 함수

 

한 개 이상의 데이터프레임열을 전달하여 그래프 그리기

temp = ns_book7[['대출건수','도서권수']]

plt.boxplot(temp)
plt.show()

 

보기 좋게 y축을 로그 스케일로 바꾸기

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

 

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

: vert 매개변수를 기본값 True에서 False로 바꾼다.

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

*x-y축이 바뀌므로 로그 스케일도 x축에 지정해야 한다.

 

  • 수염 길이 조정하기

: 기본적으로 수염의 길이는 IQR의 1.5배 → whis 매개변수에서 조정 가능

 

IQR의 10배 범위 안에서 가장 멀리 떨어진 데이터까지 수염 그리기

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

 

whis 매개변수는 백분율로도 지정 가능

(0, 100)으로 지정하여 마지막 데이터까지 수염 그리기

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

 

판다스의 그래프 함수

  • 산점도 그리기

scatter() 메서드: x축과 y축에 해당하는 열 이름만 지정

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

*열 이름이 한글일 때는 실행 결과처럼 제대로 출력되지 않는다.

 

  • 히스토그램 그리기

: 데이터프레임에 apply() 메서드를 적용한 다음 이어서 바로 plot.hist() 메서드를 호출

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

 

  • 상자 수염 그림 그리기

: boxplot() 메서드

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

 

정리

함수/메서드 기능
Matplotlib.pyplot.scatter() 2차원 평면에 산점도를 그린다.
Matplotlib.pyplot.hist() 히스토그램을 그린다.
Matplotlib.pyplot.boxplot() 상자 수염 그림을 그린다.
Matplotlib.pyplot.xscale() x축의 스케일을 지정한다.
Matplotlib.pyplot.yscale() y축의 스케일을 지정한다.
numpy.random.seed() 원하는 임의의 정수를 입력하면 난수 발생을 동일하게 재현할 수 있다.
numpy.random.randn() 표준정규분포를 따르는 난수를 생성한다.

 

댓글