2015-12-09 19 views
8

Tôi đang cố gắng kết hợp một hàm tạo tập hợp con từ khung dữ liệu ban đầu của tôi và sau đó sử dụng lệnh SELECT và MUTATE của dplyr để cung cấp cho tôi số lượng mục nhập lớn/nhỏ, dựa trên tổng chiều rộng và chiều dài của các cánh/cánh hoa.Lỗi khi sử dụng dplyr bên trong của hàm

filter <- function (spp, LENGTH, WIDTH) { 
    d <- subset (iris, subset=iris$Species == spp) # This part seems to work just fine 
    large <- d %>%      
    select (LENGTH, WIDTH) %>% # This is where the problem arises. 
    mutate (sum = LENGTH + WIDTH) 
    big_samples <- which(large$sum > 4) 
return (length(big_samples)) 
} 

Về cơ bản, tôi muốn hàm trả về số lượng hoa lớn. Tuy nhiên, khi tôi chạy hàm tôi nhận được lỗi sau -

filter("virginica", "Sepal.Length", "Sepal.Width") 

Error: All select() inputs must resolve to integer column positions. 
The following do not: 
* LENGTH 
* WIDTH 

Tôi đang làm gì sai?

+3

chức năng 'dplyr' sử dụng đánh giá không chuẩn. Đó là lý do tại sao bạn không phải trích dẫn tên biến của bạn khi bạn làm một cái gì đó như 'select (mtcars, mpg)', và tại sao 'select (mtcars," mpg ")' không hoạt động. Khi bạn sử dụng 'dplyr' trong các hàm, bạn có thể sẽ muốn sử dụng" đánh giá tiêu chuẩn ". Xem 'họa tiết (" nse ")' để biết thêm chi tiết. – ialm

+0

nhưng tại sao lại là chức năng? – MLavoie

+2

Giải pháp nhanh chóng và bẩn là thay đổi 'select (LENGTH, WIDTH)%>%' thành 'select (get (LENGTH), nhận (WIDTH))%>%'. Tuy nhiên, bạn thực sự nên sử dụng 'select _()' và 'mutate _()' trong các hàm của bạn. – ialm

Trả lời

15

Bạn đang gặp sự cố NSE/SE, xem the vignette for more info.

Tóm tắt, dplyr sử dụng đánh giá không chuẩn (NSE) tên và chuyển tên cột thành chức năng, không sử dụng phiên bản đánh giá chuẩn (SE).

Phiên bản SE của các hàm dplyr kết thúc bằng _. Bạn có thể thấy rằng select_ hoạt động độc đáo với các đối số ban đầu của bạn.

Tuy nhiên, mọi thứ trở nên phức tạp hơn khi sử dụng chức năng. Chúng ta có thể sử dụng lazyeval::interp để chuyển đổi hầu hết các đối số hàm thành tên cột, xem việc chuyển đổi của mutate-mutate_ cuộc gọi trong chức năng của bạn dưới đây và tổng quát hơn, sự giúp đỡ: ?lazyeval::interp

Hãy thử:

filter <- function (spp, LENGTH, WIDTH) { 
    d <- subset (iris, subset=iris$Species == spp) 
    large <- d %>%      
     select_(LENGTH, WIDTH) %>% 
     mutate_(sum = lazyeval::interp(~X + Y, X = as.name(LENGTH), Y = as.name(WIDTH))) 
    big_samples <- which(large$sum > 4) 
    return (length(big_samples)) 
} 
+0

Đây là một giải pháp tuyệt vời cho vấn đề này. Chỉ vì tò mò, liệu có ai có một chức năng dễ dàng hơn hoặc đơn giản hơn có thể được sử dụng để đạt được kết quả tương tự không? – ari8888

+1

đây là những gì tôi sẽ làm: 'myfun <- function (loài, col1, col2) { tổng (iris $ Species == loài & (iris [[col1]] + iris [[col2]])> 4) } ' – jeremycg

6

CẬP NHẬT : Theo dplyr 0.7.0 bạn có thể sử dụng eval gọn gàng để thực hiện việc này.

Xem http://dplyr.tidyverse.org/articles/programming.html để biết thêm chi tiết.

filter_big <- function(spp, LENGTH, WIDTH) { 
    LENGTH <- enquo(LENGTH)     # Create quosure 
    WIDTH <- enquo(WIDTH)      # Create quosure 

    iris %>% 
    filter(Species == spp) %>% 
    select(!!LENGTH, !!WIDTH) %>%   # Use !! to unquote the quosure 
    mutate(sum = (!!LENGTH) + (!!WIDTH)) %>% # Use !! to unquote the quosure 
    filter(sum > 4) %>% 
    nrow() 
} 

filter_big("virginica", Sepal.Length, Sepal.Width) 

> filter_big("virginica", Sepal.Length, Sepal.Width) 
[1] 50 
Các vấn đề liên quan