簡體   English   中英

NSE函數中的dplyr group_by

[英]group_by dplyr within a function NSE

我在管道函數調用中使用dplyrgroup_by時遇到問題。

可重現的示例:

使用以下數據:

ex_data<- structure(list(word1 = c("no", "not", "not", "no", "not", "not", 
"not", "not", "no", "not", "no", "not", "not", "not", "no", "not", 
"no", "no", "not", "not", "not", "no", "not", "without", "never", 
"no", "not", "no", "no", "not", "not", "not", "no", "no", "no", 
"not", "not", "without", "never", "no", "not", "not", "not", 
"not", "not", "never", "no", "no", "not", "not"), word2 = c("doubt", 
"like", "help", "no", "want", "wish", "allow", "care", "harm", 
"sorry", "great", "leave", "pretend", "worth", "pleasure", "love", 
"danger", "want", "afraid", "doubt", "fail", "good", "forget", 
"feeling", "forget", "matter", "avoid", "chance", "hope", "forgotten", 
"miss", "perfectly", "bad", "better", "opportunity", "admit", 
"fair", "delay", "failed", "wish", "dislike", "distress", "refuse", 
"regret", "trust", "want", "evil", "greater", "better", "blame"
), score = c(-1L, 2L, 2L, -1L, 1L, 1L, 1L, 2L, -2L, -1L, 3L, 
-1L, -1L, 2L, 3L, 3L, -2L, 1L, -2L, -1L, -2L, 3L, -1L, 1L, -1L, 
1L, -1L, 2L, 2L, -1L, -2L, 3L, -3L, 2L, 2L, -1L, 2L, -1L, -2L, 
1L, -2L, -2L, -2L, -2L, 1L, 1L, -3L, 3L, 2L, -2L), n = c(102L, 
99L, 82L, 60L, 45L, 39L, 36L, 23L, 22L, 21L, 19L, 18L, 18L, 17L, 
16L, 16L, 15L, 15L, 15L, 14L, 14L, 13L, 13L, 13L, 12L, 12L, 12L, 
11L, 11L, 10L, 10L, 10L, 9L, 9L, 9L, 9L, 9L, 9L, 8L, 8L, 8L, 
8L, 8L, 8L, 8L, 7L, 7L, 7L, 7L, 7L), contribution = c(-102L, 
198L, 164L, -60L, 45L, 39L, 36L, 46L, -44L, -21L, 57L, -18L, 
-18L, 34L, 48L, 48L, -30L, 15L, -30L, -14L, -28L, 39L, -13L, 
13L, -12L, 12L, -12L, 22L, 22L, -10L, -20L, 30L, -27L, 18L, 18L, 
-9L, 18L, -9L, -16L, 8L, -16L, -16L, -16L, -16L, 8L, 7L, -21L, 
21L, 14L, -14L)), .Names = c("word1", "word2", "score", "n", 
"contribution"), row.names = c(NA, -50L), class = c("tbl_df", 
"tbl", "data.frame"))

常規的常規管道操作按預期工作:

outside_result<- ex_data %>% 
  mutate(word2=reorder(word2,contribution)) %>% 
  group_by(word1) %>% 
  top_n(10,abs(contribution)) %>% 
  group_by(word1,word2) %>% 
  arrange(desc(contribution)) %>% 
  ungroup() %>% 
  mutate(word2 = factor(paste(word2,word1, sep = "__"),
                              levels=rev(paste(word2,word1,sep="__"))))

我已經將以上內容實現為以下功能:

order_bars <- function(df,facetPanel,barCategory,value){
        df %>% mutate(barCategory=reorder(barCategory,value)) %>% 
          group_by(facetPanel) %>% 
          top_n(10,abs(value)) %>% 
          group_by(facetPanel,barCategory) %>% 
          arrange(desc(value)) %>% 
          ungroup() %>% 
          mutate(barCategory = factor(paste(barCategory,facetPanel, sep = "__"),
                                     levels=rev(paste(barCategory,facetPanel,sep="__"))))
      }

並從這篇文章中獲得建議,在函數內的mutate操作期間引用data.frame的變量時使用$表示法。

