dplyr 패키지 공부

출처 : http://www.di.fc.ul.pt/~jpn/r/



In [2]:
library(dplyr)
library(MASS)


Attaching package: 'dplyr'

The following objects are masked from 'package:stats':

    filter, lag

The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union


Attaching package: 'MASS'

The following object is masked from 'package:dplyr':

    select


In [3]:
head(Boston)
str(Boston)


crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.0063218 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98 24.0
0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14 21.6
0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03 34.7
0.03237 0 2.18 0 0.458 6.998 45.8 6.0622 3 222 18.7 394.63 2.94 33.4
0.06905 0 2.18 0 0.458 7.147 54.2 6.0622 3 222 18.7 396.90 5.33 36.2
0.02985 0 2.18 0 0.458 6.430 58.7 6.0622 3 222 18.7 394.12 5.21 28.7
'data.frame':	506 obs. of  14 variables:
 $ crim   : num  0.00632 0.02731 0.02729 0.03237 0.06905 ...
 $ zn     : num  18 0 0 0 0 0 12.5 12.5 12.5 12.5 ...
 $ indus  : num  2.31 7.07 7.07 2.18 2.18 2.18 7.87 7.87 7.87 7.87 ...
 $ chas   : int  0 0 0 0 0 0 0 0 0 0 ...
 $ nox    : num  0.538 0.469 0.469 0.458 0.458 0.458 0.524 0.524 0.524 0.524 ...
 $ rm     : num  6.58 6.42 7.18 7 7.15 ...
 $ age    : num  65.2 78.9 61.1 45.8 54.2 58.7 66.6 96.1 100 85.9 ...
 $ dis    : num  4.09 4.97 4.97 6.06 6.06 ...
 $ rad    : int  1 2 2 3 3 3 5 5 5 5 ...
 $ tax    : num  296 242 242 222 222 222 311 311 311 311 ...
 $ ptratio: num  15.3 17.8 17.8 18.7 18.7 18.7 15.2 15.2 15.2 15.2 ...
 $ black  : num  397 397 393 395 397 ...
 $ lstat  : num  4.98 9.14 4.03 2.94 5.33 ...
 $ medv   : num  24 21.6 34.7 33.4 36.2 28.7 22.9 27.1 16.5 18.9 ...

In [4]:
# 데이터의 형태를 바꾼다. 이렇게 바꾸면 큰 데이터 프레임을 보기 쉽도록 해 준다.
# print() 시 한 페이지에 해당하는 데이터만 보여주는 기능외에는 특별한 기능은 없음
my.data = tbl_df(Boston)
head(my.data)


crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.0063218 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98 24.0
0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14 21.6
0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03 34.7
0.03237 0 2.18 0 0.458 6.998 45.8 6.0622 3 222 18.7 394.63 2.94 33.4
0.06905 0 2.18 0 0.458 7.147 54.2 6.0622 3 222 18.7 396.90 5.33 36.2
0.02985 0 2.18 0 0.458 6.430 58.7 6.0622 3 222 18.7 394.12 5.21 28.7

Filter rows with filter()



In [11]:
# filter(데이터명, 조건식)
head(filter(my.data,
            rad == 4),
     n = 3)


crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.629760 8.14 0 0.538 5.949 61.8 4.7075 4 307 21 396.90 8.26 20.4
0.637960 8.14 0 0.538 6.096 84.5 4.4619 4 307 21 380.02 10.26 18.2
0.627390 8.14 0 0.538 5.834 56.5 4.4986 4 307 21 395.62 8.47 19.9

In [10]:
# 논리 연산자를 사용해서 조건을 늘려갈 수 있다.
head(filter(my.data, 
            rad == 1 & (tax<200|tax>300)),
     n = 3)


crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.0481980 3.64 0 0.392 6.108 32.0 9.2203 1 315 16.4 392.89 6.57 21.9
0.0354880 3.64 0 0.392 5.876 19.1 9.2203 1 315 16.4 395.18 9.25 20.9
0.0150190 1.21 1 0.401 7.923 24.8 5.8850 1 198 13.6 395.52 3.16 50.0

Arrange rows with arrange()



In [15]:
# sort(vector에 사용)
# order(data.table 패키지 => 데이터 프레임에 사용)
# dplyr 에는 arrange를 통해 정렬 가능
# 기본적으로 오름차순
head(arrange(my.data, 
             age,  # 첫 번째 조건 age 
             tax), # 두 번째 조건 tax 
     n = 3)

head(arrange(my.data, 
             desc(age)), # age를 기준으로 내림차순 
     n = 3)


crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.127440 6.91 0 0.448 6.770 2.9 5.7209 3 233 17.9 385.41 4.84 26.6
0.078960 12.83 0 0.437 6.273 6.0 4.2515 5 398 18.7 394.92 6.78 24.1
0.195390 10.81 0 0.413 6.245 6.2 5.2873 4 305 19.2 377.17 7.54 23.4
crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.2112412.5 7.87 0 0.524 5.631 100 6.0821 5 311 15.2 386.63 29.93 16.5
0.98843 0.0 8.14 0 0.538 5.813 100 4.0952 4 307 21.0 394.54 19.88 14.5
1.35472 0.0 8.14 0 0.538 6.072 100 4.1750 4 307 21.0 376.73 13.04 14.5

Select columns with select()



In [22]:
# select : 원하는 변수 선택
# R 기본 제공 형태가 subset이었나...?
head(dplyr::select(my.data,
                   nox, rm), 
     n = 3)

# :을 사용해서 선택하고자 하는 변수의 범위를 지정해주어도 된다.
head(dplyr::select(my.data, 
                   nox:dis), 
     n = 3)


noxrm
0.5386.575
0.4696.421
0.4697.185
noxrmagedis
0.538 6.575 65.2 4.0900
0.469 6.421 78.9 4.9671
0.469 7.185 61.1 4.9671

In [23]:
# start_with('문자') => 문자로 시작하는 변수 select
head(dplyr::select(my.data, 
                   starts_with('c')), 
     n = 3) 

# 정규표현식을 이용한 변수 select
# matches('정규표현식') 
# matches('^[cd]') => c or d로 시작하는 변수를 select
head(dplyr::select(my.data, 
                   matches('^[cd]')),
     n = 3)

# -matches('^[cd]') => c or d로 시작하는 변수를 제외하고 select     
head(dplyr::select(my.data,
              -matches('^[cd]')),
     n = 3)


crimchas
0.006320
0.027310
0.027290
crimchasdis
0.006320 4.0900
0.027310 4.9671
0.027290 4.9671
znindusnoxrmageradtaxptratioblacklstatmedv
18 2.31 0.538 6.575 65.2 1 296 15.3 396.904.98 24.0
0 7.07 0.469 6.421 78.9 2 242 17.8 396.909.14 21.6
0 7.07 0.469 7.185 61.1 2 242 17.8 392.834.03 34.7

Rename columns with rename()



In [25]:
# zn 변수명을 Z.N으로 변경
head(rename(my.data,
            Z.N=zn),
     n = 3)


crimZ.Ninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.0063218 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98 24.0
0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14 21.6
0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03 34.7

Add new columns (that are functions of existing columns) with mutate()



In [29]:
# 새로운 변수(column) 삽입 => mutate
# 2*age한 값을 twice.age 변수로 추가
# sqrt(twice.age)한 값을 new.col 변수로 추가 
head(mutate(my.data,
           twice.age = 2*age,
           new.col = sqrt(twice.age)),
     n = 3)


crimzninduschasnoxrmagedisradtaxptratioblacklstatmedvtwice.agenew.col
0.00632 18 2.31 0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98 24.0 130.4 11.41928
0.02731 0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14 21.6 157.8 12.56185
0.02729 0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03 34.7 122.2 11.05441

In [30]:
# transmute
# mutate와 비슷하지만 새롭게 추가된 변수만 결과로 반환
head(transmute(my.data,
               twice.age = 2*age,
               new.col = sqrt(twice.age)),
     n = 3)


twice.agenew.col
130.4 11.41928
157.8 12.56185
122.2 11.05441

Summarise values with summarise()



In [31]:
# na값을 제외한 age의 평균을 계산해서 mean.age에 넣어줌)
# group_by와 같이 사용해서 group별 연산 결과를 데이터로 삽입 가능
summarise(my.data, 
          mean.age = mean(age, na.rm = TRUE))


mean.age
68.5749

Select rows by position with slice():



In [35]:
# 데이터 슬라이싱
# 2:6(2,3,4,5,6) , 8 에 해당하는 row(데이터) 출력 
slice(my.data, c(2:6,8))

# 마지막 row(데이터) 출력
slice(my.data, n())


crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.02731 0.0 7.07 0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14 21.6
0.02729 0.0 7.07 0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03 34.7
0.03237 0.0 2.18 0 0.458 6.998 45.8 6.0622 3 222 18.7 394.63 2.94 33.4
0.06905 0.0 2.18 0 0.458 7.147 54.2 6.0622 3 222 18.7 396.90 5.33 36.2
0.02985 0.0 2.18 0 0.458 6.430 58.7 6.0622 3 222 18.7 394.12 5.21 28.7
0.1445512.5 7.87 0 0.524 6.172 96.1 5.9505 5 311 15.2 396.90 19.15 27.1
crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.047410 11.93 0 0.573 6.03 80.8 2.505 1 273 21 396.9 7.88 11.9

Extract distinct (unique) rows with distinct()



In [42]:
# distint() : 중복된 row를 제거해서 데이터 출력
# R 기본 기능 unique와 동일하지만 c언어 기반으로 구현되어 있어서 속도가 빠름
# Cars93 데이터로 살펴보자
distinct(Cars93, Origin)
distinct(Cars93, Type)
distinct(Cars93, Origin, Type)


Origin
non-USA
USA
Type
Small
Midsize
Compact
Large
Sporty
Van
TypeOrigin
Small non-USA
Midsizenon-USA
Compactnon-USA
MidsizeUSA
Large USA
CompactUSA
Sporty USA
Van USA
Small USA
Sporty non-USA
Van non-USA

