지난번 포스팅에서는 row나 column 기준으로 GroupBy의 Group을 지정할 수 있는 4가지 방법으로 Dicts, Series, Functions, Index Levels 를 소개하였습니다. 


이번 포스팅에서는 Python pandas에서 연속형 변수의 기술통계량 집계를 할 수 있는 GroupBy 집계 메소드와 함수 (GroupBy aggregation methods and functions)에 대해서 소개하겠습니다. 


(1) GroupBy 메소드를 이용한 집계 (GroupBy aggregation using methods): (ex) grouped.sum()

(2) 함수를 이용한 GroupBy 집계 (GroupBy aggregation using functions): grouped.agg(function)



[ Python pandas Group By 집계 메소드와 함수 ]



pandas에서 GroupBy 집계를 할 때 (1) pandas에 내장되어 있는 기술 통계량 메소드를 사용하는 방법과, (2) (사용자 정의) 함수를 grouped.agg(function) 형태로 사용하는 방법이 있습니다. GroupBy 메소드는 성능이 최적화되어 있어 성능면에서 함수를 사용하는 것보다 빠르므로, 메소드가 지원하는 집단별 기술통계량 분석 시에는 메소드를 이용하는게 좋겠습니다. 


NA 값은 모두 무시되고 non-NA 값들에 대해서만 GroupBy method가 적용됩니다. 


기술 통계량들이 어려운게 하나도 없으므로 이번 포스팅은 좀 쉬어가는 코너로 가볍게 소개합니다. 설명에 사용한 간단한 예제 데이터프레임과 'group'변수를 대상으로 GroupBy object를 만들어보겠습니다. 



# Importing common libraries

import numpy as np

import pandas as pd


# sample DataFrame

df = pd.DataFrame({'group': ['a', 'a', 'a', 'b', 'b', 'b'], 

                  'value_1': np.arange(6), 

                 'value_2': np.random.randn(6)})

df

groupvalue_1value_2
0a0-1.739302
1a10.851955
2a20.874874
3b3-0.461543
4b40.880763
5b5-0.346675




# Making GroupBy object

grouped = df.groupby('group')

grouped

<pandas.core.groupby.DataFrameGroupBy object at 0x11136f550>




  (1) GroupBy 메소드를 이용한 집계 (GroupBy aggregation using methods)


(1-1) count(), sum()

count(): 그룹 내 non-NA 개수 

sum(): 그룹 내 non-NA 합 

 

grouped.count()

value_1value_2
group
a33
b33


grouped.sum() # DataFrame

value_1value_2
group
a3-0.012473
b120.072545


*cf. grouped.size() 도 grouped.count()와 동일한 결과를 반환함



위의 예에서 보면 'value_1', 'value_2' 변수가 숫자형이므로 pandas가 알아서 잘 찾아서 count()와 sum()을 해주었으며, 반환된 결과는 데이터프레임입니다. 



만약 특정 변수에 대해서만 그룹별 요약/집계를 하고 싶다면 해당 변수를 indexing해주면 되며, 한개 변수에 대해서만 GroupBy 집계를 하면 반환되는 결과는 Series가 됩니다. 한개 변수에 대해 GroupBy 집계해서 나온 Series를 데이터프레임으로 만들고 싶으면 pd.DataFrame() 를 사용해서 집계 결과를 데이터프레임으로 변환해주면 됩니다. 



grouped.sum()['value_2'] # Series

group

a   -0.012473
b    0.072545 

Name: value_2, dtype: float64



pd.DataFrame(grouped.sum()['value_2']) # DataFrame 

value_2
group
a-0.012473
b0.072545





(1-2) 최소값, 최대값: min(), max()

min(): 그룹 내 non-NA 값 중 최소값 

max(): 그룹 내 non-NA 값 중 최대값 

 

grouped.min()

value_1value_2
group
a0-1.739302
b3-0.461543



grouped.max()

value_1value_2
group
a20.874874
b50.880763





(1-3) 중심 경향: mean(), median()

mean(): 그룹 내 non-NA 값들의 평균값 

median(): 그룹 내 non-NA 값들의 중앙값 

 

grouped.mean()

value_1value_2
group
a1-0.004158
b40.024182



