Phần một :)

Những bạn nào làm với R lâu, bằng cách này hoặc cách khác, sẽ phải gặp 2 gói sử lí dữ liệu nổi tiếng soái ca soái tỉ đó là dplyr và data.table. Riêng mình, mình chỉ sử dụng dplyr, nhưng dạo này đọc nhiều thứ viết bằng data.table quá nên đọc sơ qua để biết.

Sau đây là một bài trình bày ngắn gọn, so sánh giữa dplyr và data.table. Viết để giữ lại. Nếu các bạn muốn xem bài trước về dplyr, ggplot2 và dygraph có thể xem ở bài trước mình post: http://rpubs.com/tkvit/228141

Phần hai “_"

library(data.table) 
library(tidyverse) 
library(microbenchmark)

rm(list=ls())
filecloud <- "/Volumes/Public/Work_test/Data_R/Us_baby_names/StateNames.csv"
filehdd <- "/Volumes/TKV 900Go/Work_test/Data_R/Us_baby_names/StateNames.csv"
df <-tbl_df(fread(filecloud,
                  colClasses = c("numeric","character","numeric","character","character","numeric")))
df1 <- as.data.table(df)
df_backup <- df

Ở phần này mình chia ra df thuộc dạng data.frame, df1 thuộc dạng data.table.

dim(df)
## [1] 5647426       6
head(df)
## # A tibble: 6 × 6
##      Id     Name  Year Gender State Count
##   <dbl>    <chr> <dbl>  <chr> <chr> <dbl>
## 1     1     Mary  1910      F    AK    14
## 2     2    Annie  1910      F    AK    12
## 3     3     Anna  1910      F    AK    10
## 4     4 Margaret  1910      F    AK     8
## 5     5    Helen  1910      F    AK     7
## 6     6    Elsie  1910      F    AK     6

Dữ liệu gồm 5647426 dòng và 6 cột. Bây giờ mình bắt đầu xử lí bằng dplyr và data.table

Tìm ra top 5 tên nữ (Top 5 names female in general)

#dplyr
top5a <- df %>% filter(Gender == "F")  %>% 
    group_by(Name)   %>% 
    summarise(name_count = sum(Count),
              num_years = n_distinct(Year)) %>% #Sometime need to reset...
    ungroup() %>% 
    arrange(desc(name_count)) %>% 
    slice(1:5) 

#data.table
top5b <- df1[Gender == "F",.(name_count = sum(Count),num_years = uniqueN(Year)),by=Name
             ][order (-name_count)][1:5]
top5a
## # A tibble: 5 × 3
##        Name name_count num_years
##       <chr>      <dbl>     <int>
## 1      Mary    3730856       105
## 2  Patricia    1567779       105
## 3 Elizabeth    1500462       105
## 4  Jennifer    1461813        82
## 5     Linda    1446300       105
top5b
##         Name name_count num_years
## 1:      Mary    3730856       105
## 2:  Patricia    1567779       105
## 3: Elizabeth    1500462       105
## 4:  Jennifer    1461813        82
## 5:     Linda    1446300       105
all.equal(top5a,top5b)
## [1] TRUE

Vẽ đồ thị tên top1 theo thời gian

#dplyr
top1a <- df %>% 
    filter(Name == top5a$Name[1]) %>% 
    group_by(Year) %>% 
    summarise(n_count =sum(Count)) %>% ungroup()

#data.table
top1b <- df1[Name == top5b$Name[1],.(n_count = sum(Count)), by = Year]
top1a %>% 
    ggplot(aes(x= Year, y=n_count)) + geom_bar(stat = "identity",color = "#3399FF") + 
    theme_bw() + ggtitle(top5a$Name[1])

top1b %>%
  ggplot(aes(x= Year, y=n_count)) + geom_bar(stat = "identity",color = "#3399FF") + 
           theme_bw() + ggtitle(top5a$Name[1])

all.equal(top1a,top1b)
## [1] TRUE

Top1 tên nữ theo từng bang

#dplyr
top1a_f <- df %>% 
  group_by(State) %>% 
  summarise(nc_female = sum(Count[Name == top5a$Name[1]])) %>% ungroup()

#data.table
top1b_f <- df1[Name == top5b$Name[1], .(nc_female = sum(Count)),by=State]
all.equal(top1a_f,top1b_f)
## [1] TRUE

Tên Nữ từ năm 2010 và có số lần >100 ở tất cả các bang

Sự khác nhau về tốc độ tuy có nhưng không đáng kể ở các phần trước. Ở phần này data.table nhanh hơn rõ rệt

#dplyr
name2010a <- df %>% 
  group_by(Name,Year) %>% 
  filter(Year > 2010) %>% 
  group_by(Name) %>% 
  summarise(n_count = sum(Count)) %>% ungroup() %>% 
  filter(n_count >100)

#data.table
name2010b <- df1[Year > 2010,.(n_count = sum(Count)), by = Name][n_count>100,]
all.equal(name2010a,name2010b)
## [1] TRUE

Những tên nam cũ không được dùng từ năm 2000

#dplyr
notuse2010a <- df %>% 
  filter(Gender == "M") %>% 
  group_by(Name) %>% 
  summarise(n_count = sum(Count),
            first_use = min(Year),
            last_use = max(Year)) %>% 
  filter(first_use>1910,last_use<2000) %>% 
  ungroup() %>% 
  arrange(desc(n_count)) %>% 
  slice(1:2)

#data.table
notuse2010b <- df1[Gender == "M", .(n_count = sum(Count),
                                    first_use = min(Year),
                                    last_use = max(Year)),by = Name
                   ][first_use >1910 | last_use <2000,][order (-n_count)][1:2]

Microbenchmark cho 2 đoạn code trên

## Unit: milliseconds
##       expr      min       lq     mean   median       uq      max neval cld
##      dplyr 478.3774 534.7571 560.8748 559.1787 585.5486 661.5337   100   b
##  datatable 128.4965 146.4850 162.1112 153.6922 166.1464 312.0254   100  a

Phần ba ^^