standardowa ocena w dplyr: podsumowanie zmiennej podanej jako ciąg znaków

Aktualizacja lipiec 2020:

dplyr 1.0 zmieniło się prawie wszystko na temat tego pytania, jak również wszystkie odpowiedzi. Zobacz winietę dplyr programowanie tutaj:

Https://cran.r-project.org/web/packages/dplyr/vignettes/programming.html

Nowym sposobem odwoływania się do kolumn, gdy ich identyfikator jest przechowywany jako wektor znakowy, jest użycie zaimka .data z rlang, a następnie podzbioru tak jak w bazie R.

library(dplyr)

key <- "v3"
val <- "v2"
drp <- "v1"

df <- tibble(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2)))

df %>% 
    select(-matches(drp)) %>% 
    group_by(.data[[key]]) %>% 
    summarise(total = sum(.data[[val]], na.rm = TRUE))

#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 2 x 2
#>   v3    total
#>   <chr> <int>
#> 1 A        21
#> 2 B        19

Jeśli twój kod znajduje się w funkcji pakietowej, możesz @importFrom rlang .data, aby uniknąć notatek kontrolnych r o niezdefiniowanych globalach.

ORYGINALNE PYTANIE:

Chcę odnieść się do nieznanej nazwy kolumny wewnątrz summarise. Standardowe funkcje oceny wprowadzone w dplyr 0.3 umożliwiają odwoływanie się do nazw kolumn za pomocą zmiennych, ale wydaje się, że nie działa to, gdy wywołujesz funkcję base R wewnątrz np. a summarise.

library(dplyr)
 
key <- "v3"
val <- "v2"
drp <- "v1"
 
df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2)))

DF wygląda tak:

> df
Source: local data frame [5 x 3]

  v1 v2 v3
1  1  6  A
2  2  7  A
3  3  8  A
4  4  9  B
5  5 10  B

Chcę aby upuścić v1, Grupuj przez v3 i Sumuj v2 dla każdej grupy:

df %>% select(-matches(drp)) %>% group_by_(key) %>% summarise_(sum(val, na.rm = TRUE))

Error in sum(val, na.rm = TRUE) : invalid 'type' (character) of argument

Wersja NSE select() działa poprawnie, ponieważ może pasować do ciągu znaków. Wersja se group_by() działa dobrze, ponieważ może teraz przyjmować zmienne jako argumenty i je oceniać. Nie znalazłem jednak sposobu na osiągnięcie podobnych wyników przy użyciu funkcji bazowych r wewnątrz funkcji dplyr.

Rzeczy, które nie działają:

df %>% group_by_(key) %>% summarise_(sum(get(val), na.rm = TRUE))
Error in get(val) : object 'v2' not found

df %>% group_by_(key) %>% summarise_(sum(eval(as.symbol(val)), na.rm = TRUE))
Error in eval(expr, envir, enclos) : object 'v2' not found

Sprawdziłem kilka powiązane pytania , ale do tej pory żadne z proponowanych rozwiązań nie zadziałało.

 56
Author: Ajar, 2014-11-03

5 answers

Proszę zauważyć, że ta odpowiedź Nie dotyczy , ale poprzednich wersji.

[dplyr 0.7.0] ma nowe podejście do niestandardowej oceny (NSE) o nazwie tidyeval. Jest on szczegółowo opisany w vignette("programming").


The dplyr pomocna jest tu winieta na niestandardową ewalutację . Sprawdź sekcję "mieszanie stałych i zmiennych" i przekonaj się, że można użyć funkcji interp z pakietu lazyeval oraz "[u]se as.name Jeśli masz łańcuch znaków dający nazwę zmiennej":

library(lazyeval)
df %>%
  select(-matches(drp)) %>%
  group_by_(key) %>%
  summarise_(sum_val = interp(~sum(var, na.rm = TRUE), var = as.name(val)))
#   v3 sum_val
# 1  A      21
# 2  B      19
 53
Author: Henrik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-08 14:55:27

Wraz z wydaniem pakietu rlang i aktualizacją 0.7.0 do dplyr, jest to teraz dość proste.

Jeśli chcesz użyć ciągu znaków (np. "v1") jako nazwy zmiennej, wystarczy:

  1. Konwersja ciągu znaków na symbol za pomocą sym() z pakietu rlang
  2. w wywołaniu funkcji wpisz !! przed symbolem

Na przykład, wykonałbyś następujące czynności:

my_var <- "Sepal.Length"
my_sym <- sym(my_var)
summarize(iris, Mean = mean(!!my_sym))

