이번 포스팅에서는 국가통계포털 사이트에서 받은 2020년, 2021년도 실업률과 취업자 수 통계 데이터를 가지고 R의 dplyr과 ggplot2 패키지를 사용해서 아래의 데이터 전처리 및 시각화하는 방법을 소개하겠습니다. 

 

1. 취업자 수 증가율(%) 변수 계산 (전년 동월 대비)

2. 실업률과 취업자 수 증가율 변수의 평균, 분산, 표준편차, 중앙값, 최대값, 최소값 계산

3. 실업률과 취업자 수 증가율 변수의 시계열 그래프 그리기

4. 실업률과 취업자 수 증가율 변수의  히스토그램 그리기 (히스토그램의 구간은 10개)

 

 

먼저, 국가통계포털 사이트에서 받은 2020년, 2021년도 실업률과 취업자 수 통계 데이터를 입력해서 DataFrame을 만들어보겠습니다. 데이터 자료 구조를 어떻게 해서 만드는지 유심히 봐주세요. 

 

## making a dataframe
df <- data.frame(
  month=c("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"), 
  unemploy_rate_2020=c(4.1, 4.1, 4.2, 4.2, 4.5, 4.3, 4.0, 3.1, 3.6, 3.7, 3.4, 4.1), 
  unemploy_rate_2021=c(5.7, 4.9, 4.3, 4.0, 4.0, 3.8, 3.2, 2.6, 2.7, 2.8, 2.6, 3.5), 
  employed_num_2020=c(26800, 26838, 26609, 26562, 26930, 27055, 27106, 27085, 27012, 27088, 27241, 26526), 
  employed_num_2021=c(25818, 26365, 26923, 27214, 27550, 27637, 27648, 27603, 27683, 27741, 27795, 27298)
)

print(df)
#    month unemploy_rate_2020 unemploy_rate_2021 employed_num_2020 employed_num_2021
# 1     01                4.1                5.7             26800             25818
# 2     02                4.1                4.9             26838             26365
# 3     03                4.2                4.3             26609             26923
# 4     04                4.2                4.0             26562             27214
# 5     05                4.5                4.0             26930             27550
# 6     06                4.3                3.8             27055             27637
# 7     07                4.0                3.2             27106             27648
# 8     08                3.1                2.6             27085             27603
# 9     09                3.6                2.7             27012             27683
# 10    10                3.7                2.8             27088             27741
# 11    11                3.4                2.6             27241             27795
# 12    12                4.1                3.5             26526             27298

 

 

 

1. 취업자 수 증가율(%) 변수 계산 (전년 동월 대비)

 

dplyr 패키지로 새로운 변수를 생성하는 방법은 https://rfriend.tistory.com/235 를 참고하세요. 

dplyr 패키지의 chain operation, pipe operator %>% 사용 방법은 https://rfriend.tistory.com/236 를 참고하세요. 

 

## 1. 취업자 수 증가율(%) 변수 계산 (전년 동월 대비)
library(dplyr)
df2 <- df %>% 
  transform(
    employed_inc_rate = 100*(employed_num_2021 - employed_num_2020)/employed_num_2020) # percentage


print(df2)
#    month unemploy_rate_2020 unemploy_rate_2021 employed_num_2020 employed_num_2021 employed_inc_rate
# 1     01                4.1                5.7             26800             25818         -3.664179
# 2     02                4.1                4.9             26838             26365         -1.762426
# 3     03                4.2                4.3             26609             26923          1.180052
# 4     04                4.2                4.0             26562             27214          2.454634
# 5     05                4.5                4.0             26930             27550          2.302265
# 6     06                4.3                3.8             27055             27637          2.151174
# 7     07                4.0                3.2             27106             27648          1.999557
# 8     08                3.1                2.6             27085             27603          1.912498
# 9     09                3.6                2.7             27012             27683          2.484081
# 10    10                3.7                2.8             27088             27741          2.410662
# 11    11                3.4                2.6             27241             27795          2.033699
# 12    12                4.1                3.5             26526             27298          2.910352

 

 

 

2. 실업률과 취업자 수 증가율 변수의 평균, 분산, 표준편차, 중앙값, 최대값, 최소값 계산

 

dplyr 패키지로 데이터의 요약통계량을 계산하는 방법은 https://rfriend.tistory.com/235 를 참고하세요. 

여러개의 패키지별로 그룹별 요약통계량을 계산하는 방법은 https://rfriend.tistory.com/125 를 참고하세요. 

 

## 2. 실업률과 취업자 수 증가율 변수의 평균, 분산, 표준편차, 중앙값, 최대값, 최소값 계산
df2 %>% 
  summarise(
    unemploy_rate_2021_mean = mean(unemploy_rate_2021), 
    unemploy_rate_2021_var = var(unemploy_rate_2021), 
    unemploy_rate_2021_sd = sd(unemploy_rate_2021), 
    unemploy_rate_2021_median = median(unemploy_rate_2021), 
    unemploy_rate_2021_max = max(unemploy_rate_2021), 
    unemploy_rate_2021_min = min(unemploy_rate_2021)
  )

