13 Nhóm dữ liệu
Chương này trình bày cách nhóm và tổng hợp dữ liệu phục vụ phân tích mô tả. Sử dụng các package trong hệ sinh thái tidyverse với các hàm phổ biến và dễ sử dụng.
Nhóm dữ liệu là một cấu phần cốt lõi trong quản lý và phân tích dữ liệu. Dữ liệu được nhóm tổng hợp thống kê theo nhóm và có thể được vẽ biểu đồ theo nhóm. Các hàm từ package dplyr (một phần của thư viện tidyverse) giúp việc nhóm dữ liệu và các thao tác tiếp theo trở nên dễ dàng hơn.
Chương này sẽ giải quyết các chủ đề sau:
- Nhóm dữ liệu với hàm
group_by()
- Gỡ nhóm dữ liệu
summarise()
dữ liệu được nhóm với các thống kê
- Sự khác biệt giữa hàm
count()
vàtally()
- Ứng dụng hàm
arrange()
với dữ liệu được nhóm
- Ứng dụng hàm
filter()
với dữ liệu được nhóm
- Ứng dụng hàm
mutate()
với dữ liệu được nhóm
- Ứng dụng hàm
select()
với dữ liệu được nhóm
- Hàm
aggregate()
trong base R như một lựa chọn thay thế
13.1 Chuẩn bị
Gọi package
Đoạn code này hiển thị cách gọi các package cần thiết cho phân tích. Trong cuốn này, chúng ta nhấn mạnh đến hàm p_load()
từ package pacman, sẽ cài đặt packahe nếu cần và gọi để sử dụng. Bạn cũng có thể gọi các package đã cài đặt với hàm library()
từ base R. Xem chương R cơ bản để biết thêm thông tin về các package trong R.
::p_load(
pacman# to import data
rio, # to locate files
here, # to clean, handle, and plot the data (includes dplyr)
tidyverse, # adding total rows and columns janitor)
Nhập dữ liệu
Chúng ta nhập bộ dữ liệu về các trường hợp mô phỏng từ một vụ dịch Ebola. Nếu bạn muốn cùng thực hành, bấm vào đây để tải bộ liệu linelist
“sạch” (tệp .rds). Bộ dữ liệu được nhập bằng hàm import()
từ package rio. Xem chương Nhập xuất dữ liệu để biết các cách nhập dữ liệu khác nhau.
<- import("linelist_cleaned.rds") linelist
50 hàng đầu tiên của bộ số liệu linelist
:
13.2 Nhóm
Hàm group_by()
từ dplyr nhóm các hàng theo các giá trị duy nhất trong cột chỉ định. Nếu nhiều cột được chỉ định, các hàng được nhóm theo sự tổ hợp các giá trị thành giá trị duy nhất từ các cột. Mỗi giá trị duy nhất (hoặc tổ hợp các giá trị) tạo thành một nhóm. Những thay đổi sau đó đối với bộ dữ liệu hoặc các phép tính có thể thực hiện tùy theo đặc điểm của mỗi nhóm.
Ví dụ: lệnh bên dưới truy vấn bộ số liệu linelist
và nhóm các hàng theo giá trị duy nhất trong cột outcome
, lưu kết quả đầu ra dưới dạng bộ dữ liệu mới có tên ll_by_outcome
. (Các) cột được nhóm được đặt bên trong dấu ngoặc đơn của hàm group_by()
.
<- linelist %>%
ll_by_outcome group_by(outcome)
Lưu ý rằng không có thay đổi dễ nhận thấy nào đối với bộ dữ liệu sau khi chạy lệnh group_by()
, cho đến khi phối hợp thêm một số hàm từ dplyr khác như mutate()
, summarise()
, hoặc arrange()
trong bộ dữ liệu “đã được nhóm”.
Tuy nhiên, bạn có thể “xem” các nhóm bằng cách in bộ dữ liệu. Khi bạn in một bộ dữ liệu được nhóm, bạn sẽ thấy nó đã được chuyển đổi thành một đối tượng dạng tibble
, mà khi được in ra, sẽ hiển thị những nhóm nào đã được áp dụng và có bao nhiêu nhóm - được viết ngay phía trên hàng tiêu đề.
# print to see which groups are active
ll_by_outcome
# A tibble: 5,888 × 30
# Groups: outcome [3]
case_id generation date_infection date_onset date_hospitalisation
<chr> <dbl> <date> <date> <date>
1 5fe599 4 2014-05-08 2014-05-13 2014-05-15
2 8689b7 4 NA 2014-05-13 2014-05-14
3 11f8ea 2 NA 2014-05-16 2014-05-18
4 b8812a 3 2014-05-04 2014-05-18 2014-05-20
5 893f25 3 2014-05-18 2014-05-21 2014-05-22
6 be99c8 3 2014-05-03 2014-05-22 2014-05-23
7 07e3e8 4 2014-05-22 2014-05-27 2014-05-29
8 369449 4 2014-05-28 2014-06-02 2014-06-03
9 f393b4 4 NA 2014-06-05 2014-06-06
10 1389ca 4 NA 2014-06-05 2014-06-07
# ℹ 5,878 more rows
# ℹ 25 more variables: date_outcome <date>, outcome <chr>, gender <chr>,
# age <dbl>, age_unit <chr>, age_years <dbl>, age_cat <fct>, age_cat5 <fct>,
# hospital <chr>, lon <dbl>, lat <dbl>, infector <chr>, source <chr>,
# wt_kg <dbl>, ht_cm <dbl>, ct_blood <dbl>, fever <chr>, chills <chr>,
# cough <chr>, aches <chr>, vomit <chr>, temp <dbl>, time_admission <chr>,
# bmi <dbl>, days_onset_hosp <dbl>
Nhóm duy nhất
Các nhóm được tạo phản ánh từng tổ hợp giá trị duy nhất dọc theo các cột được sử dụng để nhóm.
Để xem các nhóm và số hàng trong mỗi nhóm, hãy chuyển tiếp dữ liệu được nhóm đến hàm tally()
. Nếu chỉ cần xem các nhóm duy nhất mà không cần số lượng, bạn có thể sử dụng hàm group_keys()
.
Dưới đây là ba giá trị duy nhất trong cột được nhóm là outcome
: “Death”, “Recover”, và NA
. Ta thấy rằng đã có nrow(linelist %>% filter(outcome == "Death"))
tử vong, nrow(linelist %>% filter(outcome == "Recover"))
hồi phục, và nrow(linelist %>% filter(is.na(outcome)))
không có outcome nào được ghi nhận.
%>%
linelist group_by(outcome) %>%
tally()
# A tibble: 3 × 2
outcome n
<chr> <int>
1 Death 2582
2 Recover 1983
3 <NA> 1323
Bạn có thể nhóm nhiều hơn một cột. Dưới đây, bộ dữ liệu được nhóm theo outcome
và gender
, sau đó được đánh số. Lưu ý cách mỗi kết hợp duy nhất của outcome
và gender
được tổ hợp thành nhóm riêng - bao gồm cả các giá trị bị thiếu ở một trong hai cột.
%>%
linelist group_by(outcome, gender) %>%
tally()
# A tibble: 9 × 3
# Groups: outcome [3]
outcome gender n
<chr> <chr> <int>
1 Death f 1227
2 Death m 1228
3 Death <NA> 127
4 Recover f 953
5 Recover m 950
6 Recover <NA> 80
7 <NA> f 627
8 <NA> m 625
9 <NA> <NA> 71
Cột mới
Bạn cũng có thể tạo một cột mới dùng để nhóm trong câu lệnh group_by()
. Điều này tương đương với việc sử dụng hàm mutate()
trước khi sử dụng hàm group_by()
. Để tạo cột nhanh, cách này có thể hữu ích, nhưng để rõ ràng hơn trong code của bạn, hãy cân nhắc cách tạo cột này ở bước mutate()
và sau đó chuyển tiếp đến hàm group_by()
.
# group dat based on a binary column created *within* the group_by() command
%>%
linelist group_by(
age_class = ifelse(age >= 18, "adult", "child")) %>%
tally(sort = T)
# A tibble: 3 × 2
age_class n
<chr> <int>
1 child 3618
2 adult 2184
3 <NA> 86
Thêm/bỏ cột được nhóm
Mặc định, nếu bạn chạy lệnh group_by()
trên dữ liệu đã được nhóm, các nhóm cũ sẽ bị xóa và (các) nhóm mới sẽ được áp dụng. Nếu bạn muốn thêm nhóm mới vào nhóm hiện có, hãy thêm đối số .add = TRUE
.
# Grouped by outcome
<- linelist %>%
by_outcome group_by(outcome)
# Add grouping by gender in addition
<- by_outcome %>%
by_outcome_gender group_by(gender, .add = TRUE)
13.3 Giữ tất cả các nhóm
Nếu bạn nhóm trên một cột dạng factor, có thể có các thứ bậc của factor mà không có trong dữ liệu. Nếu bạn nhóm trên cột này, mặc định, những thứ bậc không có trong dữ liệu đó sẽ bị loại bỏ và không thuộc dạng nhóm. Để thay đổi điều này để tất cả các thứ bậc xuất hiện dưới dạng nhóm (ngay cả khi không có trong dữ liệu), đặt .drop = FALSE
trong lệnh group_by()
.
13.4 Loại bỏ nhóm
Dữ liệu đã được nhóm sẽ vẫn được nhóm cho đến khi hủy nhóm bởi lệnh ungroup()
. Nếu bạn quên hủy nhóm, nó có thể gây ra tính toán không chính xác! Dưới đây là ví dụ về việc loại bỏ tất cả các nhóm:
%>%
linelist group_by(outcome, gender) %>%
tally() %>%
ungroup()
Bạn cũng có thể loại bỏ nhóm với các cột cụ thể, bằng cách đặt tên cột bên trong lệnh ungroup()
.
%>%
linelist group_by(outcome, gender) %>%
tally() %>%
ungroup(gender) # remove the grouping by gender, leave grouping by outcome
GHI CHÚ: Hàm count()
tự động hủy nhóm dữ liệu sau khi đếm.
13.5 Tổng hợp
Xem package dplyr trong chương Bảng mô tả để biết mô tả chi tiết về cách tạo bảng tổng hợp với hàm summarise()
. Ở đây chúng ta giải quyết ngắn gọn cách hoạt động thay đổi khi áp dụng cho dữ liệu được nhóm.
Hàm dplyr summarise()
(hoặc summarize()
) lấy một data frame và chuyển nó thành một data frame tổng hợp mới, với các cột chứa thông tin các giá trị thống kê do bạn xác định. Trên bộ dữ liệu chưa nhóm, các tổng hợp thống kê sẽ được tính toán từ tất cả các hàng. Việc áp dụng hàm summarise()
vào dữ liệu được nhóm sẽ tổng hợp những giá trị thống kê cho từng nhóm.
Cú pháp của hàm summarise()
là bạn cung cấp tên của (các) cột tổng hợp mới, một dấu bằng và sau đó là một hàm thống kê để áp dụng cho dữ liệu, như được trình bày bên dưới. Ví dụ: min()
, max()
, median()
, hoặc sd()
. Trong hàm thống kê, hãy liệt kê cột sẽ được áp dụng và bất kỳ đối số nào có liên quan (ví dụ: na.rm = TRUE
). Bạn có thể sử dụng hàm sum()
để đếm số hàng đáp ứng tiêu chí logic (với dấu bằng kép ==
).
Dưới đây là một ví dụ về hàm summarise()
được áp dụng mà không có dữ liệu được nhóm. Các giá trị thống kê trả về được tạo ra từ toàn bộ bộ dữ liệu.
# summary statistics on ungrouped linelist
%>%
linelist summarise(
n_cases = n(),
mean_age = mean(age_years, na.rm=T),
max_age = max(age_years, na.rm=T),
min_age = min(age_years, na.rm=T),
n_males = sum(gender == "m", na.rm=T))
n_cases mean_age max_age min_age n_males
1 5888 16.01831 84 0 2803
Ngược lại, bên dưới là câu lệnh summarise()
tương tự được áp dụng cho dữ liệu được nhóm. Các số liệu thống kê được tính toán cho từng nhóm kết quả. Lưu ý cách các cột dùng để nhóm sẽ chuyển sang data frame mới.
# summary statistics on grouped linelist
%>%
linelist group_by(outcome) %>%
summarise(
n_cases = n(),
mean_age = mean(age_years, na.rm=T),
max_age = max(age_years, na.rm=T),
min_age = min(age_years, na.rm=T),
n_males = sum(gender == "m", na.rm=T))
# A tibble: 3 × 6
outcome n_cases mean_age max_age min_age n_males
<chr> <int> <dbl> <dbl> <dbl> <int>
1 Death 2582 15.9 76 0 1228
2 Recover 1983 16.1 84 0 950
3 <NA> 1323 16.2 69 0 625
MẸO: Hàm tổng hợp hoạt động với cả cách viết của kiểu Anh và Mỹ - summarise()
và summarize()
đều chỉ định cùng cùng một hàm.
13.6 Counts và tallies
count()
và tally()
đều cung cấp tính năng tương tự nhưng thực chất là khác nhau. Đọc thêm về sự khác biệt giữa tally()
và count()
tại đây.
tally()
tally()
là viết tắt của summarise(n = n())
và không nhóm dữ liệu. Do đó, để có thể kiểm đếm theo nhóm, nó phải theo sau lệnh group_by()
. Bạn có thể thêm sort = TRUE
để xem các nhóm lớn nhất trước tiên.
%>%
linelist tally()
n
1 5888
%>%
linelist group_by(outcome) %>%
tally(sort = TRUE)
# A tibble: 3 × 2
outcome n
<chr> <int>
1 Death 2582
2 Recover 1983
3 <NA> 1323
count()
Ngược lại, hàm count()
hoạt động như sau:
- Áp dụng
group_by()
trên (các) cột đã chỉ định
- Áp dụng
summarise()
và trả về cộtn
với số lượng dòng mỗi nhóm
- Áp dụng
ungroup()
%>%
linelist count(outcome)
outcome n
1 Death 2582
2 Recover 1983
3 <NA> 1323
Cũng giống như với hàm group_by()
, bạn có thể tạo một cột mới trong lệnh count()
:
%>%
linelist count(age_class = ifelse(age >= 18, "adult", "child"), sort = T)
age_class n
1 child 3618
2 adult 2184
3 <NA> 86
count()
có thể được sử dụng nhiều lần, với tính năng “cuộn lên”. Ví dụ: để tổng hợp số lượng bệnh viện hiện có cho mỗi giới tính, hãy chạy lệnh như sau. Lưu ý, tên của cột cuối cùng đã được thay đổi từ tên mặc định là “n” để cho rõ ràng (với name =
).
%>%
linelist # produce counts by unique outcome-gender groups
count(gender, hospital) %>%
# gather rows by gender (3) and count number of hospitals per gender (6)
count(gender, name = "hospitals per gender" )
gender hospitals per gender
1 f 6
2 m 6
3 <NA> 6
Thêm giá trị đếm
Ngược lại với count()
và summarise()
, bạn có thể sử dụng add_count()
để thêm một cột mới n
với số lượng hàng cho mỗi nhóm trong khi vẫn giữ lại tất cả các cột khác trong dữ liệu.
Điều này có nghĩa là số lượng của nhóm, trong cột mới n
, sẽ được in ra trong mỗi hàng của nhóm. Với mục đích minh họa, chúng tôi thêm cột này và sau đó sắp xếp lại các cột để dễ xem hơn. Xem mục bên dưới về bộ lọc theo kích thước nhóm để biết một ví dụ khác.
%>%
linelist as_tibble() %>% # convert to tibble for nicer printing
add_count(hospital) %>% # add column n with counts by hospital
select(hospital, n, everything()) # re-arrange for demo purposes
# A tibble: 5,888 × 31
hospital n case_id generation date_infection date_onset
<chr> <int> <chr> <dbl> <date> <date>
1 Other 885 5fe599 4 2014-05-08 2014-05-13
2 Missing 1469 8689b7 4 NA 2014-05-13
3 St. Mark's Maternity Hosp… 422 11f8ea 2 NA 2014-05-16
4 Port Hospital 1762 b8812a 3 2014-05-04 2014-05-18
5 Military Hospital 896 893f25 3 2014-05-18 2014-05-21
6 Port Hospital 1762 be99c8 3 2014-05-03 2014-05-22
7 Missing 1469 07e3e8 4 2014-05-22 2014-05-27
8 Missing 1469 369449 4 2014-05-28 2014-06-02
9 Missing 1469 f393b4 4 NA 2014-06-05
10 Missing 1469 1389ca 4 NA 2014-06-05
# ℹ 5,878 more rows
# ℹ 25 more variables: date_hospitalisation <date>, date_outcome <date>,
# outcome <chr>, gender <chr>, age <dbl>, age_unit <chr>, age_years <dbl>,
# age_cat <fct>, age_cat5 <fct>, lon <dbl>, lat <dbl>, infector <chr>,
# source <chr>, wt_kg <dbl>, ht_cm <dbl>, ct_blood <dbl>, fever <chr>,
# chills <chr>, cough <chr>, aches <chr>, vomit <chr>, temp <dbl>,
# time_admission <chr>, bmi <dbl>, days_onset_hosp <dbl>
Thêm giá trị tổng
Để dễ dàng thêm tổng các hàng hoặc cột sau khi sử dụng tally()
hoặc count()
, hãy xem mục janitor trong chương Bảng mô tả. Package này cung cấp các hàm như adorn_totals()
và adorn_percentages()
để thêm tổng và chuyển đổi sang hiển thị tỷ lệ phần trăm. Dưới đây là một ví dụ ngắn gọn:
%>% # case linelist
linelist tabyl(age_cat, gender) %>% # cross-tabulate counts of two columns
adorn_totals(where = "row") %>% # add a total row
adorn_percentages(denominator = "col") %>% # convert to proportions with column denominator
adorn_pct_formatting() %>% # convert proportions to percents
adorn_ns(position = "front") %>% # display as: "count (percent)"
adorn_title( # adjust titles
row_name = "Age Category",
col_name = "Gender")
Gender
Age Category f m NA_
0-4 640 (22.8%) 416 (14.8%) 39 (14.0%)
5-9 641 (22.8%) 412 (14.7%) 42 (15.1%)
10-14 518 (18.5%) 383 (13.7%) 40 (14.4%)
15-19 359 (12.8%) 364 (13.0%) 20 (7.2%)
20-29 468 (16.7%) 575 (20.5%) 30 (10.8%)
30-49 179 (6.4%) 557 (19.9%) 18 (6.5%)
50-69 2 (0.1%) 91 (3.2%) 2 (0.7%)
70+ 0 (0.0%) 5 (0.2%) 1 (0.4%)
<NA> 0 (0.0%) 0 (0.0%) 86 (30.9%)
Total 2,807 (100.0%) 2,803 (100.0%) 278 (100.0%)
Để thêm các hàng tổng phức tạp hơn bao gồm các thống kê tổng hợp khác, hãy xem mục sau trong chương Bảng mô tả.
13.7 Nhóm theo ngày
Khi nhóm dữ liệu theo ngày, bạn phải có (hoặc tạo) một cột cho đơn vị ngày quan tâm - ví dụ: “ngày”, “tuần dịch tễ”, “tháng”, v.v. Bạn có thể tạo cột này bằng cách sử dụng floor_date()
từ lubridate, như được giải thích trong phần Tuần dịch tễ học trong chương Làm việc với ngày tháng. Khi bạn có cột này, bạn có thể sử dụng count()
từ dplyr để nhóm các hàng theo các giá trị ngày duy nhất đó và thu về giá trị số lượng tổng hợp.
Một bước bổ sung phổ biến cho các tình huống với ngày/tháng, là “điền vào” bất kỳ ngày nào trong chuỗi ngày không có trong dữ liệu. Sử dụng complete()
từ tidyr để chuỗi ngày tổng hợp được hoàn chỉnh bao gồm tất cả các đơn vị ngày có thể có trong phạm vi. Nếu không có bước này, một tuần không có trường hợp nào được báo cáo có thể không xuất hiện trong dữ liệu của bạn!
Trong complete()
, bạn xác định lại cột ngày của mình dưới dạng một chuỗi ngày seq.Date()
từ giá trị nhỏ nhất đến giá trị lớn nhất - do đó mà ngày/tháng được mở rộng. Mặc định, giá trị số lượng trong bất kỳ hàng “mở rộng” mới nào sẽ là NA
. Bạn có thể đặt chúng thành 0 bằng cách sử dụng argument fill =
của hàm complete()
, trong đó yêu cầu một danh sách được đặt tên (nếu cột số lượng của bạn được đặt tên là n
, hãy thêm fill = list(n = 0)
). Xem ?complete
để biết chi tiết và xem ví dụ trong chương Làm việc với ngày tháng.
Các trường hợp trong linelist
theo ngày
Dưới đây là một ví dụ về nhóm các trường hợp theo ngày mà không sử dụng complete()
. Lưu ý các hàng đầu tiên bỏ qua các ngày mà không có trường hợp nào.
<- linelist %>%
daily_counts drop_na(date_onset) %>% # remove that were missing date_onset
count(date_onset) # count number of rows per unique date
Dưới đây, chúng ta thêm lệnh complete()
để đảm bảo mỗi ngày trong phạm vi đều được hiển thị.
<- linelist %>%
daily_counts drop_na(date_onset) %>% # remove case missing date_onset
count(date_onset) %>% # count number of rows per unique date
complete( # ensure all days appear even if no cases
date_onset = seq.Date( # re-define date colume as daily sequence of dates
from = min(date_onset, na.rm=T),
to = max(date_onset, na.rm=T),
by = "day"),
fill = list(n = 0)) # set new filled-in rows to display 0 in column n (not NA as default)
Các trường hợp trong linelist
theo tuần
Nguyên tắc tương tự có thể được áp dụng cho tuần. Đầu tiên, hãy tạo một cột mới các trường hợp theo tuần bằng cách sử dụng floor_date()
với unit = "week"
. Sau đó, sử dụng count()
như trên để đạt được số lượng ca hàng tuần. Kết thúc bằng hàm complete()
để đảm bảo rằng tất cả các tuần đều được hiển thị, ngay cả khi chúng không chứa ca nào.
# Make dataset of weekly case counts
<- linelist %>%
weekly_counts drop_na(date_onset) %>% # remove cases missing date_onset
mutate(week = lubridate::floor_date(date_onset, unit = "week")) %>% # new column of week of onset
count(week) %>% # group data by week and count rows per group
complete( # ensure all days appear even if no cases
week = seq.Date( # re-define date colume as daily sequence of dates
from = min(week, na.rm=T),
to = max(week, na.rm=T),
by = "week"),
fill = list(n = 0)) # set new filled-in rows to display 0 in column n (not NA as default)
Đây là 50 hàng đầu tiên của bộ dữ liệu khi trả kết quả:
Các trường hợp trong linelist
theo tháng
Để tổng hợp các trường hợp theo tháng, hãy sử dụng lại floor_date()
từ package lubridate, nhưng với argument unit = "months"
. Điều này làm tròn xuống các ngày thành ngày đầu tiên của tháng. Đầu ra sẽ là định dạng ngày. Lưu ý rằng trong bước complete()
, chúng ta cũng sử dụng by = "months"
.
# Make dataset of monthly case counts
<- linelist %>%
monthly_counts drop_na(date_onset) %>%
mutate(month = lubridate::floor_date(date_onset, unit = "months")) %>% # new column, 1st of month of onset
count(month) %>% # count cases by month
complete(
month = seq.Date(
min(month, na.rm=T), # include all months with no cases reported
max(month, na.rm=T),
by="month"),
fill = list(n = 0))
Số lượng đếm hàng ngày theo tuần
Để tổng hợp số lượng hàng ngày thành số lượng hàng tuần, hãy sử dụng floor_date()
như trên. Tuy nhiên, hãy sử dụng group_by()
và summarize()
thay vì count()
bởi vì chúng ta cần tính tổng sum()
số lượng trường hợp hàng ngày thay vì chỉ đếm số hàng mỗi tuần.
Số lượng đếm hàng ngày theo tuần
Để tổng hợp số lượng hàng ngày thành số lượng hàng tháng, hãy sử dụng floor_date()
với unit = "month"
như trên. Tuy nhiên, hãy sử dụng group_by()
và summarize()
thay vì count()
bởi vì chúng ta cần tính tổng sum()
số lượng trường hợp hàng ngày thay vì chỉ đếm số hàng mỗi tháng.
13.8 Sắp xếp dữ liệu đã nhóm
Sử dụng hàm dplyr arrange()
để sắp xếp các hàng trong bộ dữ liệu tương tự khi dữ liệu được nhóm lại, trừ khi bạn thiết lập đối số .by_group =TRUE
. Trong trường hợp này, các hàng được sắp xếp thứ tự đầu tiên theo các cột nhóm và sau đó theo bất kỳ cột nào khác mà bạn chỉ định để arrange()
.
13.9 Lọc trên nhóm dữ liệu đã nhóm
filter()
Khi được áp dụng cùng với các hàm đánh giá bộ dữ liệu (như max()
, min()
, mean()
), các hàm này sẽ được áp dụng cho các nhóm. Ví dụ: nếu bạn muốn lọc và giữ các hàng có bệnh nhân trên độ tuổi trung vị, hàm này sẽ áp dụng cho mỗi nhóm - lọc để giữ các hàng trên độ tuổi trung bình của nhóm.
Cắt hàng theo nhóm
Hàm dplyr slice()
, mà lọc hàng dựa trên vị trí trong dữ liệu, cũng có thể được áp dụng cho mỗi nhóm. Hãy nhớ sắp xếp dữ liệu trong mỗi nhóm để có được “lát cắt” mong muốn.
Ví dụ: chỉ lấy 5 lần nhập viện gần nhất từ mỗi bệnh viện:
- Nhóm bộ số liệu
linelist
theo cộthospital
- Sắp xếp bản ghi từ gần nhất đến xa nhất theo
date_hospitalisation
trong mỗi nhóm bệnh viện
- Cắt để lấy 5 hàng đầu tiên từ mỗi bệnh viện
%>%
linelist group_by(hospital) %>%
arrange(hospital, date_hospitalisation) %>%
slice_head(n = 5) %>%
arrange(hospital) %>% # for display
select(case_id, hospital, date_hospitalisation) # for display
# A tibble: 30 × 3
# Groups: hospital [6]
case_id hospital date_hospitalisation
<chr> <chr> <date>
1 20b688 Central Hospital 2014-05-06
2 d58402 Central Hospital 2014-05-10
3 b8f2fd Central Hospital 2014-05-13
4 acf422 Central Hospital 2014-05-28
5 275cc7 Central Hospital 2014-05-28
6 d1fafd Military Hospital 2014-04-17
7 974bc1 Military Hospital 2014-05-13
8 6a9004 Military Hospital 2014-05-13
9 09e386 Military Hospital 2014-05-14
10 865581 Military Hospital 2014-05-15
# ℹ 20 more rows
slice_head()
- chọn n hàng từ trên xuống dưới
slice_tail()
- chọn n hàng từ dưới lên trên
slice_sample()
- chọn ngẫu nhiên n dòng
slice_min()
- chọn n dòng với giá trị cao nhất trong cột order_by =
, sử dụng with_ties = TRUE
để giữ mối liên hệ
slice_max()
- chọn n dòng với giá trị thấp nhất trong cột order_by =
,sử dụng with_ties = TRUE
để giữ mối liên hệ
Xem chương Loại bỏ trùng lặp để tham khảo thêm ví dụ và chi tiết về hàm slice()
.
Lọc theo quy mô nhóm
Hàm add_count()
thêm một cột n
vào dữ liệu gốc cho biết số hàng trong nhóm của hàng đó.
Như trình bày bên dưới, add_count()
được áp dụng cho cột hospital
, vì vậy các giá trị trong cột mới n
phản ánh số hàng trong nhóm bệnh viện của hàng đó. Lưu ý cách các giá trị trong cột n
được lặp lại. Trong ví dụ dưới đây, tên cột n
có thể được thay đổi bằng cách sử dụng đối số name =
trong add_count()
. Với mục đích diễn giải, chúng ta sắp xếp lại các cột với select()
.
%>%
linelist as_tibble() %>%
add_count(hospital) %>% # add "number of rows admitted to same hospital as this row"
select(hospital, n, everything())
# A tibble: 5,888 × 31
hospital n case_id generation date_infection date_onset
<chr> <int> <chr> <dbl> <date> <date>
1 Other 885 5fe599 4 2014-05-08 2014-05-13
2 Missing 1469 8689b7 4 NA 2014-05-13
3 St. Mark's Maternity Hosp… 422 11f8ea 2 NA 2014-05-16
4 Port Hospital 1762 b8812a 3 2014-05-04 2014-05-18
5 Military Hospital 896 893f25 3 2014-05-18 2014-05-21
6 Port Hospital 1762 be99c8 3 2014-05-03 2014-05-22
7 Missing 1469 07e3e8 4 2014-05-22 2014-05-27
8 Missing 1469 369449 4 2014-05-28 2014-06-02
9 Missing 1469 f393b4 4 NA 2014-06-05
10 Missing 1469 1389ca 4 NA 2014-06-05
# ℹ 5,878 more rows
# ℹ 25 more variables: date_hospitalisation <date>, date_outcome <date>,
# outcome <chr>, gender <chr>, age <dbl>, age_unit <chr>, age_years <dbl>,
# age_cat <fct>, age_cat5 <fct>, lon <dbl>, lat <dbl>, infector <chr>,
# source <chr>, wt_kg <dbl>, ht_cm <dbl>, ct_blood <dbl>, fever <chr>,
# chills <chr>, cough <chr>, aches <chr>, vomit <chr>, temp <dbl>,
# time_admission <chr>, bmi <dbl>, days_onset_hosp <dbl>
Sau đó, nó trở nên dễ dàng để lọc các hàng trường hợp nhập viện tại một bệnh viện “nhỏ”, chẳng hạn như một bệnh viện tiếp nhận ít hơn 500 bệnh nhân:
%>%
linelist add_count(hospital) %>%
filter(n < 500)
13.10 Tạo cột mới trên dữ liệu được nhóm
Để giữ lại tất cả các cột và hàng (không tổng hợp) và thêm một cột mới chứa thống kê theo nhóm, hãy sử dụng hàm mutate()
sau group_by()
thay vì summarise()
.
Điều này hữu ích nếu bạn muốn nhóm thống kê trong bộ dữ liệu gốc với tất cả các cột khác được hiển thị - ví dụ: cho các phép tính so sánh một hàng với nhóm của nó.
Ví dụ: code dưới đây tính toán sự khác biệt giữa thời gian trễ nhập viện của một hàng và thời gian chậm trễ trung vị đối với bệnh viện đó. Các bước lần lượt là:
- Nhóm dữ liệu theo bệnh viện
- Sử dụng cột
days_onset_hosp
(nhập viện trễ) để tạo một cột mới chứa giá trị trễ trung bình tại bệnh viện của hàng đó
- Tính toán sự khác biệt giữa hai cột
Chúng ta chỉ lựa chọn select()
những cột cần hiển thị, cho mục đích diễn giải.
%>%
linelist # group data by hospital (no change to linelist yet)
group_by(hospital) %>%
# new columns
mutate(
# mean days to admission per hospital (rounded to 1 decimal)
group_delay_admit = round(mean(days_onset_hosp, na.rm=T), 1),
# difference between row's delay and mean delay at their hospital (rounded to 1 decimal)
diff_to_group = round(days_onset_hosp - group_delay_admit, 1)) %>%
# select certain rows only - for demonstration/viewing purposes
select(case_id, hospital, days_onset_hosp, group_delay_admit, diff_to_group)
# A tibble: 5,888 × 5
# Groups: hospital [6]
case_id hospital days_onset_hosp group_delay_admit diff_to_group
<chr> <chr> <dbl> <dbl> <dbl>
1 5fe599 Other 2 2 0
2 8689b7 Missing 1 2.1 -1.1
3 11f8ea St. Mark's Maternity… 2 2.1 -0.1
4 b8812a Port Hospital 2 2.1 -0.1
5 893f25 Military Hospital 1 2.1 -1.1
6 be99c8 Port Hospital 1 2.1 -1.1
7 07e3e8 Missing 2 2.1 -0.1
8 369449 Missing 1 2.1 -1.1
9 f393b4 Missing 1 2.1 -1.1
10 1389ca Missing 2 2.1 -0.1
# ℹ 5,878 more rows
13.11 Chọn trên dữ liệu được nhóm
Hàm select()
hoạt động trên dữ liệu được nhóm, nhưng các cột được nhóm luôn được bao gồm (ngay cả khi không được đề cập trong select()
). Nếu bạn không muốn nhóm các cột này, trước tiên hãy bỏ nhóm bằng hàm ungroup()
.
13.12 Tài nguyên học liệu
Dưới đây là một số tài nguyên hữu ích cung cấp thêm thông tin:
Bạn có thể thực hiện bất kỳ hàm tổng hợp nào trên dữ liệu được nhóm; xem RStudio cheat sheet về biến đổi dữ liệu
Trang Data Carpentry của dplyr
Chương tham khảo hệ sinh thái tidyverse về group_by() và grouping
Trang này về Thao tác dữ liệu