작성자: admin 작성일시: 2016-04-14 22:02:36 조회수: 3259 다운로드: 144
카테고리: Python 태그목록:

파이썬으로 데이터 분포 살펴보기

분포

데이터의 수가 적으면 데이터의 값을 하나 하나 살펴볼 수 있지만 데이터의 수가 많다면 숫자가 어떤 값 근처에 어떤 모양으로 모여 있는지 전반적인 형태를 살펴보는 수밖에 없다. 데이터 값의 전반적인 형태를 데이터의 분포(distribution)라고 한다.

일차원 데이터의 분포를 살펴보는 데는 다음과 같은 방법을 사용할 수 있다.

  • 기술 통계 (descriptive statistics)
  • 히스토그램 (histogram)
  • 커널 밀도 (kernel density)

기술 통계

기술 통계(descriptive statistics)는 데이터 분포의 특징을 대표할 수 있는 몇가지 숫자를 계산하여 이 숫자들로부터 데이터의 분포를 추측하는 방법이다. 흔히 일반인들이 통계라고 부르는 것이 바로 기술 통계를 말한다.

데이터의 분포의 특징을 대표하는 값들로는

  • 데이터의 숫자 (count)
  • 평균 (mean, average)
  • 분산 (variance)
  • 표준 편차 (standard deviation)
  • 최댓값 (maximum)
  • 최솟값 (minimum)
  • 중앙값 (median)
  • 사분위수 (quartile)

등이 많이 사용된다. 이러한 기술 통계 수치들을 분포의 특성이라고도 한다.

데이터가 $x_1, x_2, \cdots, x_N$ 일때, 평균은 보통 $\bar{x}$라고 표시하며 다음과 같이 계산된다. $$ \bar{x} = \dfrac{1}{N}\sum_{i=1}^N x_i $$

분산은 보통 $s^2$이라고 표시하며 계산된 평균 $\bar{x}$를 이용하여 다음과 같이 계산된다. $$ s^2 = \dfrac{1}{N}\sum_{i=1}^N (x_i - \bar{x})^2 $$

표준 편차는 보통 $s$이라고 표시하며 분산의 제곱근 값이다. $$ s = \sqrt{s^2} $$

최댓값은 데이터 중에서 가장 큰 값을, 최솟값은 가장 작은 값을 의미한다.

중앙값은 데이터를 크기대로 정렬하였을 때 가장 가운데에 있는 수를 말한다. 만약 데이터의 수가 짝수이면 보통 중앙의 두 수의 평균을 사용한다.

사분위수(quartile)는 데이터를 크기대로 정렬하였을 때 1/4, 2/4, 3/4 위치에 있는 수를 말한다. 1/4의 위치란 전체 데이터의 수가 만약 100개이면 25번째 순서를 말한다. 따라서 2사분위수는 중앙값과 같다.

때로는 위치를 1/100 단위로 나눈 백분위수(percentile)을 사용하기도 한다. 1사분위수는 25% 백분위수와 같다.

예를 들어 다음과 같은 데이터가 있다고 하자.

In:
x = np.array([ 18,   5,  10,  23,  19,  -8,  10,   0,   0,   5,   2,  15,   8,
                2,   5,   4,  15,  -1,   4,  -7, -24,   7,   9,  -6,  23, -13,
                1,   0,  16,  15,   2,   4,  -7, -18,  -2,   2,  13,  13,  -2,
               -2,  -9, -13, -16,  20,  -4,  -3, -11,   8, -15,  -1,  -7,   4,
               -4, -10,   0,   5,   1,   4,  -5,  -2,  -5,  -2,  -7, -16,   2,
               -3, -15,   5,  -8,   1,   8,   2,  12, -11,   5,  -5,  -7,  -4])

이 데이터의 기술 통계값을 구하는 파이썬 명령어는 각각 다음과 같다.

In:
len(x)  # 갯수
Out:
78
In:
np.mean(x) # 평균
Out:
0.69230769230769229
In:
np.var(x) # 분산
Out:
96.059171597633139
In:
np.std(x)  # 표준 편차
Out:
9.8009780939268065
In:
np.max(x)  # 최댓값
Out:
23
In:
np.min(x)  # 최솟값
Out:
-24
In:
np.median(x)  # 중앙값
Out:
0.5
In:
np.percentile(x, 25)  # 1사분위 수
Out:
-5.75
In:
np.percentile(x, 50)  # 2사분위 수
Out:
0.5
In:
np.percentile(x, 75)  # 3사분위 수
Out:
5.0