# unemploy_rate_2021_mean unemploy_rate_2021_var unemploy_rate_2021_sd 
#                   3.675              0.9547727             0.9771247
# 
# unemploy_rate_2021_median unemploy_rate_2021_max unemploy_rate_2021_min
#                      3.65                    5.7                    2.6


df2 %>% 
  summarise(
    employed_inc_rate_mean = mean(employed_inc_rate), 
    employed_inc_rate_var = var(employed_inc_rate), 
    employed_inc_rate_sd = sd(employed_inc_rate), 
    employed_inc_rate_median = median(employed_inc_rate), 
    employed_inc_rate_max = max(employed_inc_rate), 
    employed_inc_rate_min = min(employed_inc_rate)
  )

# employed_inc_rate_mean employed_inc_rate_var employed_inc_rate_sd 
#               1.367697              3.970439             1.992596
# 
# employed_inc_rate_median employed_inc_rate_max employed_inc_rate_min
#                 2.092436              2.910352             -3.664179

 

 

3. 실업률과 취업자 수 증가율 변수의 시계열 그래프 그리기

 

ggplot2 로 시계열 그래프 그리기는 https://rfriend.tistory.com/73 를 참고하세요. 

 

## 3. 실업률과 취업자 수 증가율 변수의 시계열 그래프 그리기 
library(ggplot2)

ggplot(df2, aes(x=month, y=unemploy_rate_2021, group=1)) +
  geom_line() +
  ylim(0, max(df2$unemploy_rate_2021)) +
  ggtitle("Time Series Plot of Unemployment Rate, Year 2021")

Time Series Plot of Unemployment Rate

 

 

ggplot(df2, aes(x=month, y=employed_inc_rate, group=1)) +
  geom_line() +
  ylim(min(df2$employed_inc_rate), max(df2$employed_inc_rate)) +
  ggtitle("Time Series Plot of Employment Increase Rate, Year 2021")

Time Series Plot of Employment Increase Rate

 

 

 

4. 실업률과 취업자 수 증가율 변수의  히스토그램 그리기 (히스토그램의 구간은 10개)

 

ggplot2 패키지로 히스토그램 그리기는 https://rfriend.tistory.com/67 를 참고하세요. 

 

ggplot(df2, aes(x=employed_inc_rate)) + 
  geom_histogram(bins=10) + 
  ggtitle("Histogram of Unemployment Rate, Year 2021")

Histogram of Unemployment Rate

 

 

ggplot(df2, aes(x=employed_inc_rate)) + 
  geom_histogram(bins=10) + 
  ggtitle("Histogram of Employment Incease Rate, Year 2021")

Histogram of Employment Increase Rate

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 PostgreSQL, Greenplum database에서 SQL, MADlib 함수, PL/R, PL/Python을 사용해서 연속형 데이터에 대한 요약통계량을 구하는 방법을 소개하겠습니다.  무척 쉬운 내용이므로 쉬어가는 코너 정도로 가볍게 생각해주시면 좋겠습니다. ^^


PostgreSQL, Greenplum database 에서 연속형 데이터에 대해 그룹별로, 

(1) SQL 로 요약통계량 구하기

(2) Apache MADlib 으로 요약통계량 구하기





참고로, 이번 포스팅에서는 PostgreSQL 9.4, Greenplum 6.10.1 버전을 사용하였으며, PostgreSQL 9.4 버전보다 낮은 버전을 사용하면 최빈값(mode), 사분위부(percentile) 구하는 함수를 사용할 수 없습니다. 


먼저, 예제로 사용하기 위해 '나이'의 연속형 데이터와 '성별'의 범주형 데이터 (그룹)를 가진 간단한 테이블을 만들어보겠습니다. 결측값(missing value)도 성별 그룹별로 몇 개 넣어봤습니다. 



DROP TABLE IF EXISTS cust;

CREATE TABLE cust (id INT, age INT, gender TEXT);

INSERT INTO cust VALUES

(1,NULL,'M'),

(2,NULL,'M'),

(3,25,'M'),

(4,28,'M'),

(5,27,'M'),

(6,25,'M'),

(7,26,'M'),

(8,29,'M'),

(9,25,'M'),

(10,27,'M'),

(11,NULL,'F'),

(12,23,'F'),

(13,25,'F'),

(14,23,'F'),

(15,24,'F'),

(16,26,'F'),

(17,23,'F'),

(18,24,'F'),

(19,22,'F'),

(20,23,'F');

 




 (1) SQL로 연속형 데이터의 그룹별 요약통계량 구하기


함수가 굳이 설명을 안해도 될 정도로 간단하므로 길게 설명하지는 않겠습니다. 


표준편차 STDDEV() 와 분산 VARIANCE() 함수는 표본표준편차(sample standard deviation), 표본분산(sample variance) 를 계산해줍니다. 만약 모표준편차(population standard deviation), 모분산(population variance)를 구하고 싶으면 STDDEV_POP(), VAR_POP() 함수를 사용하면 됩니다. 


