작성자: admin 작성일시: 2016-09-29 21:18:44 조회수: 409 다운로드: 50
카테고리: R 태그목록:

R 데이터프레임 그룹 연산과 피봇 테이블

그룹 연산

그룹바이(group-by) 연산 혹은 그룹 연산이란 데이터를 몇 개의 키를 기준으로 그룹을 만든 뒤에 각 그룹의 대표값을 구하는 작업을 말한다. split-apply-combine 연산이라고도 한다.

  • split 단계

    • 특정 Key 값에 따라 데이터 그룹을 만든다.
  • apply 단계

    • 각각의 그룹에 대해 원하는 연산을 하여 대표값을 생성한다.
    • n(), mean(), median(), min(), max(), sum(), prod(), std(), var(), quantile(), first(), last()
  • combine 단계

    • 그룹의 Key 값에 대해 원하는 연산의 결과를 Value로 지정한 데이터를 생성한다.

데이터프레임에 대해 그룹 연산을 하려면 dplyr 패키지를 사용한다.

In:
library("dplyr")

예를 들어 아래와 같은 데이터가 있을 때 key1의 값에 따라 데이터를 분류하고 각각의 데이터 그룹에 대해 data1의 평균을 구하려면 어떻게 해야 할까?

In:
set.seed(0)
df <- data.frame(key1=c('a', 'a', 'b', 'b', 'a'),
                 key2=c('one', 'two', 'one', 'two', 'one'),
                 data1=rnorm(5), data2=rnorm(5))
df
key1key2data1data2
a one 1.2629543 -1.539950042
a two -0.3262334 -0.928567035
b one 1.3297993 -0.294720447
b two 1.2724293 -0.005767173
a one 0.4146414 2.404653389

dplyr 패키지의 group_by 명령과 summarise 명령을 조합하여 다음과 같이 구한다.

  • group_by(데이터프레임, 키열1, 키열2, ...)
  • summarise(그룹바이_데이터, 계산열이름=계산함수(데이터열))
In:
summarise(group_by(df, key1), mean=mean(data1))
key1mean
a 0.4504541
b 1.3011143

위의 명령은 df 데이터프레임을 일단 key1의 값에 따라 분류한 뒤 data1 열을 평균(mean)해서 mean이라는 이름의 열로 만든 것이다.

만약 key1, key2 두 열을 모두 키로 하려면 다음과 같아진다.

In:
summarise(group_by(df, key1, key2), mean=mean(data1))
key1key2mean
a one 0.8387979
a two -0.3262334
b one 1.3297993
b two 1.2724293

피봇 테이블

이 결과에 tidyr 패키지의 spread 명령을 사용하면 피봇 데이블(pivot table)형태로 바꿀 수 있다.

In:
library("tidyr")
In:
spread(summarise(group_by(df, key1, key2), mean=mean(data1)), key2, mean)
key1onetwo
a 0.8387979 -0.3262334
b 1.3297993 1.2724293

위에서는 key2를 가로 방향으로 눕혔다.

그룹 연산의 사용 예

reshape2 패키지에 있는 tips 라는 샘플 데이터를 이용하여 그룹 연산의 예를 알아보자.

In:
library("reshape2")
In:
head(tips, 10)
total_billtipsexsmokerdaytimesize
16.99 1.01 FemaleNo Sun Dinner2
10.34 1.66 Male No Sun Dinner3
21.01 3.50 Male No Sun Dinner3
23.68 3.31 Male No Sun Dinner2
24.59 3.61 FemaleNo Sun Dinner4
25.29 4.71 Male No Sun Dinner4
8.77 2.00 Male No Sun Dinner2
26.88 3.12 Male No Sun Dinner4
15.04 1.96 Male No Sun Dinner2
14.78 3.23 Male No Sun Dinner2
In:
tips['tip_pct'] <- tips['tip'] / tips['total_bill']
In:
head(tips, 10)
total_billtipsexsmokerdaytimesizetip_pct
16.99 1.01 Female No Sun Dinner 2 0.05944673
10.34 1.66 Male No Sun Dinner 3 0.16054159
21.01 3.50 Male No Sun Dinner 3 0.16658734
23.68 3.31 Male No Sun Dinner 2 0.13978041
24.59 3.61 Female No Sun Dinner 4 0.14680765
25.29 4.71 Male No Sun Dinner 4 0.18623962
8.77 2.00 Male No Sun Dinner 2 0.22805017
26.88 3.12 Male No Sun Dinner 4 0.11607143
15.04 1.96 Male No Sun Dinner 2 0.13031915
14.78 3.23 Male No Sun Dinner 2 0.21853857
In:
summary(tips)
   total_bill         tip             sex      smoker      day         time    
 Min.   : 3.07   Min.   : 1.000   Female: 87   No :151   Fri :19   Dinner:176  
 1st Qu.:13.35   1st Qu.: 2.000   Male  :157   Yes: 93   Sat :87   Lunch : 68  
 Median :17.80   Median : 2.900                          Sun :76               
 Mean   :19.79   Mean   : 2.998                          Thur:62               
 3rd Qu.:24.13   3rd Qu.: 3.562                                                
 Max.   :50.81   Max.   :10.000                                                
      size         tip_pct       
 Min.   :1.00   Min.   :0.03564  
 1st Qu.:2.00   1st Qu.:0.12913  
 Median :2.00   Median :0.15477  
 Mean   :2.57   Mean   :0.16080  
 3rd Qu.:3.00   3rd Qu.:0.19148  
 Max.   :6.00   Max.   :0.71034  
In:
summarise(group_by(tips, sex, smoker), mean=mean(tip_pct), var=var(tip_pct))
sexsmokermeanvar
Female No 0.1569210 0.001326503
Female Yes 0.1821504 0.005125774
Male No 0.1606687 0.001751318
Male Yes 0.1527712 0.008206175
In:
peak_to_peak <- function(x) {
    return(max(x) - min(x))
}

s <- summarise(group_by(tips, sex, smoker), peak_to_peak=peak_to_peak(tip))
s
sexsmokerpeak_to_peak
FemaleNo 4.20
FemaleYes 5.50
Male No 7.75
Male Yes 9.00
In:
spread(s, smoker, peak_to_peak)
sexNoYes
Female4.20 5.5
Male 7.75 9.0

질문/덧글

아직 질문이나 덧글이 없습니다. 첫번째 글을 남겨주세요!