SciPy 패키지와 Pandas 패키지에는 이러한 기술 통계값을 한번에 계산하는 명령도 있다.

In:
sp.stats.describe(x)
Out:
DescribeResult(nobs=78, minmax=(-24, 23), mean=0.69230769230769229, variance=97.306693306693305, skewness=0.11586487731702556, kurtosis=-0.15461828136911615)
In:
s = pd.Series(x)
s.describe()
Out:
count    78.000000
mean      0.692308
std       9.864416
min     -24.000000
25%      -5.750000
50%       0.500000
75%       5.000000
max      23.000000
dtype: float64

히스토그램

히스토그램은 자료 값이 가질 수 있는 범위를 몇 개의 구간으로 나누고 각 구간에 해당하는 값의 숫자 혹은 상대적 빈도를 계산하는 방법이다.

파이썬에서 히스토그램을 구하거나 그리기 위해서는 다음과 같은 명령을 사용한다.

matplotlib 패키지의 hist 함수는 다음과 같은 3개의 값을 반환한다.

  • n : 각 구간에 포함된 값의 갯수 혹은 빈도 리스트
  • bins : 구간의 경계값 리스트
  • patches : 각 구간을 그리는 matplotlib patch 객체 리스트

위의 자료에 대해 히스토그램을 그리면 아래와 같다.

In:
n, bins, patches = plt.hist(x, bins=10)
plt.show()
In:
n
Out:
array([  1.,   5.,   5.,   9.,  15.,  18.,  10.,   6.,   5.,   4.])
In:
bins
Out:
array([-24. , -19.3, -14.6,  -9.9,  -5.2,  -0.5,   4.2,   8.9,  13.6,
        18.3,  23. ])
In:
patches

seaborn 패키지의 displot명령은 히스토그램에 대한 axis 객체만을 반환하는 대신 러그(rug), 커널 밀도(kernel density) 등을 표시하거나 특정한 확률 모형으로 fitting하는 추가 기능이 있다.

In:
sns.distplot(x, rug=True)
plt.show()

앞의 그림에서 곡선으로 나타난 것이 커널 밀도이다. 커널 밀도는 커널이라고 하는 특정 구간의 분포를 묘사하는 함수의 집합을 사용하여 전체 분포를 묘사하는 방법이다. 커널 밀도를 사용하면 분포의 전체 모양을 파악하기가 더 쉽다.

커널 밀도에 관한 자세한 내용은 scikit-learn 패키지의 사용자 가이드와 예제를 참조한다.

다차원 데이터 분포를 묘사하는 경우

다차원 데이터 분포는 순서가 정해진 여러개의 일차원 데이터가 있는 것과 같다.

만약 2차원 데이터이고 각 데이터가 모두 연속적인 실수값이라면 스캐터 플롯(scatter plot)을 사용하면 된다. 스캐터 플롯을 그리기 위해서는 seaborn 패키지의 jointplot 명령을 사용한다. jointplot 명령은 스캐터 플롯뿐 아니라 각 변수의 히스토그램도 동시에 그린다.

다음 데이터는 붓꽃의 꽃잎의 길이, 꽃잎의 폭, 꽃받침의 길이, 꽃받침의 폭, 그리고 종(species)을 나타낸 데이터이다.

In:
iris = sns.load_dataset("iris")
iris.tail()
Out:
sepal_length sepal_width petal_length petal_width species
145 6.7 3.0 5.2 2.3 virginica
146 6.3 2.5 5.0 1.9 virginica
147 6.5 3.0 5.2 2.0 virginica
148 6.2 3.4 5.4 2.3 virginica
149 5.9 3.0 5.1 1.8 virginica
In:
sns.jointplot(x="sepal_length", y="sepal_width", data=iris)
plt.show()

또한 인수를 바꾸면 커널 밀도의 형태로도 표시할 수 있다.

In:
sns.jointplot(x="sepal_length", y="sepal_width", data=iris, kind="kde", space=0, zorder=0, n_levels=6)
plt.show()

만약 3차원 이상의 데이터라면 seaborn 패키지의 pairplot 명령을 사용한다. pairplot은 그리도(grid) 형태로 각 집합의 조합에 대해 히스토그램과 스캐터 플롯을 그린다.

In:
sns.pairplot(iris, hue="species", markers=["o", "s", "D"], size=2)
plt.show()