PostgreSQL 9.4 버전 이상부터 최빈값(MODE), 백분위수(Percentile) 함수가 생겨서 정렬한 후에 집계하는 기능이 매우 편리해졌습니다. (MODE(), PERCENTILE_DISC() 함수를 사용하지 않고 pure SQL로 최빈값과 백분위수를 구하려면 query 가 꽤 길어집니다.)



SELECT

    gender AS group_by_value

    , 'age' AS target_column

    , COUNT(*) AS row_count

    , COUNT(DISTINCT age) AS distinct_values

    , AVG(age)

    , VARIANCE(age)

    , STDDEV(age)

    , MIN(age)

    , PERCENTILE_DISC(0.25) WITHIN GROUP (ORDER BY age) AS first_quartile

    , MEDIAN(age)

    , PERCENTILE_DISC(0.75) WITHIN GROUP (ORDER BY age) AS third_quartile

    , MAX(age)

    , MODE() WITHIN GROUP (ORDER BY age) -- over PostgreSQL 9.4

FROM cust

WHERE age IS NOT NULL

GROUP BY gender

ORDER BY gender;





성별 그룹별로 연령(age) 칼럼의 결측값 개수를 구해보겠습니다. 

결측값 개수는 WHERE age IS NULL 로 조건절을 주고 COUNT(*)로 행의 개수를 세어주면 됩니다. 



SELECT 

    gender

    , COUNT(*) AS missing_count

FROM cust

WHERE age IS NULL

GROUP BY gender

ORDER BY gender;


Out[5]:
gendermissing_count
F1
M2





위의 집계/ 요약통계량과 결측값 개수를 하나의 조회 결과로 보려면 아래처럼 Join 을 해주면 됩니다.



WITH summary_tbl AS (
    SELECT
        gender AS group_by_value
        , 'age' AS target_column
        , COUNT(*) AS row_count
        , COUNT(DISTINCT age) AS distinct_values
        , AVG(age)
        , VARIANCE(age)
        , STDDEV(age)
        , MIN(age)
        , PERCENTILE_DISC(0.25) WITHIN GROUP (ORDER BY age) AS first_quartile
        , MEDIAN(age)
        , PERCENTILE_DISC(0.75) WITHIN GROUP (ORDER BY age) AS third_quartile
        , MAX(age)
        , MODE() WITHIN GROUP (ORDER BY age)
    FROM cust
    WHERE age IS NOT NULL
    GROUP BY gender
    ORDER BY gender
), missing_tbl AS (
    SELECT
        gender AS group_by_value
        , COUNT(*) AS missing_count
    FROM cust
    WHERE age IS NULL
    GROUP BY gender
)
SELECT a.*, b.missing_count
FROM summary_tbl a LEFT JOIN missing_tbl b USING(group_by_value)
;

 




  (2) Apache MADlib으로 연속형 데이터의 그룹별 요약통계량 구하기


Apache MADlib의 madlib.summary() 함수를 사용하면 단 몇 줄의 코드만으로 위의 (1)번에서 SQL 집계 함수를 사용해서 길게 짠 코드를 대신해서 매우 깔끔하고 간단하게 구할 수 있습니다. 


아래는 (1)번의 결과를 얻기위해 성별(gender) 연령(age) 칼럼의 집계/요약데이터를 구하는 madlib.summary() 함수 예시입니다. 


Target columns 위치에는 1 개 이상의 분석을 원하는 연속형 데이터 칼럼을 추가로 넣어주기만 하면 되므로 (1) 번의 pure SQL 대비 훨씬 편리한 측면이 있습니다! 


그리고 그룹별로 구분해서 집계/요약하고 싶으면 Grouping columns 위치에 기준 칼럼 이름을 넣어주기만 하면 되므로 역시 (1)번의 pure SQL 대비 훨씬 편리합니다!



DROP TABLE IF EXISTS cust_summary;

SELECT madlib.summary('cust'     -- Source table

                      ,'cust_summary'   -- Output table

                      , 'age'                -- Target columns

                      , 'gender'            -- Grouping columns

);






madlib.summary() 함수의 결과 테이블에서 조회할 수 있는 집계/요약통계량 칼럼 리스트는 아래와 같습니다. 



SELECT column_name

FROM INFORMATION_SCHEMA.COLUMNS

    WHERE TABLE_SCHEMA = 'public'

        AND TABLE_NAME    = 'cust_summary'

    ORDER BY ORDINAL_POSITION;

Out[7]:
column_name
group_by
group_by_value
target_column
column_number
data_type
row_count
distinct_values
missing_values
blank_values
fraction_missing
fraction_blank
positive_values
negative_values
zero_values
mean
variance
confidence_interval
min
max
first_quartile
median
third_quartile
most_frequent_values
mfv_frequencies

 



[Reference]

* PostgreSQL aggregate functions: https://www.postgresql.org/docs/9.4/functions-aggregate.html

* Apache MADlib summary function: https://madlib.apache.org/docs/v1.11/group__grp__summary.html