grouped.median()

value_1value_2
group
a10.851955
b4-0.346675



※ 그룹별로 집계된 결과값의 변수에 접두사(Prefix)를 붙이려면 add_prefix() 를 사용합니다. 

예) df.groupby('key_col').mean().add_prefix('mean_')




(1-4) 퍼짐 정도: std(), var(), quantile()


표준편차, 분산 계산에 n-1 자유도를 사용했으므로 샘플표준편차, 샘플분산으로 봐야겠네요. 

quantile() 의 괄호 안에 0~1 사이의 값을 넣어주면 분위수를 계산해주며, 최소값과 최대값을 등분하여 그 사이를 interpolation 하여 분위수를 계산하는 방식입니다. 


std(): 그룹 내 표준편차

var(): 그룹 내 분산

quantile(): 그룹 내 분위수 


grouped.std() 

value_1value_2
group
a1.01.502723
b1.00.744042



grouped.var()

value_1value_2
group
a12.258176
b10.553598

 

 # interpolation

grouped.quantile(0.1) 

0.1value_1value_2
group
a0.2-1.221051
b3.2-0.438569




(1-5) first(), last()

first(): 그룹 내 non-NA 값 중 첫번째 값 

last(): 그룹 내 non-NA 값 중 마지막 값 

 

grouped.first()

value_1value_2
group
a0-1.739302
b3-0.461543


 

grouped.last()

value_1value_2
group
a20.874874
b5-0.346675





(1-6) describe()

describe(): 그룹 별 기술통계량 

- 옆으로 길게

 describe().T: 그룹 별 기술통계량 

- 세로로 길게

 

grouped.describe()['value_1']

countmeanstdmin25%50%75%max
group
a3.01.01.00.00.51.01.52.0
b3.04.01.03.03.54.04.55.0


 

grouped.describe()['value_1'].T

groupab
count3.03.0
mean1.04.0
std1.01.0
min0.03.0
25%0.53.5
50%1.04.0
75%1.54.5
max2.05.0





  (2) 함수를 이용한 GroupBy 집계: grouped.agg(function)


필요로 하는 집계함수가 pandas GroupBy methods에 없는 경우 사용자 정의 함수를 정의해서 집계에 사용할 수 있습니다. IQR(Inter-Quartile Range, Q3 - Q1) 를 사용자 정의 함수로 정의하고, 이를 grouped.aggregate() 혹은 grouped.agg() 의 괄호 안에 넣어서 그룹 별로 IQR를 계산해보겠습니다. 



def iqr_func(x):

    q3, q1 = np.percentile(x, [75, 25])

    iqr = q3 - q1

    return iqr




grouped.aggregate(function) 

grouped.agg(function) 

 

grouped.aggregate(iqr_func)

value_1value_2
group
a11.307088
b10.671153


 

grouped.agg(iqr_func)

value_1value_2
group
a11.307088
b10.671153



위에서 사용자 정의함수로 정의해서 그룹별로 집계한 결과가 맞게 나온건지 quantile() 메소드로 그룹별 Q3 와 Q1을 계산해서 확인해보니, 위의 grouped.agg(iqr_func)가 잘 계산한거 맞네요. 



grouped.quantile([0.75, 0.25])

value_1value_2
group
a0.751.50.863414
0.250.5-0.443674
b0.754.50.267044
0.253.5-0.404109

 


다음번 포스팅에서는 grouped.agg() 의 좀더 다양한 사용법을 소개하겠습니다. 


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

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
,

통계는 크게 표본의 (a) 도수 분포와 중심화 경향, 그리고 퍼짐 정도를 측정하여 집단의 특성에 대해서 기술하는 기술통계(descriptive statistics)와, (b) 기술통계량을 가지고 모집단의 parameter 값 (모평균, 모분산 등)을 추정하고 가설을 검증하는 추정통계(inferential statistics)로 구분할 수 있습니다.

 

이번 포스팅에서는 R에서 벡터를 대상으로 사용할 수 있는 기술 통계 관련 함수에 대해서 알아보겠습니다.

 

R 기술통계 함수

 

-- 분포 및 중심화 경향 --

 

