Câu trả lời này sẽ bao gồm nhiều yếu tố giống như câu trả lời hiện có, nhưng vấn đề này (chuyển tên cột cho các hàm) xuất hiện thường xuyên đến mức tôi muốn có một câu trả lời bao quát mọi thứ một cách toàn diện hơn.
Giả sử chúng ta có một khung dữ liệu rất đơn giản:
dat <- data.frame(x = 1:4,
y = 5:8)
và chúng tôi muốn viết một hàm tạo một cột mới z
là tổng của các cột x
và y
.
Một vấp ngã rất phổ biến ở đây là một nỗ lực tự nhiên (nhưng không chính xác) thường trông như thế này:
foo <- function(df,col_name,col1,col2){
df$col_name <- df$col1 + df$col2
df
}
#Call foo() like this:
foo(dat,z,x,y)
Vấn đề ở đây là df$col1
không đánh giá biểu thức col1
. Nó chỉ đơn giản là tìm kiếm một cột theo df
nghĩa đen được gọi col1
. Hành vi này được mô tả trong ?Extract
phần "Đối tượng đệ quy (giống như danh sách)".
Giải pháp đơn giản nhất và thường được đề xuất nhất chỉ đơn giản là chuyển từ $
sang [[
và truyền các đối số hàm dưới dạng chuỗi:
new_column1 <- function(df,col_name,col1,col2){
#Create new column col_name as sum of col1 and col2
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column1(dat,"z","x","y")
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
Đây thường được coi là "thực hành tốt nhất" vì đây là phương pháp khó thực hiện nhất. Truyền tên cột dưới dạng chuỗi là không rõ ràng như bạn có thể nhận được.
Hai tùy chọn sau đây tiên tiến hơn. Nhiều gói phổ biến sử dụng các loại kỹ thuật này, nhưng sử dụng chúng tốt đòi hỏi nhiều kỹ năng và kỹ năng hơn, vì chúng có thể giới thiệu sự phức tạp tinh tế và các điểm thất bại không lường trước được. Đây phần của cuốn sách nâng cao R Hadley là một tài liệu tham khảo tuyệt vời cho một số trong những vấn đề này.
Nếu bạn thực sự muốn lưu người dùng nhập tất cả các trích dẫn đó, một tùy chọn có thể là chuyển đổi tên cột trống, không trích dẫn thành chuỗi bằng cách sử dụng deparse(substitute())
:
new_column2 <- function(df,col_name,col1,col2){
col_name <- deparse(substitute(col_name))
col1 <- deparse(substitute(col1))
col2 <- deparse(substitute(col2))
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column2(dat,z,x,y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
Thật ra, điều này có vẻ hơi ngớ ngẩn, vì chúng ta thực sự đang làm điều tương tự như trong new_column1
, chỉ với một loạt các công việc phụ để chuyển đổi tên trần thành chuỗi.
Cuối cùng, nếu chúng ta muốn thực sự ưa thích, chúng ta có thể quyết định thay vì nhập tên của hai cột để thêm, chúng ta muốn linh hoạt hơn và cho phép kết hợp hai biến khác. Trong trường hợp đó, chúng tôi có thể sử dụng eval()
một biểu thức liên quan đến hai cột:
new_column3 <- function(df,col_name,expr){
col_name <- deparse(substitute(col_name))
df[[col_name]] <- eval(substitute(expr),df,parent.frame())
df
}
Để cho vui, tôi vẫn đang sử dụng deparse(substitute())
tên của cột mới. Ở đây, tất cả những điều sau đây sẽ hoạt động:
> new_column3(dat,z,x+y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
> new_column3(dat,z,x-y)
x y z
1 1 5 -4
2 2 6 -4
3 3 7 -4
4 4 8 -4
> new_column3(dat,z,x*y)
x y z
1 1 5 5
2 2 6 12
3 3 7 21
4 4 8 32
Vì vậy, câu trả lời ngắn về cơ bản là: truyền tên cột data.frame dưới dạng chuỗi và sử dụng [[
để chọn các cột đơn. Chỉ bắt đầu đi sâu vào eval
, substitute
vv nếu bạn thực sự biết những gì bạn đang làm.