Разница между `cross(all_of())` и `!!`

Начиная с data.frame indf и colname, являющегося одним из его столбцов, я хочу построить еще один фрейм данных outdf с двумя столбцами: первый, называемый colname, содержит уникальные значения indf$colname, а второй, называемый n, содержит количество дубликаты в indf$colname (оригинал включен, поэтому sum(duplicated())+1).

colname должен быть указан динамически.

После некоторых исследований, проб и ошибок, похоже, что это можно сделать так:

indf <- data.frame(a=c("A","A","B"), b=c(1,2,3))
colname = "a"
outdf <- indf %>%
  group_by(across(all_of(colname))) %>%
  mutate(n = n()) %>%
  select(!!colname, n)

Я хотел бы знать, почему group_by требует across(all_of(colname)) для обработки динамически определенного имени столбца, а с select мне приходится снимать кавычки с помощью !!.

Если я использую across(all_of()) в select, я получаю эту ошибку:

Error in `select()`:
ℹ In argument: `across(all_of(colname))`.
Caused by error in `across()`:
! Must only be used inside data-masking verbs like `mutate()`,
  `filter()`, and `group_by()`.

А если я использую !! в group_by, создается новый столбец с именем "a" (включая двойные кавычки).

Обновлено:

Внутри !! тоже не работает arrange.

# This doesn't work
outdf %>%
  arrange(desc(!!colname))

Вместо этого вам нужно across(all_of()):

outdf %>%
  arrange(desc(across(all_of(colname))))
group_by( !!sym(colname) ) тоже работает.
G. Grothendieck 25.08.2024 15:43
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Функция all_of является вспомогательной функцией выбора, как matches и contains. Внутри он просто преобразует имя вашего столбца в числовой индекс столбца. Однако, начиная с версии 1.2.0, помощники выбора необходимо использовать внутри контекста выбора (см. tidyselect).

Это означает, что помощники выбора можно использовать непосредственно внутри ?`faq-selection-context`, не заключая их в select, поскольку это уже контекст выбора.

Другие глаголы, такие как across и mutate, не составляют контекст выбора, и функция group_by необходима для преобразования индексов столбцов во входные данные, соответствующие этим функциям.

Просто используйте across без select(all_of(colname)):

library(dplyr)

indf    <- data.frame(a = c("A", "A", "B"), b = c(1, 2, 3))
colname <- "a"

indf %>%
  group_by(across(all_of(colname))) %>%
  mutate(n = n()) %>%
  select(all_of(colname), n)
#> # A tibble: 3 x 2
#> # Groups:   a [2]
#>   a         n
#>   <chr> <int>
#> 1 A         2
#> 2 A         2
#> 3 B         1

и почему !! внутри не работает group_by? Внутри это тоже не работает arrange

robertspierre 25.08.2024 14:33

@robertspierre, потому что group_by(!!colname) оценивается как group_by("a"), а не group_by(a). Это потому, что colname — это строка символов, а не символ. Вам понадобится что-то вроде group_by(!!str2lang(colname)), чтобы это заработало. Это работает только внутри select, потому что select также может принимать строки символов в качестве аргументов (indf %>% select("a") выберет столбец a). group_by не принимает строки символов в качестве аргумента группировки.

Allan Cameron 25.08.2024 15:13

Это выглядит слишком сложным и раздутым, чем должно быть, с большим количеством исключений, чем правил.

robertspierre 25.08.2024 15:42

@robertspierre в каком-то смысле вы усложняете задачу, пытаясь использовать инструменты там, где они не предназначены для использования. Если ваши столбцы хранятся в виде символьной строки, используйте функции выбора indf %>% group_by(across(all_of(colname))) %>% select(all_of(colname)). Tidyverse использует нестандартную оценку, чтобы упростить прямой выбор или группировку по именам столбцов. Как только вы начнете хранить имена столбцов в виде символов, вы сделаете что-то необычное, что требует обходных путей и, возможно, лучше сделать это за пределами tidyverse.

Allan Cameron 25.08.2024 16:03

Мне нужно написать общую функцию, которая достигает этого независимо от кадра данных и имени столбца.

robertspierre 25.08.2024 16:15

@robertspierre, так почему бы не использовать код в моем ответе? Оператор !! здесь не нужен.

Allan Cameron 25.08.2024 20:40

Другие вопросы по теме