(1) 평균 : mean(x)

 

> x <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
> mean(x)
[1] 5.5 

 

 

(2) 중앙값 : median(x)

 

> x <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
> median(x)
[1] 5.5
> y <- c(1, 2, 3, 4, 5, 6, 7, 8, 9)
> median(y)
[1] 5

 

벡터 x가 홀수개이면 정 가운데 값을 중앙값을 가져오지만, 위의 case와 같이 x가 짝수개 이면 정가운데의 양쪽 두개의 값을 가져다가 평균을 내서 중앙값을 계산합니다.

 

 

(3) 최소값 : min(x)

 

> min(x)
[1] 1
> min(y)
[1] 1 

 

 

which.min(my_vec) 은 최소값이 있는 위치의 index 를 반환합니다. NA가 포함되어 있는 vector의 경우 min(my_vec) 이 NA를 반환한데 반해서 (NA에 대한 전처리 필요), my_vec[wich.min(my_vec)] 처럼 최소값을 ndexing을 해오면 '-12'를 반환했습니다.

 

 

> my_vec <- c(-5, 3, 10, 3, -12, NA)
> my_vec
[1]  -5   3  10   3 -12  NA
> 
> min(my_vec)
[1] NA
> 
> which.min(my_vec) # index of min value in 'my_vec' vector
[1] 5
> 
> my_vec[which.min(my_vec)]
[1] -12

 

 

 

 

(4) 최대값 : max(x)

 

> max(x)
[1] 10
> max(y) 

 

> my_vec <- c(-5, 3, 10, 3, -12, NA)
> my_vec
[1]  -5   3  10   3 -12  NA
> 
> max(my_vec)
[1] NA
> 
> which.max(my_vec) # index of max value in 'my_vec' vector
[1] 3
> 
> my_vec[which.max(my_vec)]
[1] 10 

 

 

 

(5) 범위 : range(x)

 

> range(x)
[1]  1 10
> range(y)
[1] 1 9 

 

 

(6) IQR(Inter-Quartile Range) : IQR(x)

 

> IQR(x)
[1] 4.5
> IQR(y)
[1] 4 

 

 

(7) 중심화 경향 및 분포 요약 : summary(x)

 

> summary(x)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   1.00    3.25    5.50    5.50    7.75   10.00 

 

숫자형 벡터의 경우 summary() 함수가 위의 1번에서 6번까지 함수를 한번에 처리할 수 있는 유용한 함수가 되겠습니다.

 

 

-- 퍼짐 정도 --

 

(8) 분산 : var(x)

 

> var(x)
[1] 9.166667
> var(y)
[1] 7.5 

 

 

(9) 표준편차 : sd(x)

 

> sd(x); sd(y)
[1] 3.02765
[1] 2.738613 

 

참고) 세미콜론 ';' 을 사용하면 같은 줄에 R 명령어를 연속으로 해서 쓸 수 있습니다

 

 

-- 확률분포의 비대칭 정도 --

 

(10) 왜도

 

> install.packages("fBasics") # 왜도, 첨도 분석 가능한 package 설치 > library(fBasics) # package 호출 > hist(mtcars$mpg)

 

 

 

 

 

 

> skewness(mtcars$mpg) [1] 0.610655 attr(,"method") [1] "moment"

 

 

R에 왜도와 첨도를 위한 함수가 내장되어 있지 않기 때문에 별도 패키지(fBasics)를 설치해야 합니다.

자동차 정보가 들어있는 mtcars 데이터 프레임의 연비에 대해서 히스토그램을 그려보니 평균보다 왼쪽으로 치우쳐 있고 오른쪽으로 꼬리가 긴 분포를 띠고 있네요. 그러면 왜도(skewness) 가 '0'보다 크게 나타납니다. (공식이 평균에서 관측치를 뺀 값을 3제곱 하기 때문이예요) 위 예에서는 왜도가 0.61로 '0'보다 크게 나왔지요. 정규분포의 평균과 일치하면 왜도는 '0'이 되고, 반대로 평균보다 오른쪽으로 값이 치우쳐 있고 왼쪽으로 꼬리가 길면 왜도는 '0'보다 작은 값이 나옵니다.

 

 

(11) 첨도

 

> kurtosis(mtcars$mpg)
[1] -0.372766
attr(,"method")
[1] "excess"

 

관측값이 정규분포보다 뾰쪽한가 아닌가를 가늠하는 쳑도가 첨도입니다. '3'보다 크면 정규분포보다 더 뾰족한 모양이고, '3'보다 작으면 정규분포보다 덜 뾰족한 모양이라고 해석하면 되겠습니다. (패키지에 따라서는 '3'을 빼서 '0'으로 표준화해서 값을 제시하기도 합니다)

 

 

-- 기타 함수 --

 

(12) 합 : sum(x)

 

> sum(x)
[1] 55
> sum(y)
[1] 45

 

 

(13) n차 차분 : diff(x, lag=n)

 

> diff(x, lag=1)
[1] 1 1 1 1 1 1 1 1 1
> diff(x, lag=2)
[1] 2 2 2 2 2 2 2 2
> diff(x, lag=3)
[1] 3 3 3 3 3 3 3 

 

관측값에서 직전 관측값을 뺀 차분을 구하는 함수입니다. 시계열분석할 때 정상화하기 위해서 차분을 이용하는데요, 시차(lag)를 분석 목적에 따라 또 데이터 특성에 따라서 입력해주면 됩니다. 디폴트는 lag=1 이 되겠습니다.

 

 

(14) 길이, 관측값 개수 : length()

 

> # 벡터에 length() 사용 시
> length(x)
[1] 10
> length(y)
[1] 9 
> 

> # 데이터 프레임에 length()사용 시

> length(mtcars)
[1] 11
> 

> # 데이터 프레임의 특정 변수에 length($) 사용 시

> length(mtcars$mpg)
[1] 32

 

벡터에서 length()는 관측값 개수를 계산해서 보여줍니다.

데이터 프레임에서는 column 개수를 나타내주고요, 데이터 프레임의 특정 변수를 지정하면 그 특정 변수의 관측값의 개수를 세서 보여줍니다.

 

 

(15) 순위 : rank()

 

> rank(x) [1] 1 2 3 4 5 6 7 8 9 10 >
>
rank(-x) [1] 10 9 8 7 6 5 4 3 2 1 >

> mtcars$mpg
 [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5
[23] 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7 15.0 21.4

>

> rank(mtcars$mpg, 
+      na.last = TRUE, 
+      ties.method = c("max"))
 [1] 20 20 25 22 15 14  4 26 25 17 13 11 12  8  2  2  5 31 30 32 23  9  8  3 17 28 27 30 10 18  6 22

 

> ##----------------------- > ## rank() {base package} > ##----------------------- > > # if there are no ties(i.e., equal values), no problem at all > x <- c(1, 5, 9, 7) > rank(x) [1] 1 2 4 3 > > > # if there are ties, ties can be handled in several ways > y <- c(1, 1, 1, 5, 9, 7) > > # returns average, default setting > rank(y) [1] 2 2 2 4 6 5 > rank(y, ties.method = c("average")) [1] 2 2 2 4 6 5 > > # first occurrence wins > rank(y, ties.method = c("first")) [1] 1 2 3 4 6 5 > > # ties broken at random > rank(y, ties.method = c("random")) [1] 3 2 1 4 6 5 > > rank(y, ties.method = c("random")) # ...random one more time [1] 1 3 2 4 6 5 > > rank(y, ties.method = c("random")) # ...random...again [1] 1 2 3 4 6 5 > > # rank by max value as used classically > rank(y, ties.method = c("max")) [1] 3 3 3 4 6 5 > > # rank by min value as in Sports > rank(y, ties.method = c("min")) [1] 1 1 1 4 6 5

 

rank는 순위대로 정렬해주는게 아니라 순위의 색인을 나타내줍니다.

디폴트는 작은 값부터 1을 부여해주고, 큰 것 부터 1을 부여하려면 '-'를 붙여주면 됩니다.

 

동일한 값(Ties, i.e, equal values)이 있을 경우 rank() 함수는 "average" (default), "first", "random", "max", "min" 등의 옵션을 제공합니다.

 

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

 

728x90
반응형
Posted by Rfriend
,