다음번 포스팅에서는 PostgreSQL, Greenplum에서 SQL과 Apache MADlib을 이용하여 상관계수, 상관계수 행렬을 구하는 방법(https://rfriend.tistory.com/581)을 소개하겠습니다.


이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!



728x90
반응형
Posted by Rfriend
,

데이터 분석을 하다 보면 변수들 간의 척도 (scale) 가 서로 다른 경우 직접적으로 상호 비교를 할 수가 없습니다.  모델링에서는 척도(scale)가 다름으로 인해서 모수의 왜곡이 생길 수도 있습니다.

 

따라서 모델링 작업에 들어가기 전에 변수들 간의 척도가 다른 경우에는 보통 표준화(scale standization)를 진행합니다.

 

표준화 중에서도 모집단이 '정규분포 (normal distribution, Gaussian distribution)을 따르는 경우 평균이 0, 표준편차는 1 인 표준정규분포(standard normal distribution)로 표준화 하는 방법을 많이 사용합니다. 

 

이번 포스팅에서는

 

 - Numpy : z = (x - mean())/std()

 - scipy.stats : zscore()

 - sklearn.preprocessing : StandardScaler().fit_transform()

 

의 모듈, method를 이용한 표준정규분포 표준화 (mean removal and variance scaling, mean = 0, std = 1)에 대해서 소개하겠습니다.

 

 

 

 

실습에 필요한 모듈을 importing하고 예제 Dataset을 만들어보겠습니다.

 

 

In [1]: import numpy as np


In [2]: data = np.random.randint(30, size=(6, 5))


In [3]: data

Out[3]:

array([[ 3,  5, 14, 24, 24],
       [ 3,  9,  1, 20,  3],
       [10,  5, 11, 17, 28],
       [26,  9, 20, 10,  8],
       [15,  7,  1, 24,  2],
       [15, 19, 10, 13,  2]])

 

 

 

표준정규분포로 표준화하는 3가지 방법을 차례대로 소개하겠습니다.

 

 

  (1) Numpy 를 이용한 표준화 : z = (x - mean())/std()

 

칼럼마다 각각의 평균, 표준편차를 적용해서 표준화를 하려면 mean(data, axis=0), std(data, axis=0) 처럼 'axis=0' 을 설정해주면 됩니다.

 

 

# (1) Using numpy, z = (x-mean)/std

In [4]: from numpy import *


In [5]: data_standadized_np = (data - mean(data, axis=0)) / std(data, axis=0)


In [6]: data_standadized_np

Out[6]:

array([[-1.13090555, -0.84016805,  0.66169316,  1.14070365,  1.19426502],
       [-1.13090555,  0.        , -1.24986486,  0.38023455, -0.75998683],
       [-0.25131234, -0.84016805,  0.22056439, -0.19011728,  1.56650347],
       [ 1.75918641,  0.        ,  1.54395071, -1.5209382 , -0.29468877],
       [ 0.37696852, -0.42008403, -1.24986486,  1.14070365, -0.85304644],
       [ 0.37696852,  2.10042013,  0.07352146, -0.95058638, -0.85304644]])

 

# check of 'mean=0', 'standard deviation=1'

In [7]: mean(data_standadized_np, axis=0)

Out[7]:

array([ -5.55111512e-17,   0.00000000e+00,   9.25185854e-18,
         0.00000000e+00,   3.70074342e-17])


In [8]: std(data_standadized_np, axis=0)

Out[8]: array([ 1.,  1.,  1.,  1.,  1.])

 

 

  • 평균(mean): np.mean(arr)
  • 표준편차(standard deviation): np.std(arr)
  • 분산(variance): np.var(arr)


import numpy as np

arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])


print('mean:', np.mean(arr))

print('standard deviation:', np.std(arr))

print('variance:', np.var(arr))


mean: 5.0
standard deviation: 3.1622776601683795
variance: 10.0

 


 


 

  (2) scipy.stats 을 이용한 표준화 : ss.zscore()

 

 

# (2) Standardization using zscore() of scipy.stats

In [9]: import scipy.stats as ss


In [10]: data_standadized_ss = ss.zscore(data)


In [11]: data_standadized_ss

Out[11]:

array([[-1.13090555, -0.84016805,  0.66169316,  1.14070365,  1.19426502],
       [-1.13090555,  0.        , -1.24986486,  0.38023455, -0.75998683],
       [-0.25131234, -0.84016805,  0.22056439, -0.19011728,  1.56650347],
       [ 1.75918641,  0.        ,  1.54395071, -1.5209382 , -0.29468877],
       [ 0.37696852, -0.42008403, -1.24986486,  1.14070365, -0.85304644],
       [ 0.37696852,  2.10042013,  0.07352146, -0.95058638, -0.85304644]])

 

 

 

 

  (3) sklearn.preprocessing 을 이용한 표준화 : StandardScaler().fit_transform()

 

 

In [12]: from sklearn.preprocessing import StandardScaler


In [13]: data_standadized_skl = StandardScaler().fit_transform(data)

 

In [14]: data_standadized_skl

Out[14]:

array([[-1.13090555, -0.84016805,  0.66169316,  1.14070365,  1.19426502],
       [-1.13090555,  0.        , -1.24986486,  0.38023455, -0.75998683],
       [-0.25131234, -0.84016805,  0.22056439, -0.19011728,  1.56650347],
       [ 1.75918641,  0.        ,  1.54395071, -1.5209382 , -0.29468877],
       [ 0.37696852, -0.42008403, -1.24986486,  1.14070365, -0.85304644],
       [ 0.37696852,  2.10042013,  0.07352146, -0.95058638, -0.85304644]])

 

 

 

다음번 포스팅에서는 데이터셋에 Outlier 가 들어있을 때 Robust하게 표준화할 수 있는 방법으로서 sklearn.preprocessing.robust_scale, sklearn.preprocessing.RobustScaler 을 소개하겠습니다.

 

많은 도움이 되었기를 바랍니다.

 

 

 

728x90
반응형
Posted by Rfriend
,

일변량 연속형 자료에 대해 기술통계량(descriptive statistics)을 이용한 자료의 요약과 정리는 크게

 

- (1) 중심화 경향 (central tendency)

  : 산술평균, 중앙값, 최빈값, 기하평균, CAGR, 조화평균, 가중평균

 

- (2) 퍼짐 정도 (dispersion)

  : 분산, 표준편차, 변이계수, 범위, IQR, 백분위수

 

- (3) 분포형태와 대칭정도 (distribution)

  : 왜도, 첨도, 분위수-분위수 

 

의 3가지로 구분할 수 있습니다.

 

지난 포스팅에서는 중심화 경향에 대해서 알아보았는데요, 이것만 가지고는 자료의 특성을 파악했다고 보기 어려우며, 이와 더불어 자료가 중심으로 부터 얼마나 퍼져있는지, 분포는 어떤 형태인지를 같이 알아야만 합니다. 

 

아래 3-1반과 3-2반의 수학 점수를 보면 두 학급 모두 평균은 62점으로 같습니다만, 표준편차는 27점 vs. 5.7점으로 매우 다름을 알 수 있습니다.  3-1반은 최우등생과 최열등생이 모여있는 반이고, 3-2반은 비슷한 실력의 중급 학생들이 모여있는 반이라고 하겠습니다.  왜 평균만 보면 안되는지 아셨을 겁니다.

 

학급 (class)

수학 점수 (math score)

평균 (mean)

표준편차(sd)

 3학년 1반

25, 55, 60, 70, 100

62

27.06 

 3학년 2반

55, 60, 60, 65, 70

62

5.70 

 

 

 

이번 포스팅에서는 일변량 연속형 자료의 (2) 퍼짐 정도 (dispersion)에 대해 통계 이론과 활용 상의 주의점을 알아보고, R 함수를 가지고 예를 들어보겠습니다. 

 

 

[ 산술통계량(descriptive statistics)과 R function ]

 

 산술통계

 통계량 (statistics)

R function 

 중심화 경향

(central

tendency)

 산술평균 (arithmetic mean)

 mean()

 중앙값 (median)  median()
 최빈값 (mode)

 which.max(table())

 기하평균 (geometric mean)

 prod(x)^(1/n)1/mean(1/x)

where, n = length(x)

 연평균성장률 (CAGR

 : Componded Average Growth Rate)

 (FV/IV)^(1/n)-1

where, IV : initial value of an investment
          FV : final value  of an investment
          n : investment periods

 조화평균 (harmonic mean)

 1/mean(1/x)

 가중평균 (weighted average)

 weighted.mean()

 퍼짐 정도

(dispersion)

 분산 (variance)

 var()

 표준편차 (standard deviation)  sd()

 변이계수 (coefficient of variation)

 100*sd(x)/mean(x)

 범위 (range)

 diff(range())

 IQR (Inter Quartile Range)

 IQR()

 최소값 (min)

 min()

 최대값 (max)

 max()
 백분위수(percentile)

 quantile(x, probs=c(,,,,))

 분포형태와

대칭정도

(distribution)

 왜도 (skewness)

 skewness(), fBasics package

 첨도 (kurtosis)

 kurtosis(), fBasics package

 분위수-분위수(Quantile-Quantile)

 qqnorm(), qqline(), qqplot()

 

※ 중심화 경향, 퍼짐 정도, 분포형태와 대칭정도의 통계량을 함께 봐야함

※ 통계량과 함께 그래프를 함께 봐야함

 

 

R 실습에는 MASS 패키지 내 Cars93 데이터의 차종(Type), 가격(Price) 변수를 활용하겠습니다. 

 

