Khóa học
Gần như mọi dự án phân tích dữ liệu với R đều liên quan đến việc trích xuất các hàng, cột hoặc giá trị cụ thể từ một tập dữ liệu lớn hơn. Subsetting là cách bạn làm điều đó trong R, dùng ký pháp dấu ngoặc [] để kiểm soát chỉ mục cấp thấp, hàm subset() để lọc theo điều kiện một cách dễ đọc, hoặc các động từ của dplyr như filter() và select() cho các pipeline dữ liệu hiện đại.
TL;DR
-
Dùng ký pháp dấu ngoặc
df[rows, cols]để subset hàng và cột theo vị trí -
Dùng
$để trích một cột dưới dạng vector:df$column_name -
Dùng
subset(df, condition)để lọc theo điều kiện dễ đọc trong các phiên tương tác -
Thêm
drop = FALSEkhi chọn một cột duy nhất để giữ kết quả ở dạng data frame -
Với mã sản xuất và pipeline dữ liệu, ưu tiên ký pháp dấu ngoặc hoặc
dplyr::filter()thay vìsubset()
Chọn hàng
Dưới đây là ví dụ về subsetting trên một data frame tên là debt.
debt[3:6, ]
name payment
3 Dan 150
4 Rob 50
5 Rob 75
6 Rob 100
Cú pháp df[rows, columns] là nền tảng của subsetting trong R. Ở đây, 3:6 chọn các hàng 3 đến 6, và phần trống sau dấu phẩy nghĩa là "trả về tất cả các cột". Kết quả là một data frame nhỏ hơn với cấu trúc cột giống bản gốc.
Chọn hàng từ một cột cụ thể
Một hành vi cần lưu ý là việc đơn giản hóa xảy ra khi bạn chọn một cột duy nhất. Chọn ba hàng đầu tiên chỉ của cột payment sẽ đơn giản hóa kết quả thành một vector.
debt[1:3, 2]
100 200 150
Số 2 ở đây ám chỉ cột thứ hai của debt, tức payment. Vì ta chọn một cột duy nhất, R loại bỏ cấu trúc data frame và trả về một vector số đơn thuần.
Định dạng dataframe
Để giữ nguyên dưới dạng dataframe, chỉ cần thêm drop = FALSE như dưới đây:
debt[1:3, 2, drop = FALSE]
payment
1 100
2 200
3 150
Chọn một cột cụ thể
Bạn cũng có thể chọn một cột bằng toán tử $ với cú pháp dataframe$column. Ví dụ sau trích xuất cột payment từ debt. R trả kết quả dưới dạng vector thay vì data frame.
debt$payment
100 200 150 50 75 100
Sử dụng hàm subset()
Khi cần tạo các subset phức tạp hơn hoặc subset dựa trên điều kiện, bước tiếp theo là dùng hàm subset(). Ví dụ, nếu bạn muốn xem các khoản nợ của người tên Dan. Bạn có thể dùng dấu ngoặc để chọn các khoản nợ của họ và cộng lại, nhưng đó không phải là cách làm vững chắc, đặc biệt khi tập dữ liệu có thể thay đổi.
# Cách này hoạt động, nhưng không cung cấp nhiều thông tin
debt[1:3, ]
subset() trên biến phân loại
Một cách tốt hơn là dùng hàm subset() để chọn các hàng mà cột name bằng Dan. Lưu ý cần dùng dấu bằng kép (==), gọi là toán tử quan hệ.
# Hoạt động, nhưng không nhiều thông tin và không vững chắc
debt[1:3, ]
# Cung cấp thông tin rõ ràng hơn nhiều!
subset(debt, name == "Dan")
name payment
1 Dan 100
2 Dan 200
3 Dan 150
Kết quả chỉ chứa ba hàng nơi name bằng "Dan". Lưu ý rằng số thứ tự hàng gốc (1, 2, 3) được giữ nguyên, giúp bạn lần ngược kết quả về data frame nguồn.
subset() trên biến số
Ta cũng có thể subset theo các cột số. Nếu muốn xem các hàng có khoản thanh toán bằng $100, bạn làm như sau:
subset(debt, payment == 100)
name payment
1 Dan 100
6 Rob 100
Hai hàng khớp điều kiện: hàng 1 (Dan) và hàng 6 (Rob) đều có khoản thanh toán đúng bằng $100. Điều này cho thấy subset() quét mọi hàng bất kể tên là gì, trả về tất cả bản ghi phù hợp.
Truy cập và subset các dataframe
Nếu bạn chỉ cần các dòng tiền từ công ty A thì sao? Ở đây, hàm subset() lọc các hàng từ một data frame khác, cash:
subset(cash, company == "A")
company cash_flow year
1 A 1000 1
2 A 4000 3
3 A 550 4
Hãy nhớ:
-
Đối số đầu tiên bạn truyền vào
subset()là tên dataframe của bạn,cash. -
Lưu ý rằng bạn không nên đặt
companytrong dấu ngoặc kép! -
==là toán tử bằng. Nó kiểm tra nơi hai giá trị bằng nhau và trả về một vector logic.
Ví dụ tương tác về phương thức subset()
Trong ví dụ sau, chúng ta dùng subset() để chọn các hàng của cash tương ứng với công ty B, rồi lọc các dòng tiền đáo hạn trong 1 năm.
# Các hàng về công ty B
subset(cash, company == "B")
# Các hàng có dòng tiền đáo hạn trong 1 năm
subset(cash, year == 1)
Khi chạy đoạn mã trên, bạn sẽ nhận được kết quả sau:
company cash_flow year
4 B 1500 1
5 B 1100 2
6 B 750 4
7 B 6000 5
company cash_flow year
1 A 1000 1
4 B 1500 1
Tự mình thử trong khóa Introduction to R for Finance của chúng tôi.
Nội dung này được trích từ khóa học Introduction to R for Finance của DataCamp do Lore Dirick biên soạn.
Subsetting với dplyr
Gói tidyverse là dplyr cung cấp một lựa chọn hiện đại để subset data frame. Hàm filter() chọn hàng và select() chọn cột, cả hai dùng cú pháp pipe để xâu chuỗi các thao tác.
library(dplyr)
# Lọc các hàng có name là "Dan"
debt %>% filter(name == "Dan")
# Chỉ chọn cột payment (giữ ở dạng data frame)
debt %>% select(payment)
# Kết hợp: lọc hàng và chọn cột trong một pipeline
debt %>%
filter(payment >= 100) %>%
select(name, payment)
Không giống subset(), các hàm dplyr hoạt động ổn định bên trong các hàm khác và xử lý nhóm, join, và tổng hợp trong cùng một pipeline. Nếu bạn xây dựng quy trình phân tích dữ liệu thay vì chạy các truy vấn đơn lẻ, dplyr là công cụ tiêu chuẩn.
So sánh các phương pháp subsetting
Hãy so sánh các phương pháp subsetting khác nhau trong R bằng bảng sau:
| Phương pháp | Cú pháp | Phù hợp nhất cho | Lưu ý |
|---|---|---|---|
Dấu ngoặc [] |
df[rows, cols] |
Kiểm soát cấp thấp, lập trình | Hoạt động trên mọi đối tượng R |
$ |
df$col |
Trích nhanh một cột | Trả về vector, không phải data frame |
subset() |
subset(df, cond) |
Lọc tương tác | Không khuyến nghị dùng bên trong hàm |
dplyr::filter() |
df %>% filter(cond) |
Pipeline dữ liệu, mã dễ đọc | Yêu cầu gói dplyr |
Kết luận
R cung cấp cho bạn nhiều cách để subset dữ liệu: ký pháp dấu ngoặc [] cho quyền kiểm soát đầy đủ, subset() cho lọc tương tác dễ đọc, và dplyr::filter() cho các pipeline dữ liệu. Dấu ngoặc hoạt động trên mọi đối tượng R, subset() dễ đọc khi khám phá đơn lẻ, và dplyr mở rộng tốt khi bạn xâu chuỗi nhiều thao tác.
Để tìm hiểu sâu hơn về thao tác dữ liệu trong R, tôi khuyến nghị khóa Data Manipulation with dplyr hoặc khóa Introduction to the Tidyverse trên DataCamp.
Câu hỏi thường gặp về Subset trong R
Sự khác biệt giữa subset() và dplyr::filter() trong R là gì?
Cả hai hàm đều lọc hàng dựa trên điều kiện, nhưng hành vi khác nhau trong ngữ cảnh lập trình. subset() dùng đánh giá không chuẩn (non-standard evaluation), thuận tiện cho tương tác nhưng không đáng tin cậy bên trong các hàm do người dùng định nghĩa. dplyr::filter() được thiết kế để hoạt động an toàn trong hàm và tích hợp với toán tử pipe (%>%) để xâu chuỗi nhiều bước xử lý dữ liệu.
Làm thế nào để subset nhiều cột cùng lúc trong R?
Bạn có thể truyền một vector tên cột hoặc chỉ số cột vào bên trong dấu ngoặc. Ví dụ, df[, c("name", "payment")] chọn hai cột theo tên, trong khi df[, c(1, 3)] chọn theo vị trí. Với dplyr, bạn có thể dùng select(df, name, payment) hoặc các hàm hỗ trợ như starts_with() và contains() để khớp cột theo mẫu.
Vì sao chọn một cột duy nhất trong R trả về vector thay vì data frame?
Mặc định R sẽ đơn giản hóa kết quả khi chỉ chọn một cột bằng ký pháp dấu ngoặc. Hành vi này được điều khiển bởi tham số drop, mặc định là TRUE. Để giữ kết quả là data frame, hãy thêm drop = FALSE vào biểu thức dấu ngoặc của bạn, ví dụ, df[, 2, drop = FALSE].
Tôi có thể subset hàng dựa trên nhiều điều kiện trong R không?
Có. Bạn có thể kết hợp các điều kiện bằng toán tử & (VÀ) và | (HOẶC). Ví dụ, subset(df, name == "Dan" & payment > 100) trả về các hàng có tên là Dan và khoản thanh toán lớn hơn 100. Với dplyr, bạn có thể tách các điều kiện bằng dấu phẩy trong filter(): df %>% filter(name == "Dan", payment > 100).