2017-12-18 100 views
7

tôi có các thiết lập sau dữ liệu (mẫu):Làm thế nào để lặp qua một chức năng eval gọn gàng bằng cách sử dụng purrr?

train <- data.frame(ps_ind_06_bin = c(FALSE, FALSE, FALSE, TRUE, TRUE, FALSE), 
         ps_ind_07_bin = c(FALSE, TRUE, TRUE, FALSE, TRUE, TRUE), 
         ps_ind_08_bin = c(TRUE, TRUE, TRUE, FALSE, TRUE, FALSE), 
         ps_ind_09_log = c(1, 3, 4, 2, 3, 2)) 

tôi có chức năng sau đây cho thấy một ggplot cho một hoạt động group_by():

get_charts1 <- function(mygroup){ 
    quo_var <- enquo(mygroup) 
    train %>% 
    group_by(!!quo_var) %>% 
    count() %>% 
    ungroup() %>% 
    ggplot(aes_q(x = quo_var, y = quote(n), fill = quo_var)) + 
    geom_col() + 
    theme(legend.position = "none") 
    } 

Nó hoạt động tốt khi tôi tự imput một tên cột , ví dụ:

get_charts1(ps_ind_07_bin) 

Tuy nhiên, tôi muốn sử dụng hàm trên một số cột mà tôi đặt trên vectơ:

binarias <- train %>% 
      select(ends_with("bin")) %>% 
      colnames() 

Sử dụng bản đồ và tham gia một số gợi ý, tôi cố gắng sử dụng:

listaplots <- map(quo(!!! syms(binarias)), get_charts1) 

Nhưng điều này mang lại cho tôi những lỗi sau:

"Error: Can't splice at top-level" 

Có ai biết những gì tôi cần phải làm gì để có được điều này để làm việc?

+0

Loo ks như 'bản đồ (quos (ps_ind_06_bin, ps_ind_07_bin), get_charts1)' không hoạt động nên vấn đề không phải là với việc mở rộng thực sự. Dường như 'map()' chỉ bắt buộc đánh giá các tham số. – MrFlick

+0

Chụp đối tượng cưỡng bức (bao gồm cả các quosures hoặc biểu tượng bắt buộc) sẽ hoạt động ra khỏi hộp trong phiên bản rlang tiếp theo. Điều này sẽ tương đương với unquoting. – lionel

+0

[Tôi nên làm gì khi ai đó trả lời câu hỏi của tôi?] (Https://stackoverflow.com/help/someone-answers) – zx8754

Trả lời

2

Thay vì map, tôi nghĩ bạn muốn invoke_map tại đây. Điều này dường như cho những gì bạn muốn

listaplots <- invoke_map(get_charts1, rlang::syms(binarias)) 

Các map() dường như để buộc đánh giá các thông số trong khi invoke_map không.

1

Thay đổi enquo() để sym() và mã của bạn hoạt động tốt như thế này:

get_charts1 <- function(mygroup){ 
    quo_var <- sym(mygroup) # <- HERE 

    train %>% 
     group_by(!!quo_var) %>% 
     count() %>% 
     ungroup() %>% 
     ggplot(aes_q(x = quo_var, y = quote(n), fill = quo_var)) + 
     geom_col() + 
     theme(legend.position = "none") 
} 

binarias <- train %>% select(ends_with("bin")) %>% colnames() 

binarias %>% map(get_charts1) 
9

Tôi sẽ bắt đầu bằng cách tạo ra một reprex (bạn đã tiến rất gần, nhưng quên để tải các gói cần thiết), và tái phong cách sang một định dạng phù hợp sử dụng styler:

library(tidyverse) 
library(rlang) 

train <- data.frame(
    ps_ind_06_bin = c(FALSE, FALSE, FALSE, TRUE, TRUE, FALSE), 
    ps_ind_07_bin = c(FALSE, TRUE, TRUE, FALSE, TRUE, TRUE), 
    ps_ind_08_bin = c(TRUE, TRUE, TRUE, FALSE, TRUE, FALSE), 
    ps_ind_09_log = c(1, 3, 4, 2, 3, 2) 
) 

get_charts <- function(mygroup) { 
    quo_var <- enquo(mygroup) 
    train %>% 
    group_by(!! quo_var) %>% 
    count() %>% 
    ungroup() %>% 
    ggplot(aes_q(x = quo_var, y = quote(n), fill = quo_var)) + 
    geom_col() + 
    theme(legend.position = "none") 
} 

Bạn muốn tự động thế hệ mã như thế này:

get_charts(ps_ind_06_bin) 
get_charts(ps_ind_07_bin) 
get_charts(ps_ind_08_bin) 

Điều đó sẽ yêu cầu vòng lặp for hoặc hàm áp dụng/bản đồ. A map() hoạt động tốt ở đây vì chúng tôi muốn trả lại đối tượng ggplot2 và thực hiện rằng với vòng lặp for đòi hỏi một số cơ sở hạ tầng hơn.Đó là đơn giản một khi bạn nhớ rằng bạn cần phải sử dụng những biểu tượng ở đây, không chuỗi nguyên

vars <- train %>% select(ends_with("bin")) %>% colnames() 

vars %>% 
    syms() %>% 
    map(function(var) get_charts(!!var)) 

## [[1]] 

## 
## [[2]] 

## 
## [[3]] 

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