> library(MASS)
> str(Cars93)
'data.frame':	93 obs. of  27 variables:
 $ Manufacturer      : Factor w/ 32 levels "Acura","Audi",..: 1 1 2 2 3 4 4 4 4 5 ...
 $ Model             : Factor w/ 93 levels "100","190E","240",..: 49 56 9 1 6 24 54 74 73 35 ...
 $ Type              : Factor w/ 6 levels "Compact","Large",..: 4 3 1 3 3 3 2 2 3 2 ...
 $ Min.Price         : num  12.9 29.2 25.9 30.8 23.7 14.2 19.9 22.6 26.3 33 ...
 $ Price             : num  15.9 33.9 29.1 37.7 30 15.7 20.8 23.7 26.3 34.7 ...
 $ Max.Price         : num  18.8 38.7 32.3 44.6 36.2 17.3 21.7 24.9 26.3 36.3 ...
 $ MPG.city          : int  25 18 20 19 22 22 19 16 19 16 ...
 $ MPG.highway       : int  31 25 26 26 30 31 28 25 27 25 ...
 $ AirBags           : Factor w/ 3 levels "Driver & Passenger",..: 3 1 2 1 2 2 2 2 2 2 ...
 $ DriveTrain        : Factor w/ 3 levels "4WD","Front",..: 2 2 2 2 3 2 2 3 2 2 ...
 $ Cylinders         : Factor w/ 6 levels "3","4","5","6",..: 2 4 4 4 2 2 4 4 4 5 ...
 $ EngineSize        : num  1.8 3.2 2.8 2.8 3.5 2.2 3.8 5.7 3.8 4.9 ...
 $ Horsepower        : int  140 200 172 172 208 110 170 180 170 200 ...
 $ RPM               : int  6300 5500 5500 5500 5700 5200 4800 4000 4800 4100 ...
 $ Rev.per.mile      : int  2890 2335 2280 2535 2545 2565 1570 1320 1690 1510 ...
 $ Man.trans.avail   : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 1 1 1 1 1 ...
 $ Fuel.tank.capacity: num  13.2 18 16.9 21.1 21.1 16.4 18 23 18.8 18 ...
 $ Passengers        : int  5 5 5 6 4 6 6 6 5 6 ...
 $ Length            : int  177 195 180 193 186 189 200 216 198 206 ...
 $ Wheelbase         : int  102 115 102 106 109 105 111 116 108 114 ...
 $ Width             : int  68 71 67 70 69 69 74 78 73 73 ...
 $ Turn.circle       : int  37 38 37 37 39 41 42 45 41 43 ...
 $ Rear.seat.room    : num  26.5 30 28 31 27 28 30.5 30.5 26.5 35 ...
 $ Luggage.room      : int  11 15 14 17 13 16 17 21 14 18 ...
 $ Weight            : int  2705 3560 3375 3405 3640 2880 3470 4105 3495 3620 ...
 $ Origin            : Factor w/ 2 levels "USA","non-USA": 2 2 2 2 2 1 1 1 1 1 ...
 $ Make              : Factor w/ 93 levels "Acura Integra",..: 1 2 4 3 5 6 7 9 8 10 . 

 

 

 

아래의 차종별로 가격 (Price by Type)을 Histogram으로 살펴보면 Midsize 가 좌우로 가장 많이 퍼져있으며, Compact, Large, Sporty 가 그 다음으로 많이 퍼져있고, 마지막으로 Small, Van 이 가장 작게 퍼져있음을 알 수 있습니다.  이걸 아래의 통계량들을 가지고 퍼짐 정도를 측정해 보겠습니다.

 

> # Histogram, Price by Type
> library(MASS) # Cars93 dataset
> library(ggplot2)
> ggplot(Cars93, aes(x=Price)) + 
+   geom_histogram(binwidth=5, fill = "blue", colour = "black") + 
+   ggtitle("Histogram, Price by Type") + 
+   facet_grid(Type ~ .)

 

 

 

 

이제부터 R 함수를 이용해서 퍼짐 정도 (dispersion) 를 파악할 수 있는 통계량을 하나씩 살펴보겠습니다.

 

(1) 분산 (variance) : var()

 

 

분산(variance)은 표준편차(standard deviation)와 함께 가장 일반적으로 사용되는 퍼짐 정도를 나타내는 통계량입니다.  각 관찰값에서 평균을 빼면 평균으로 부터의 거리, 편차(deviation)가 나오는데요, 이걸 모두 합하면 '0'이 됩니다.  따라서 '0'이 되지 않고 퍼진 정도를 알기 위해서 제곱(square)을 하여 합(sum)한 것이고, 관찰값 개수 N으로 나누어서 편차제곱의 평균값으로 퍼진 정도를 측정한 것이 분산(variance)입니다.

 

표본에서 분산을 계산할 때는 편차 제곱합을 관찰값 개수 n에서 1을 뺀 n-1을 사용하여 나누어줍니다.

 

 
> # variance : var()
> 
> var(Cars93$Price)
[1] 93.30458
> 
> with(Cars93, tapply(Price, Type, var))
   Compact      Large    Midsize      Small     Sporty        Van 
 44.714500  40.164000 150.426320   3.815333  63.596099   3.527500

 

 

차종별 가격(Price by Type)의 분산을 구하기 위해 tapply(var, factor, function) 함수를 사용하였습니다.

 

 

 

(2) 표준편차 (standard deviation) : sd()

 

 