Bardziej zwięźle, można połączyć krok konwersji swojego string do symbolu z sym() i prefiks go z !! podczas pisania wywołania funkcji.

Na przykład możesz napisać:

my_var <- "Sepal.Length"
summarize(iris, mean(!!sym(my_var)))


Aby powrócić do oryginalnego przykładu, możesz wykonać następujące czynności:

library(rlang)

key <- "v3"
val <- "v2"
drp <- "v1"

df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2)))

df %>% 
  # NOTE: we don't have to do anything to `drp`
  # since the matches() function expects a character string
  select(-matches(drp)) %>% 
  group_by(!!sym(key)) %>% 
  summarise(sum(!!sym(val), na.rm = TRUE))


Składnia Alternatywna

Z wydaniem rlang w wersji 0.4.0, możesz użyć następującej składni:

my_var <- "Sepal.Length"
my_sym <- sym(my_var)
summarize(iris, Mean = mean({{ my_sym }}))

Zamiast pisać !!my_sym, możesz napisać {{ my_sym }}. Ma tę zaletę, że jest prawdopodobnie jaśniejsza, ale ma wadą jest to, że musisz przekonwertować ciąg znaków na symbol przed umieszczeniem go w nawiasach. Na przykład możesz napisać !!sym(my_var), ale nie możesz napisać {{sym(my_var)}}

Dodatkowe informacje

Ze wszystkich oficjalnych dokumentów wyjaśniających, jak działa użycie sym() i !!, te wydają się być najbardziej dostępne:

  1. Winieta Dplyr: programowanie za pomocą dplyr

  2. Sekcja Hadley Wickham ' s książka "Advanced R" O metaprogramowaniu

 36
Author: bschneidr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-30 15:32:38

Podaj argument .dots listę łańcuchów konstruujących łańcuchy za pomocą paste, sprintf lub używając interpolacji łańcuchowej z pakietu gsubfn poprzez fn$list w miejsce list, Jak to robimy tutaj:

library(gsubfn)
df %>% 
   group_by_(key) %>% 
   summarise_(.dots = fn$list(mean = "mean($val)", sd = "sd($val)"))

Dając:

Source: local data frame [2 x 3]

  v3 mean        sd
1  A  7.0 1.0000000
2  B  9.5 0.7071068
 9
Author: G. Grothendieck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-21 17:50:07

Nowa aktualizacja dplyr:

Nowa funkcjonalność dplyr może w tym pomóc. Zamiast łańcuchów zmiennych, które wymagają niestandardowej oceny, używamy quosures quo(). Cofamy cytowanie za pomocą innej funkcji !!. Więcej o tych Zobacz tę winietę . Będziesz potrzebował developer ' s version of dplyr aż do pełnego wydania.

library(dplyr) #0.5.0.9004+
key <- quo(v3)
val <- quo(v2)
drp <- "v1"

df <- data_frame(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2)))
df %>% select(-matches("v1")) %>% 
  group_by(!!key) %>% 
  summarise(sum(!!val, na.rm = TRUE))
# # A tibble: 2 × 2
#      v3 `sum(v2, na.rm = TRUE)`
#   <chr>                   <int>
# 1     A                      21
# 2     B                      19
 8
Author: Pierre L,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-01 21:39:56

dplyr 1.0 zmieniło się prawie wszystko na temat tego pytania, jak również wszystkie odpowiedzi. Zobacz winietę dplyr Programowanie tutaj:

Https://cran.r-project.org/web/packages/dplyr/vignettes/programming.html

Nowym sposobem odwoływania się do kolumn, gdy ich identyfikator jest przechowywany jako wektor znakowy, jest użycie zaimka .data z rlang, a następnie podzbioru tak jak w bazie r.

library(dplyr)

key <- "v3"
val <- "v2"
drp <- "v1"

df <- tibble(v1 = 1:5, v2 = 6:10, v3 = c(rep("A", 3), rep("B", 2)))

df %>% 
    select(-matches(drp)) %>% 
    group_by(.data[[key]]) %>% 
    summarise(total = sum(.data[[val]], na.rm = TRUE))

#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 2 x 2
#>   v3    total
#>   <chr> <int>
#> 1 A        21
#> 2 B        19

Jeśli Twój kod znajduje się w funkcji pakietu, możesz @importFrom rlang .data aby uniknąć R sprawdź notatki o niezdefiniowanych globalach.

 1
Author: Ajar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-02 14:50:39