Create samples with sample_n() and sample_f()



In [47]:
# n개의 데이터 sampling
sample_n(my.data, 3)

# n%의 데이터 sampling
sample_frac(my.data, .01)

# n%의 데이터 복원추출
sample_frac(my.data, .01,
            replace = TRUE)


crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.627390 8.14 0 0.538 5.834 56.5 4.4986 4 307 21.0 395.62 8.47 19.9
16.811800 18.10 0 0.700 5.277 98.1 1.4261 24 666 20.2 396.90 30.81 7.2
0.173310 9.69 0 0.585 5.707 54.0 2.3817 6 391 19.2 396.90 12.01 21.8
crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.081870 2.89 0 0.445 7.820 36.9 3.4952 2 276 18.0 393.53 3.57 43.8
0.024980 1.89 0 0.518 6.540 59.7 6.2669 1 422 15.9 389.96 8.65 16.5
0.195390 10.81 0 0.413 6.245 6.2 5.2873 4 305 19.2 377.17 7.54 23.4
0.614700 6.20 0 0.507 6.618 80.8 3.2721 8 307 17.4 396.90 7.60 30.1
0.790410 9.90 0 0.544 6.122 52.8 2.6403 4 304 18.4 396.90 5.98 22.1
crimzninduschasnoxrmagedisradtaxptratioblacklstatmedv
0.054250 4.05 0 0.510 6.315 73.4 3.3175 5 296 16.6 395.60 6.29 24.6
0.387350 25.65 0 0.581 5.613 95.6 1.7572 2 188 19.1 359.29 27.26 15.7
15.177200 18.10 0 0.740 6.152 100.0 1.9142 24 666 20.2 9.32 26.45 8.7
0.078960 12.83 0 0.437 6.273 6.0 4.2515 5 398 18.7 394.92 6.78 24.1
9.595710 18.10 0 0.693 6.404 100.0 1.6390 24 666 20.2 376.11 20.31 12.1

Grouped operations



In [53]:
# jupyter에서는 %>% 단축키((ctrl + shift + m)) 사용이 불가능 한 것 같다... 
# group_by(tax) => tax 별로 grouping해서 
# sumamrise(count = n(), mean.age = mean(age,na.rm = TRUE)
# => 각 tax별 count와 age의 평균을 계산
result.1 = my.data %>%
            group_by(tax) %>%
            summarise(count = n(),
                      mean.age = mean(age, na.rm = TRUE))
head(result.1, n = 3)


taxcountmean.age
187 1 36.10000
188 7 89.07143
193 8 75.48750

In [58]:
# Cars93 데이터가 보기 편할 것 같다...
# count     : Type별 개수
# diff.type : 중복을 제거한 Type 개수
# first     : Type별 RPM의 첫번째 데이터
# last      : Type별 RPM의 마지막 데이터
result.2 = Cars93 %>%
            group_by(Type) %>%
            summarise(count = n(),
                      diff.type = n_distinct(Type),
                      first.tax=first(RPM),
                      last.tax=last(RPM))
head(result.2, n = 3)


Typecountdiff.typefirst.taxlast.tax
Compact16 1 5500 5400
Large 11 1 4800 4800
Midsize22 1 5500 6200

그 밖에도 min(), max(), mean(), sum(), sd(), median(), IQR() 등...

다양한 기술 통계량을 구할 수 있다.


In [75]:
# tax, rad 2개의 변수를 이용하여 그룹핑
result.3 = my.data %>%
            group_by(tax, rad) %>%
            summarise(size = n())
head(result.3)


taxradsize
1875 1
1882 7
1933 8
1981 1
2163 1
2165 4

In [96]:
date=c("2014-01-01" ,"2014-01-01" ,"2014-01-01" ,
       "2014-01-01" ,"2014-01-02" ,"2014-01-02" ,
       "2014-01-02" ,"2014-01-03" ,"2014-01-03" ,"2014-01-03")
alpabet=c("a","a","b","c","d","e","a","a","d","c")
df = data.frame(date, alpabet)
df


datealpabet
2014-01-01a
2014-01-01a
2014-01-01b
2014-01-01c
2014-01-02d
2014-01-02e
2014-01-02a
2014-01-03a
2014-01-03d
2014-01-03c

In [102]:
# dumplicated() 함수는 중복된 데이터일 경우 TRUE 아니면 FALSE를 반환하는 함수
# !dumplicated()를 사용시 중복된 데이터가 삭제됨
df %>% 
  arrange(date) %>%                  # date 기준으로 오름차순
  filter(!duplicated(number)) %>%    # 중복된 알파벳 제거
  group_by(date) %>%                 # date로 그룹핑해서
  summarise(count = length(date))%>% # count  : 각 date 원소 개수 
  mutate(cumsum = cumsum(count))     # cumsum : count의 누적합


datecountcumsum
2014-01-013 3
2014-01-022 5