표준편차(standard deviation)는 분산(variance)에다가 제곱근(squared root)을 취한 값입니다.   분산(variance)의 경우 편차를 제곱하다 보니 원자료의 scale과는 달라져버리게 되어 해석하는데 좀 곤란한 상황이 벌어집니다.  이 문제를 해결할 수 있는 것이 바로 표준편차입니다.  편차 제곱한 분산에다가 제곱근을 취했기 때문에 원자료와 scale이 동일해지기 때문입니다. 표준편차도 분산과 동일하게 숫자가 커질 수록 중심으로부터 멀리 퍼져있다고 해석하면 되며, 원자료와 scale이 동일하기 때문에 평균에서 (정규분포의 경우) 좌우로 표준편차만큼 퍼져있다고 생각하면 이해하기가 쉽겠습니다.

 

 

 
> # standard deviation : sd()
> 
> sd(Cars93$Price)
[1] 9.65943
> 
> with(Cars93, tapply(Price, Type, sd))
  Compact     Large   Midsize     Small    Sporty       Van 
 6.686890  6.337507 12.264841  1.953288  7.974716  1.878164
 

 

위의 차종별 가격의 표준편차를 보면 위의 histogram과 동일한 결과가 나왔음을 알 수 있습니다.  Midsize가 표준편차가 12.26으로 가장 크고, Van이 1.87로 표준편차가 가장 작게 나왔습니다.

 

 

 

(3) 변이계수 (coefficeint of variation) : 100*sd()/mean()

 

위에서 표준편차(standard deviation)가 scale이 원자료와 같기 때문에 분산(variance)보다는 사용하기에 유용하다고 말했습니다.  하지만 표준편차도 약점이 있는데요, 절대 크기가 현저하게 달라서 평균이 서로 매우 다른 두 집단 간 비교, 측정 단위가 다른 두 변수 간 비교에는 부적합합니다.  이럴 때 퍼짐 정도를 비교 가능하도록 표준화해준 통계량이 변이계수(coeffieicent of variation)이 되겠습니다.  변이계수는 표준편차를 평균으로 나눈 다음에 100을 곱해서 계산합니다.

 

차종별 가격의 변이계수를 구하면 아래와 같은데요, 변이계수가 표준편차와 뭐가 다른가 잘 감이 안잡힐 수도 있겠습니다.

 

 

> # coefficient of variation : sd()/mean()
> 
> with(Cars93, 100*sd(Price)/mean(Price))
[1] 49.51096
> 
> attach(Cars93)
> with(Cars93[Type == c("Compact"),], 100*sd(Price)/mean(Price))
[1] 36.71594
> with(Cars93[Type == c("Large"),], 100*sd(Price)/mean(Price))
[1] 26.08028
> with(Cars93[Type == c("Midsize"),], 100*sd(Price)/mean(Price))
[1] 45.06121
> with(Cars93[Type == c("Small"),], 100*sd(Price)/mean(Price))
[1] 19.21267
> with(Cars93[Type == c("Sporty"),], 100*sd(Price)/mean(Price))
[1] 41.12193
> with(Cars93[Type == c("Van"),], 100*sd(Price)/mean(Price))
[1] 9.833319
> detach(Cars93)
 

 

 

변이계수의 이해를 돕기 위해서 하나의 예를 추가로 들어보겠습니다.

 

A회사와 B회사가 있는데요, 한달 주식가격의 평균과 표준편차가 아래와 같은 때, 표준편차로만 보면 B회사(sd 2,000원)가 A회사(sd 1,000원)의 2배로서 Risk가 더 높다고 생각할 수 있습니다만, 여기에는 함정이 있으며, 이렇게 계산하면 틀립니다.  B회사의 주당 평균 주가(mean 50,000원)는 A회사의 주당 평균주가(mean 10,000원)의 5배에 해당할만큼 큰 차이를 보이고 있습니다. 

 

이럴 경우 급이 다르기 때문에 평균으로 표준편차를 나누어준 비율인 변이계수를 사용해서 동급으로 만들어주고 퍼짐 정도를 비교해야만 합니다. A회사의 변이계수는 10%, B회사의 변이계수는 4%로서 A회사가 B회사보다 Risk가 2.5배 더 높다고 평가할 수 있으며, 앞서의 표준편차와는 정반대의 결과가 나왔음에 유의하시기 바랍니다.

  

 

 

> # example : stock price's mean, sd of company A and company B
> 
> company_A_mean <- c(10000)
> company_A_sd <- c(1000)
> 
> company_B_mean <- c(50000)
> company_B_sd <- c(2000)
> 
> 
> coe_var_A <- 100*company_A_sd/company_A_mean
> coe_var_A
[1] 10
> 
> coe_var_B <- 100*company_B_sd/company_B_mean
> coe_var_B
[1] 4

 

 

 

 

(4) 최소값 (min) : min()

(5) 최대값 (max) : max() 

(6) 범위 (range) : diff(range())

(7) 백분위수 (percentile) : quantile(x, probs=c(,,,,))

(8) IQR (Inter Quartile Range) : IQR()

 

 

 

범위(range)는 최대값에서 최소값을 뺀 값으로, 직관적으로 가장 이해하기 쉬운 퍼짐 정도 통계량입니다. 다만, 특이값(outlier)에 민감하므로 특이값을 제거 후에 사용하거나, 아니면 특이값에 견고한 IQR(Inter Quartile Range) 를 대신 사용할 수 있습니다.

 

p 백분위수(pth percentile)는 자료를 크기 순서대로 정렬해놓았을 때 p%가 자기값 이하(자기값 포함)로 적어도 p%의 관측값이 있고, 자기값 이상으로 적오도 (100-p)%의 관측값이 있는 수를 의미합니다.  Q1, Q2(median), Q3 등은 우리가 자주 사용하는 대표적인 백분위수(percentile)로서, 사분위수(quartile)이라고도 하며 이때 Q1은 25% percentile, Q2는 50% percentile, Q3는 75% percentile이 되겠지요.

 

R로는 함수 한줄로 누워서 떡먹기보다 더 쉬운데요, 이것을 SQL, Hive로 구현하려면 머리가 좀 아프고 코딩을 좀 해야만 합니다. ^^; 

 

자, 그럼 R로 차종별 가격의 Min, Max, 범위, 25% percentile(Q1), 75% percentile(Q3), IQR을 차례대로 구해보겠습니다.

 

 

> ##---------- > # min, max, range, IQR, percentile > attach(Cars93) > > # min : min() > min(Price) [1] 7.4 > tapply(Price, Type, min) Compact Large Midsize Small Sporty Van 11.1 18.4 13.9 7.4 10.0 16.3 > > # max : max() > max(Price) [1] 61.9 > tapply(Price, Type, max) Compact Large Midsize Small Sporty Van 31.9 36.1 61.9 15.9 38.0 22.7 > > # range : diff(range()) > diff(range(Price)) [1] 54.5 > > diff(range(Cars93[Type==c("Compact"),]$Price)) [1] 20.8 > diff(range(Cars93[Type==c("Large"),]$Price)) [1] 17.7 > diff(range(Cars93[Type==c("Midsize"),]$Price)) [1] 48 > diff(range(Cars93[Type==c("Small"),]$Price)) [1] 8.5 > diff(range(Cars93[Type==c("Sporty"),]$Price)) [1] 28 > diff(range(Cars93[Type==c("Van"),]$Price)) [1] 6.4 > > # Percentile : quantile(var, probs=c(,,)) > quantile(Price, c(0.25, 0.75)) 25% 75% 12.2 23.3 > > quantile(Cars93[Type==c("Compact"),]$Price, c(0.25, 0.75)) 25% 75% 13.375 20.675 > quantile(Cars93[Type==c("Large"),]$Price, c(0.25, 0.75)) 25% 75% 20.00 26.95 > quantile(Cars93[Type==c("Midsize"),]$Price, c(0.25, 0.75)) 25% 75% 16.775 34.200 > quantile(Cars93[Type==c("Small"),]$Price, c(0.25, 0.75)) 25% 75% 8.6 11.3 > quantile(Cars93[Type==c("Sporty"),]$Price, c(0.25, 0.75)) 25% 75% 14.175 22.425 > quantile(Cars93[Type==c("Van"),]$Price, c(0.25, 0.75)) 25% 75% 19.0 19.7 > > > # IQR : IQR() > IQR(Price) [1] 11.1 > > IQR(Cars93[Type==c("Compact"),]$Price) [1] 7.3 > IQR(Cars93[Type==c("Large"),]$Price) [1] 6.95 > IQR(Cars93[Type==c("Midsize"),]$Price) [1] 17.425 > IQR(Cars93[Type==c("Small"),]$Price) [1] 2.7 > IQR(Cars93[Type==c("Sporty"),]$Price) [1] 8.25 > IQR(Cars93[Type==c("Van"),]$Price) [1] 0.7 > detach(Cars93)

 

 

 

위의 퍼짐 정도(range, Q1, median, Q3, lower/upper whisker line, outlier) & 중심 경향(mean) 관련 통계량들을 박스 그림(box-and-whisker plot)으로 그리면 아래와 같습니다.

 

> # box plot with mean
> ggplot(Cars93, aes(x = Type, y = Price)) +
+   geom_boxplot(width=0.8, outlier.size=3, outlier.shape=16, outlier.colour="red") +
+   stat_summary(fun.y="mean", geom="point", shape=21, size=3, fill="blue") +
+   ggtitle("Box Plot by Car Type, adding mean") 

 

 

 

 

저 위에도 적어놨지만요, 통계량은 중심화 경향, 퍼짐 정도, 분포형태 및 대칭 정도 통계량을 같이 봐야 하고, 그래프도 같이 봐서 종합적으로 해석하는 것이 정말 중요합니다.

 

중심화 경향과 퍼짐 정도가 다른 두 데이터셋을 표준화하는 방법은 아래의 포스팅을 참고하시기 바랍니다.

 

☞  R 데이터 변환 (1) 표준화 : z 표준화 변환, [0-1] 변환

 

많은 도움 되었기를 바랍니다. 

 

이번 포스팅이 도움이 되었다면 아래의 '공감 ~♡'를 꾸욱 눌러주세요. ^^

 

728x90
반응형
Posted by Rfriend
,