inside_result<-order_bars(ex_data,ex_data$word1,ex_data$word2,ex_data$contribution)

R引發以下錯誤:

Error: unknown variable to group by : facetPanel
Called from: resolve_vars(new_groups, tbl_vars(.data))

我懷疑group_by需要調整以使用命名變量,或者我必須使用.dot表示法來引用列,盡管我只是把它扔了出去。

您將需要學習如何使用1) dplyr動詞的SE版本,例如group_by_mutate_以及2)神秘的lazyeval::interp 請仔細閱讀vignette("nse")

然后我們可以得出:

order_bars <- function(df, facetPanel, barCategory, value){
  require(lazyeval)
  df %>% 
    mutate_(barCategory = interp(~reorder(x, y), x = as.name(barCategory), 
                                 y = as.name(value))) %>% 
    group_by_(facetPanel) %>% 
    filter_(interp(~min_rank(desc(abs(x))) <= 10, x = as.name(value))) %>% 
    group_by_(facetPanel, barCategory) %>% 
    arrange_(interp(~desc(x), x = as.name(value))) %>% 
    ungroup() %>% 
    mutate_(barCategory = interp(
      ~factor(paste(x, y, sep = "__"), levels = rev(paste(x, y, sep = "__"))),
      x = as.name(barCategory), y = as.name(facetPanel)))
}

order_bars(ex_data, 'word1', 'word2', 'contribution')
 # A tibble: 25 × 6 word1 word2 score n contribution barCategory <chr> <chr> <int> <int> <int> <fctr> 1 not like 2 99 198 like__not 2 not help 2 82 164 help__not 3 no great 3 19 57 great__no 4 no pleasure 3 16 48 pleasure__no 5 not love 3 16 48 love__not 6 not care 2 23 46 care__not 7 not want 1 45 45 want__not 8 not wish 1 39 39 wish__not 9 no good 3 13 39 good__no 10 not allow 1 36 36 allow__not 

需要注意的是,我們需要更換top_nfilter_說法,因為沒有top_n_存在。 查看top_n的源代碼,很明顯應該如何構造filter_語句。

或者,如果您想花哨的話,可以編寫NSE版本的order_bars

order_bars <- function(df,facetPanel,barCategory,value){
  facetPanel <- substitute(facetPanel)
  barCategory <- substitute(barCategory)
  value <- substitute(value)

  require(lazyeval)
  df %>% 
    mutate_(barCategory = interp(~reorder(x, y), x = barCategory, y = value)) %>% 
    group_by_(facetPanel) %>% 
    filter_(interp(~min_rank(desc(abs(x))) <= 10, x = value)) %>% 
    group_by_(facetPanel, barCategory) %>% 
    arrange_(interp(~desc(x), x = value)) %>% 
    ungroup() %>% 
    mutate_(barCategory = interp(
      ~factor(paste(x, y, sep = "__"), levels = rev(paste(x, y, sep = "__"))),
      x = barCategory, y = facetPanel))
}

order_bars(ex_data, word1, word2, contribution)

理想情況下,您將只完全編寫SE版本,然后使用lazyeval將NSE版本鏈接到SE版本。 我將其留給讀者練習。

通過rlang_0.4.0dplyr_0.8.2 ,我們可以使用整潔的求值運算符({{...}})或curl-curly將單引號和反引號抽象為一個插值步驟。

library(rlang)
library(dplyr)
order_barsN <- function(df, facetPanel, barCategory, value) {
    df %>% 
        mutate(barCategory = reorder({{barCategory}}, {{value}}))%>%
        group_by({{facetPanel}}) %>%
        filter(min_rank(desc(abs({{value}}))) <= 10) %>%
        group_by({{facetPanel}}, {{barCategory}}) %>%
        arrange(desc({{value}})) %>%
        ungroup %>%
        mutate(barCategory = factor(str_c({{barCategory}}, {{facetPanel}}, sep="__"),
                levels = rev(str_c({{barCategory}}, {{facetPanel}}, sep="__"))))

        }


out2 <- order_barsN(ex_data, word1, word2, contribution)

-檢查上一個答案

out1 <- order_bars(ex_data, word1, word2, contribution)
identical(out1, out2)
#[1] TRUE

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM