2014-10-21 16 views
26

Tôi muốn lấy một số dữ liệu từ máy chủ sql với bộ lọc động. Tôi đang sử dụng dplyr gói R lớn theo cách sau:Đánh giá không chuẩn (NSE) trong bộ lọc của dplyr và kéo dữ liệu từ MySQL

#Create the filter 
filter_criteria = ~ column1 %in% some_vector 
#Connect to the database 
connection <- src_mysql(dbname <- "mydbname", 
      user <- "myusername", 
      password <- "mypwd", 
      host <- "myhost") 
#Get data 
data <- connection %>% 
tbl("mytable") %>% #Specify which table 
filter_(.dots = filter_criteria) %>% #non standard evaluation filter 
collect() #Pull data 

Đoạn mã này hoạt động tốt nhưng bây giờ tôi muốn để lặp nó bằng cách nào đó trên tất cả các cột của bảng của tôi, vì vậy tôi muốn để viết bộ lọc dưới dạng:

#Dynamic filter 
i <- 2 #With a loop on this i for instance 
which_column <- paste0("column",i) 
filter_criteria <- ~ which_column %in% some_vector 

Và sau đó áp dụng lại mã đầu tiên với bộ lọc được cập nhật.

Rất tiếc, cách tiếp cận này không đưa ra kết quả mong đợi. Trong thực tế nó không đưa ra bất kỳ lỗi nào nhưng thậm chí không kéo bất kỳ kết quả nào vào R. Cụ thể, tôi đã xem xét một chút vào truy vấn SQL được tạo ra bởi hai đoạn mã và có một khác biệt quan trọng.

Trong khi người đầu tiên, làm việc, mã tạo ra một truy vấn có dạng:

SELECT ... FROM ... WHERE 
`column1` IN .... 

('đăng nhập tên cột), điều thứ hai sẽ tạo ra một truy vấn có dạng:

SELECT ... FROM ... WHERE 
'column1' IN .... 

('đăng nhập vào tên cột)

Có ai có bất kỳ gợi ý nào về cách xây dựng điều kiện lọc để làm cho nó hoạt động không?

Trả lời

40

Nó không thực sự liên quan đến SQL. Ví dụ trong R này không làm việc một trong hai:

df <- data.frame(
    v1 = sample(5, 10, replace = TRUE), 
    v2 = sample(5,10, replace = TRUE) 
) 
df %>% filter_(~ "v1" == 1) 

Nó không làm việc bởi vì bạn cần phải vượt qua để filter_ biểu thức ~ v1 == 1 - không phải là biểu hiện ~ "v1" == 1.

phiên bản dplyr> = 0,6

Để giải quyết vấn đề, chỉ cần sử dụng toán tử trích dẫn quo và các nhà điều hành dequoting !!

library(dplyr) 
which_column = quot(v1) 
df %>% filter(!!which_column == 1) 

phiên bản dplyr < 0,6

Để giải quyết vấn đề, sử dụng hàm interp từ gói lazyeval.

library(lazyeval) 
filter_criteria <- interp(~ which_column == 1, which_column = as.name("v1")) 
df %>% filter_(filter_criteria) 
+0

Hey Matthew, cảm ơn bạn rất nhiều vì câu trả lời của bạn. Phương pháp đầu tiên bạn đề xuất giải quyết vấn đề của tôi, cảm ơn bạn !! Tôi đã đọc các họa tiết nse và đi rất gần với giải pháp này bản thân mình, nhưng tôi quên cuộc gọi as.name/as.symbol. Phương pháp thứ hai bạn đề nghị là không khả thi trong mã tôi đang viết vì không có dataframe trong R được nêu ra, bộ lọc phải hoạt động như WHERE clasue trong truy vấn sql được tạo ra và sau đó kéo dữ liệu. Đó là lý do tại sao tôi bao gồm các đề cập đến SQL trong tiêu đề và trong văn bản của câu hỏi. Cảm ơn bạn một lần nữa cho câu trả lời của bạn! –

+0

Rất vui được! – Matthew

+0

Bạn có thể giải thích những gì có thể được thực hiện nếu 1 cũng là một biến khác? một cái gì đó như filter_criteria <- interp (~ which_column == val123, which_column = as.name ("v1"), val123 = ???) Đây val123 là một số nguyên – qwerty123

3

Dưới đây là một giải pháp nhẹ ít tiết và một trong đó sử dụng các hành vi điển hình của các chức năng giải nén, '[' trong việc lựa chọn một cột theo giá trị nhân vật chứ không phải là chuyển đổi nó vào một yếu tố ngôn ngữ:

df %>% filter(., '['(., which_column)==1) 

set.seed(123) 
df <- data.frame(
     v1 = sample(5, 10, replace = TRUE), 
     v2 = sample(5,10, replace = TRUE) 
) 
which_column <- "v1" 
df %>% filter(., '['(., which_column)==1) 
# v1 v2 
#1 1 5 
+0

điều này cũng hoạt động: 'bộ lọc (df, '[' (df, which_column) == 1)' – biocyberman

4

Một giải pháp thay thế, với dplyr phiên bản 0.5.0 (có thể thực hiện sớm hơn đó), nó có thể vượt qua một chuỗi gồm như là đối số .dots, mà tôi tìm thấy dễ đọc hơn so với giải pháp lazyeval :: interp:

df <- data.frame(
    v1 = sample(5, 10, replace = TRUE), 
    v2 = sample(5,10, replace = TRUE) 
) 

which_col <- "v1" 
which_val <- 1 
df %>% filter_(.dots= paste0(which_col, "== ", which_val)) 

    v1 v2 
1 1 1 
2 1 2 
3 1 4 

CẬP NHẬT cho dplyr 0.6:

packageVersion("dplyr") 
# [1] ‘0.5.0.9004’ 

df %>% filter(UQ(rlang::sym(which_col))==which_val) 
#OR 
df %>% filter((!!rlang::sym(which_col))==which_val) 

(. Tương tự như phản ứng @Matthew 's cho dplyr 0.6, nhưng tôi giả định which_col đó là một biến string)

Các vấn đề liên quan