TÌM HIỂU VỀ DPLYR
DPLYR là một thư viện nằm trong quần thể eco-system tidyverse, có chức năng thao tác và biến đổi dữ liệu một cách trực quan. Package dplyr là thành phần rất quan trọng trong hệ sinh thái tidyverse, vì nó cung cấp những function hoán chuyển và thao tác trên dữ liệu sau khi nó đã được tải vào R. Package này được phát hành lần đầu tiên vào ngày 17 tháng 1 năm 2014, và nhanh chóng tạo ra phong trào thay thế baseR bằng dplyr trong cộng đồng. Phiên bản mới nhất hiện nay là dplyr 0.7.4 (phát hành ngày 29/9/2017).
dplyr được viết bởi Hadley Wickham và đem lại cho chúng ta những hàm hữu ích, dễ sử dụng khi thao tác xử lý dữ liệu. Một trong những khía cạnh độc đáo của dplyr đó là với cùng một tập các tools, chúng ta có thể thao tác với nhiều nguồn dữ liệu khác, bao gồm data frames, data tables, databases và multidimensional arrays.
Để tìm hiểu về các hàm xử lý dữ liệu cơ bản, trong nội dung này tôi chỉ đề cập đến một vài bộ dữ liệu cơ bản, bộ dữ liệu này chứa những thông tin về chất lượng không khí từ tháng 5 năm 19734 tháng 9 năm 1973 tại New York.
CÁC HÀM TRONG DPLYR
Cài thư viện dplyr
library(dplyr)
data("airquality")
head(airquality)
## Ozone Solar.R Wind Temp Month Day
## 1 41 190 7.4 67 5 1
## 2 36 118 8.0 72 5 2
## 3 12 149 12.6 74 5 3
## 4 18 313 11.5 62 5 4
## 5 NA NA 14.3 56 5 5
## 6 28 NA 14.9 66 5 6
Hàm select
Trong khi filter() đặt con một khung dữ liệu theo hàng, select() trả về một tập con gồm các cột.
Hàm này có thể lấy tên cột (ngay cả khi không có dấu ngoặc kép) hoặc số vị trí cột bắt đầu từ bên trái. Hơn nữa, không giống như thư viện base trong R, các lệnh trong dấu ngoặc trong select() không cần phải được nối bằng c().
select(airquality, Ozone, Temp) %>% head(4)
## Ozone Temp
## 1 41 67
## 2 36 72
## 3 12 74
## 4 18 62
%>% select(-Ozone, -Temp) %>% head(4) airquality
## Solar.R Wind Month Day
## 1 190 7.4 5 1
## 2 118 8.0 5 2
## 3 149 12.6 5 3
## 4 313 11.5 5 4
Hàm filter
Hàm này có tác dụng lọc dữ liệu, kết quả của nó trả về các dữ liệu thỏa mãn một điều kiện nào đó, thông thường hàm filter sẽ lọc dữ liệu theo dòng (lọc theo quan sát- filter by observations)
Ví dụ: Chúng ta muốn lọc các kết quả có chất lượng \(Ozone > 106\); lọc các kết quả có chất lượng \(Ozone > 106\) và rơi vào tháng 8
filter(airquality, Ozone > 106) %>% head(5)
## Ozone Solar.R Wind Temp Month Day
## 1 115 223 5.7 79 5 30
## 2 135 269 4.1 84 7 1
## 3 108 223 8.0 85 7 25
## 4 122 255 4.0 89 8 7
## 5 110 207 8.0 90 8 9
filter(airquality, Ozone > 106 & Month == 8) %>% head(5)
## Ozone Solar.R Wind Temp Month Day
## 1 122 255 4.0 89 8 7
## 2 110 207 8.0 90 8 9
## 3 168 238 3.4 81 8 25
## 4 118 225 2.3 94 8 29
filter(airquality, Ozone > 106, Month == 8, Wind > 7) %>% head(5)
## Ozone Solar.R Wind Temp Month Day
## 1 110 207 8 90 8 9
Hàm mutate
Hàm mutate có tác dụng tạo thêm một cột biến mới thỏa mãn một điều kiện nào đó hoặc đơn thuần là tạo ra cột biến mới dựa theo một công thức tính toán nào đó. Ví dụ: Chúng ta muốn thêm một cột biến mới, hiển thị nhiệt độ theo độ C trong bộ dữ liệu airquality
mutate(airquality, temp.celsius = Temp - 31) %>% head(5)
## Ozone Solar.R Wind Temp Month Day temp.celsius
## 1 41 190 7.4 67 5 1 36
## 2 36 118 8.0 72 5 2 41
## 3 12 149 12.6 74 5 3 43
## 4 18 313 11.5 62 5 4 31
## 5 NA NA 14.3 56 5 5 25
Hàm summarize và group_by
Hàm summarize giúp khái quát thống kê, đơn thuần là tổng kết nhiều giá trị nào đó trở thành một giá trị. Hàm này thông thường kết hợp với hàm sắp xếp theo nhóm, tạo ra sức mạnh thống kê khá tuyệt vời. Ví dụ: Chúng ta muốn nhóm các dữ liệu theo các tháng thành các nhóm, sau đó tính trung bình nhiệt độ theo các tháng để so sánh
summarize(group_by(airquality, Month), round(mean(Temp, na.rm = T)))
## # A tibble: 5 x 2
## Month `round(mean(Temp, na.rm = T))`
## <int> <dbl>
## 1 5 66
## 2 6 79
## 3 7 84
## 4 8 84
## 5 9 77
Hàm sample
Hàm này có tác dụng lấy ngẫu nhiên từ bộ dữ liệu ra bao nhiêu quan sát, có thể lấy theo số lượng hoặc lấy theo \(\%\). Ví dụ:
sample_n(airquality, 4) # Lấy ngẫu nhiên 4
## Ozone Solar.R Wind Temp Month Day
## 1 NA NA 14.3 56 5 5
## 2 1 8 9.7 59 5 21
## 3 7 NA 6.9 74 5 11
## 4 97 272 5.7 92 7 9
sample_frac(airquality, size = 0.02) # Lấy ngẫu nhiên 2%
## Ozone Solar.R Wind Temp Month Day
## 1 34 307 12.0 66 5 17
## 2 61 285 6.3 84 7 18
## 3 23 299 8.6 65 5 7
Hàm count
Hàm count có tác dụng thống kê số lượng. Chức năng của hàm này hoàn toàn giống như tác dụng của hàm table() khi chúng ta cần thống kê số lượng cho các biến phân loại. Ví dụ: Muốn đếm số lượng Nam hoặc Nữ cho một tập dữ liệu gồm 100 quan sát chẳng hạn, với ví dụ airquality:
count(airquality, Month > 5) # Đếm xem có bao nhiêu quan sát có tháng lớn hơn 5 và nhỏ hơn
## Month > 5 n
## 1 FALSE 31
## 2 TRUE 122
count(airquality, Month) # Thống kê theo tháng
## Month n
## 1 5 31
## 2 6 30
## 3 7 31
## 4 8 31
## 5 9 30
Hàm arrange
Hàm arrange() được sử dụng để sắp xếp các hàng theo các biến. Hiện tại, tập dữ liệu airquality được sắp xếp dựa trên Tháng và sau đó là Ngày. Chúng ta có thể sử dụng chức năng sắp xếp để sắp xếp các hàng theo thứ tự giảm dần của Tháng, và sau đó theo thứ tự tăng dần của Ngày.
arrange(airquality, Month, Day) %>% head(5) # mặc định là ascending- tăng dần
## Ozone Solar.R Wind Temp Month Day
## 1 41 190 7.4 67 5 1
## 2 36 118 8.0 72 5 2
## 3 12 149 12.6 74 5 3
## 4 18 313 11.5 62 5 4
## 5 NA NA 14.3 56 5 5
arrange(airquality, desc(Month), Day) %>% head(5) # để sắp giảm dần, dùng desc (tức descending)
## Ozone Solar.R Wind Temp Month Day
## 1 96 167 6.9 91 9 1
## 2 78 197 5.1 92 9 2
## 3 73 183 2.8 93 9 3
## 4 91 189 4.6 93 9 4
## 5 47 95 7.4 87 9 5
Hàm contains()
contains() là một hàm trợ giúp được sử dụng với select(), tương tự với hàm tìm chuỗi str_detect() được sử dụng với filter(), contains() cũng hữu ích để chọn tất cả các tên cột có một ký tự nhất định.
Ví dụ để chỉ chọn các cột có tên chứa chữ cái \(y\):
%>% select(contains('y')) %>% head(4) mpg_df
## # A tibble: 4 x 4
## year cyl cty hwy
## <int> <int> <int> <int>
## 1 1999 4 18 29
## 2 1999 4 21 29
## 3 2008 4 20 31
## 4 2008 4 21 30
Hàm starts_with()
start_with() và end_with() cung cấp tính năng lựa chọn cụ thể hơn so với select(). Nếu chúng ta muốn tất cả các cột bắt đầu bằng chữ cái \(c\):
%>% select(starts_with('c')) %>% head(4) mpg_df
## # A tibble: 4 x 3
## cyl cty class
## <int> <int> <chr>
## 1 4 18 compact
## 2 4 21 compact
## 3 4 20 compact
## 4 4 21 compact
%>% select( 2, 1, class, contains('y')) %>% head(4) mpg_df
## # A tibble: 4 x 7
## model manufacturer class year cyl cty hwy
## <chr> <chr> <chr> <int> <int> <int> <int>
## 1 a4 audi compact 1999 4 18 29
## 2 a4 audi compact 1999 4 21 29
## 3 a4 audi compact 2008 4 20 31
## 4 a4 audi compact 2008 4 21 30
Hàm everything()
Một hàm trợ giúp rất hữu ích là hàm everything(), trả về tất cả các tên cột chưa được chỉ định. Nó thường được sử dụng khi sắp xếp lại thứ tự tất cả các cột trong khung dữ liệu:
%>% select(class,displ,year,everything()) %>% head(4) mpg_df
## # A tibble: 4 x 11
## class displ year manufacturer model cyl trans drv cty hwy fl
## <chr> <dbl> <int> <chr> <chr> <int> <chr> <chr> <int> <int> <chr>
## 1 compact 1.8 1999 audi a4 4 auto(l5) f 18 29 p
## 2 compact 1.8 1999 audi a4 4 manual(m~ f 21 29 p
## 3 compact 2 2008 audi a4 4 manual(m~ f 20 31 p
## 4 compact 2 2008 audi a4 4 auto(av) f 21 30 p
Toán tử pipe
Giới thiệu về toán tử pipe (%>%)
Trong lập trình, pipe là 1 khái niệm thường được dùng để mô tả việc sử dụng đầu ra của 1 hàm xử lý này để sử dụng như đầu vào của 1 hàm xử lý khác. Khi khối xử lý kéo dài thành 1 chuỗi liên tiếp nhau thì còn được gọi là chaining và có lẽ việc gắn kết liên tục thành luồng đó gợi đến hình tượng của ống nước nên người ta gọi hành vi nối đó là nối ống piping.
Toán tử pipe không chỉ thay đổi về cách thức viết R code, làm cho R code trong sáng và được cấu trúc tốt hơn mà còn thay đổi cách tư duy của người dùng R.
Toán tử Forward Pipe
Đây là dạng pipe thông dụng nhất. Công dụng của Forward Pipe là chuyển toàn bộ kết quả của hàm đi trước (bên trái) thành dữ liệu đầu vào của hàm đi sau (bên phải) trong một chuỗi quy trình. Kết quả sau cùng là của hàm cuối cùng (bên phải) trong chuỗi. Như vậy toán tử Forward Pipe có tính chất 1 chiều và định hướng từ trái sang phải. Có thể hình dung về một dòng chảy của data qua một đường ống (pipe).
# Forward pipe
rnorm(100,20,5)%>%
matrix(ncol=2)%>%
data.frame(x=.[,1],y=.[,2])%>%
plot(col="red")
Là một chuỗi quy trình :
Tạo ngẫu nhiên 100 số theo phân phối chuẩn, trung bình = 20, sd=5 ;
Chia đều vector này thành 1 matrix có 2 cột,
Chuyển matrix này thành 1 dataframe, và gán giá trị 2 cột 1, 2 của matrix cho 2 biến x,y.
Cuối cùng, vẽ scatterdot matrix giữa X1,X2,x,y bằng hàm plot().
Cách trình bày này rõ ràng và dễ hiểu, tránh việc tạo object trung gian và lồng ghép các hàm nếu như ta không dùng pipe.
Toán tử T pipe
Toán tử T pipe có thể được hình dung như 1 ống nước hình chữ T, khiến cho dữ liệu đầu vào của 1 hàm A đi trước sẽ được truyền cho 2 nhánh tương ứng với quy trình B1 (là 1 hàm) và quy trình B2. Một ứng dụng phổ biến nhất của T pipe là để vẽ 2 đồ thị khác nhau cho cùng 1 gói dữ liệu, như thí dụ sau :
# T pipe
rnorm(100,10,1)%T>%
ts.plot(col="red")%>%
density()%>%
plot(col="blue","densityplot")
Toán tử Assigning pipe
Toán tử Assigning pipe cho phép trích xuất đích danh một đối tượng trong kết quả của hàm đi trước để sử dụng như dữ liệu đầu vào cho hàm đi sau. Như vậy nó có tính định hướng 1 chiều nhưng chuyên biệt, để sử dụng toán tử này được, cần sử dụng thư viện magrittr.
library(magrittr)
data.frame(x=rnorm(100,10,5),
y=rnorm(100,20,5)) %$% ts.plot(x,col="red")
data.frame(x=rnorm(100,10,5),
y=rnorm(100,20,5)) %$% ts.plot(y,col="blue")
Toán tử Backward pipe
Công dụng của backward pipe trái chiều với forward pipe, tức là kết quả cuối cùng sau mọi quy trình bên phải trong chuỗi sẽ được truyền ngược về object đầu tiên nằm ngoài cùng bên trái của chuỗi.
Để minh họa, ta có thí dụ sau đây:
X là 1 vector chứa 100 giá trị ngẫu nhiên có phân phối chuẩn Y cũng thế (chính là X). Ta dùng backward pipe để thực hiện lần lượt 2 phép toán : bình phương X, sau đó khai căn bậc 2. Dễ thấy kết quả sau cùng chính là giá trị ban đầu. Có thể kiểm tra bằng cách so sánh x, y, chúng hoàn toàn như nhau
library(magrittr)
=abs(rnorm(100))
x=x
ycbind(x,y)%>%head()
## x y
## [1,] 1.2824727 1.2824727
## [2,] 0.3962973 0.3962973
## [3,] 1.1776062 1.1776062
## [4,] 0.2534644 0.2534644
## [5,] 1.8974508 1.8974508
## [6,] 0.2274406 0.2274406
%<>% .^2 %>% sqrt()
x ==y x
## [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [16] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [31] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [46] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [61] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [76] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [91] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
THỰC HÀNH VỚI DỮ LIỆU MPG
library(tidyverse)
library(dplyr)
<- mpg
mpg_df # filter the mpg_df data for cars manufactured in the year 1999
filter(mpg_df, year == 1999) %>% head(5)
## # A tibble: 5 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto(~ f 18 29 p comp~
## 2 audi a4 1.8 1999 4 manua~ f 21 29 p comp~
## 3 audi a4 2.8 1999 6 auto(~ f 16 26 p comp~
## 4 audi a4 2.8 1999 6 manua~ f 18 26 p comp~
## 5 audi a4 quattro 1.8 1999 4 manua~ 4 18 26 p comp~
# Show the dimension
filter(mpg_df, year == 1999) %>% dim()
## [1] 117 11
# let’s take all vehicles in the ‘midsize’ class:
filter(mpg_df, class == "midsize") %>% head(5)
## # A tibble: 5 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a6 quattro 2.8 1999 6 auto(~ 4 15 24 p mids~
## 2 audi a6 quattro 3.1 2008 6 auto(~ 4 17 25 p mids~
## 3 audi a6 quattro 4.2 2008 8 auto(~ 4 16 23 p mids~
## 4 chevrolet malibu 2.4 1999 4 auto(~ f 19 27 r mids~
## 5 chevrolet malibu 2.4 2008 4 auto(~ f 22 30 r mids~
# filter for vehicles built in 1999 and with mileage in the city (cty) greater than 18.
%>% filter(year==1999 & cty > 18) %>% head(4) mpg_df
## # A tibble: 4 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 manual(m5) f 21 29 p comp~
## 2 chevrolet malibu 2.4 1999 4 auto(l4) f 19 27 r mids~
## 3 honda civic 1.6 1999 4 manual(m5) f 28 33 r subc~
## 4 honda civic 1.6 1999 4 auto(l4) f 24 32 r subc~
# filter for vehicles (i.e., rows) where the manufacturer is Chevrolet or the class is ‘suv’.
%>% filter(manufacturer=='chevrolet' | class=='suv') %>% head(4) mpg_df
## # A tibble: 4 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 chevrolet c1500 sub~ 5.3 2008 8 auto(~ r 14 20 r suv
## 2 chevrolet c1500 sub~ 5.3 2008 8 auto(~ r 11 15 e suv
## 3 chevrolet c1500 sub~ 5.3 2008 8 auto(~ r 14 20 r suv
## 4 chevrolet c1500 sub~ 5.7 1999 8 auto(~ r 13 17 r suv
%>% filter( (manufacturer=='chevrolet' | class=='suv') & hwy < 20) %>% head(4) mpg_df
## # A tibble: 4 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 chevrolet c1500 sub~ 5.3 2008 8 auto(~ r 11 15 e suv
## 2 chevrolet c1500 sub~ 5.7 1999 8 auto(~ r 13 17 r suv
## 3 chevrolet c1500 sub~ 6 2008 8 auto(~ r 12 17 r suv
## 4 chevrolet k1500 tah~ 5.3 2008 8 auto(~ 4 14 19 r suv
Sử dụng str_detect() và %in
Thông thường, chúng ta muốn nắm bắt các hàng có chứa một chuỗi các chữ cái cụ thể. Ví dụ: có 10 kiểu xe khác nhau có chứa các chữ cái \('4wd'\). Một cách tốt hơn nhiều là ‘phát hiện’ các chữ cái \('4wd'\) trong cột và trả về tất cả các hàng mà chúng có mặt, bằng cách sử dụng str_detect ().
Khi chúng ta quan tâm đến một tập hợp con các hàng có thể chứa một số giá trị khác nhau, thay vì viết một lệnh OR dài, sẽ hữu ích khi chỉ đưa ra một vectơ có giá trị quan tâm.
Ví dụ: để lấy tập hợp con các phương tiện trong mpg_df có 4, 5 hoặc 6 xi lanh, chúng ta có thể chỉ định trong tập hợp (4,5,6)
library(tidyverse)
%>% filter(str_detect(model,'4wd')) %>% head(5) mpg_df
## # A tibble: 5 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 chevrolet k1500 ta~ 5.3 2008 8 auto(l~ 4 14 19 r suv
## 2 chevrolet k1500 ta~ 5.3 2008 8 auto(l~ 4 11 14 e suv
## 3 chevrolet k1500 ta~ 5.7 1999 8 auto(l~ 4 11 15 r suv
## 4 chevrolet k1500 ta~ 6.5 1999 8 auto(l~ 4 14 17 d suv
## 5 dodge dakota p~ 3.7 2008 6 manual~ 4 15 19 r pick~
%>% filter(cyl %in% c(4,5,6)) %>% head(5) mpg_df
## # A tibble: 5 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto(l5) f 18 29 p compa~
## 2 audi a4 1.8 1999 4 manual(m5) f 21 29 p compa~
## 3 audi a4 2 2008 4 manual(m6) f 20 31 p compa~
## 4 audi a4 2 2008 4 auto(av) f 21 30 p compa~
## 5 audi a4 2.8 1999 6 auto(l5) f 16 26 p compa~
Phát hiện dữ liệu trống
Nếu có giá trị \(NA\) (bị thiếu) trong một cột cụ thể, chúng ta có thể kiểm tra hoặc loại bỏ chúng bằng cách sử dụng trình trợ giúp is.na ().
Để kiểm tra sự hiện diện của các giá trị \(NA\) trong cột year, ví dụ:
%>% filter(is.na(year)) mpg
## # A tibble: 0 x 11
## # ... with 11 variables: manufacturer <chr>, model <chr>, displ <dbl>,
## # year <int>, cyl <int>, trans <chr>, drv <chr>, cty <int>, hwy <int>,
## # fl <chr>, class <chr>
# To drop out all the missing value
%>% filter(!is.na(year)) %>% head(4) mpg
## # A tibble: 4 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto(l5) f 18 29 p compa~
## 2 audi a4 1.8 1999 4 manual(m5) f 21 29 p compa~
## 3 audi a4 2 2008 4 manual(m6) f 20 31 p compa~
## 4 audi a4 2 2008 4 auto(av) f 21 30 p compa~
Kiểm tra giá trị bằng complete.cases(.)
Để chỉ lọc các hàng không có giá trị bị thiếu:
%>% filter(complete.cases(.)) %>% head(4) mpg
## # A tibble: 4 x 11
## manufacturer model displ year cyl trans drv cty hwy fl class
## <chr> <chr> <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
## 1 audi a4 1.8 1999 4 auto(l5) f 18 29 p compa~
## 2 audi a4 1.8 1999 4 manual(m5) f 21 29 p compa~
## 3 audi a4 2 2008 4 manual(m6) f 20 31 p compa~
## 4 audi a4 2 2008 4 auto(av) f 21 30 p compa~
# And to filter for all rows with a missing value in at least one column:
%>% filter( !complete.cases(.) ) mpg
## # A tibble: 0 x 11
## # ... with 11 variables: manufacturer <chr>, model <chr>, displ <dbl>,
## # year <int>, cyl <int>, trans <chr>, drv <chr>, cty <int>, hwy <int>,
## # fl <chr>, class <chr>
Chaining dplyr and ggplot
%>%
mpg_df filter(class=='midsize') %>%
select(class,manufacturer,displ,year) %>%
arrange(displ) %>%
ggplot(aes(x=class,y=displ)) + geom_boxplot()
DỮ LIỆU DIAMOND
Trong nội dung phần này, chúng ta sẽ tổng hợp thêm một số hàm khác và các cách phối hợp các hàm trong thư viện dplyr để thao tác với dữ liệu
Tạo ra một cột biến mới, với giá trị là đô la Úc, biết rằng \(AUD=USD\times 1.25\)
library(ggplot2)
<- diamonds
diamonds_df %>% select(-x, -y, -z) %>% mutate(AUD = price*1.25) %>% head(4) diamonds_df
## # A tibble: 4 x 8
## carat cut color clarity depth table price AUD
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 408.
## 2 0.21 Premium E SI1 59.8 61 326 408.
## 3 0.23 Good E VS1 56.9 65 327 409.
## 4 0.29 Premium I VS2 62.4 58 334 418.
Chúng ta có thể thêm một cột biến nữa là giá 1 carat bằng cách lấy cột price chia cho cột carat
%>% select(-x, -y , -z) %>% mutate(ppc = price/carat) %>% head(4) diamonds_df
## # A tibble: 4 x 8
## carat cut color clarity depth table price ppc
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl>
## 1 0.23 Ideal E SI2 61.5 55 326 1417.
## 2 0.21 Premium E SI1 59.8 61 326 1552.
## 3 0.23 Good E VS1 56.9 65 327 1422.
## 4 0.29 Premium I VS2 62.4 58 334 1152.
Thử thách: Biết rằng 1 carat nặng 0.2 grams, hãy sử dụng hàm mutate() để thêm 2 cột biến, một cột biến theo giá AUD và một cột biến tính giá trị của 1 gram kim cương theo AUD (Australian Dollars).
Việc kết hợp hàm \(ifelse()\) và hàm mutate() có thể được thực hiện để tạo ra nhiều biến số một cách dễ dàng. Ví dụ: tạo ra một biến số là price-label với điều kiện nếu giá \(price>5000\) thì kim cương là loại đắt (expensive), ngược lại là loại rẻ (cheap)
%>% select(-x, -y, -z) %>% mutate(price_label = ifelse(price > 5000, "expensive", "cheap")) %>% head(10) diamonds_df
## # A tibble: 10 x 8
## carat cut color clarity depth table price price_label
## <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <chr>
## 1 0.23 Ideal E SI2 61.5 55 326 cheap
## 2 0.21 Premium E SI1 59.8 61 326 cheap
## 3 0.23 Good E VS1 56.9 65 327 cheap
## 4 0.29 Premium I VS2 62.4 58 334 cheap
## 5 0.31 Good J SI2 63.3 58 335 cheap
## 6 0.24 Very Good J VVS2 62.8 57 336 cheap
## 7 0.24 Very Good I VVS1 62.3 57 336 cheap
## 8 0.26 Very Good H SI1 61.9 55 337 cheap
## 9 0.22 Fair E VS2 65.1 61 337 cheap
## 10 0.23 Very Good H VS1 59.4 61 338 cheap
# Make the plot
%>% select(-x,-y,-z) %>%
diamonds_df mutate(price_label = ifelse(price > 5000,'expensive','cheap')) %>%
ggplot(aes(x=price, fill = price_label)) +
geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Lệnh case_when()
Lệnh case_when() được sử dụng khi chúng ta có nhiều điều kiện ràng buộc, câu lệnh này được coi là thay thế trong trường hợp phải dùng quá nhiều ifelse(). Giả dụ về độ tinh khiết (clarity) của kim cương, chúng ta phát biểu vài giả định và quy ước như sau:
IF: internally flawless (Hoàn toàn tinh khiết)
VVS1 and 2: very very slight impurity 1 and 2 (Có tạp chất rất rất nhỏ)
VS1 and 2: very slight impurity 1 and 2 (Có lượng nhỏ tạp chất)
SI1 and 2: slight impurity 1 and 2 (Tạp chất ít)
I1: impurity (Tạp chất, mờ đục)
%>%
diamonds_df select(clarity) %>%
mutate(clarity_group = case_when(clarity == 'IF' ~ 'flawless',
str_detect(clarity, 'VVS') ~ 'VV_slight',
str_detect(clarity, 'VS') ~ 'V_slight',
str_detect(clarity, 'SI') ~ 'slight',
== 'I1' ~ 'impurity',
clarity TRUE ~ 'other')) %>% head(10)
## # A tibble: 10 x 2
## clarity clarity_group
## <ord> <chr>
## 1 SI2 slight
## 2 SI1 slight
## 3 VS1 V_slight
## 4 VS2 V_slight
## 5 SI2 slight
## 6 VVS2 VV_slight
## 7 VVS1 VV_slight
## 8 SI1 slight
## 9 VS2 V_slight
## 10 VS1 V_slight
Toán tử n() và summarize()
Trong trường hợp chúng ta muốn thực hiện thống kê nhóm hoặc thống kê theo các hàm với các cột, sử dụng summarize(), giống như ở lúc đầu đã đề cập đến. Ở đây tôi đề cập thêm đến toán tử n() để đếm số dòng hay số quan sát cho các cột. Tuy nhiên cần nói lại rằng hàm summarize() thực sự phát huy sức mạnh khi kết hợp cùng với hàm thống kê theo nhóm group_by().
%>% summarize(mean_price = mean(price),
diamonds_df sd_price = sd(price),
min_price = min(price),
max_price = max(price),
n_rows = n())
## # A tibble: 1 x 5
## mean_price sd_price min_price max_price n_rows
## <dbl> <dbl> <int> <int> <int>
## 1 3933. 3989. 326 18823 53940
Hàm summarize và group_by khi kết hợp.
%>% group_by(clarity) %>%
diamonds_df summarize(mean_price = mean(price),
sd_price = sd(price),
min_price = min(price),
max_price = max(price),
n_rows = n()) %>% head(10)
## # A tibble: 8 x 6
## clarity mean_price sd_price min_price max_price n_rows
## <ord> <dbl> <dbl> <int> <int> <int>
## 1 I1 3924. 2807. 345 18531 741
## 2 SI2 5063. 4260. 326 18804 9194
## 3 SI1 3996. 3799. 326 18818 13065
## 4 VS2 3925. 4042. 334 18823 12258
## 5 VS1 3839. 4012. 327 18795 8171
## 6 VVS2 3284. 3822. 336 18768 5066
## 7 VVS1 2523. 3335. 336 18777 3655
## 8 IF 2865. 3920. 369 18806 1790
%>%
diamonds_df group_by(clarity, cut) %>%
summarize(mean_price = mean(price),
sd_price = sd(price),
min_price = min(price),
max_price = max(price),
n_rows = n()) %>% head(10)
## `summarise()` has grouped output by 'clarity'. You can override using the `.groups` argument.
## # A tibble: 10 x 7
## # Groups: clarity [2]
## clarity cut mean_price sd_price min_price max_price n_rows
## <ord> <ord> <dbl> <dbl> <int> <int> <int>
## 1 I1 Fair 3704. 3099. 584 18531 210
## 2 I1 Good 3597. 2285. 361 11548 96
## 3 I1 Very Good 4078. 2720. 511 15984 84
## 4 I1 Premium 3947. 2827. 345 16193 205
## 5 I1 Ideal 4336. 2671. 413 16538 146
## 6 SI2 Fair 5174. 3928. 536 18308 466
## 7 SI2 Good 4580. 3901. 335 18788 1081
## 8 SI2 Very Good 4989. 4126. 383 18692 2100
## 9 SI2 Premium 5546. 4488. 345 18784 2949
## 10 SI2 Ideal 4756. 4252. 326 18804 2598