Partindo de um data.frame indf
e colname
sendo uma de suas colunas, quero construir outro dataframe outdf
com 2 colunas: a primeira, chamada colname
, contém os valores únicos de indf$colname
, enquanto a segunda, chamada n
, contém o número de duplicatas em indf$colname
(o original incluído , então sum(duplicated())+1
).
colname
deve ser especificado dinamicamente.
Depois de alguma pesquisa e tentativa e erro, parece que a maneira de fazer isso é:
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)
Gostaria de saber por que group_by
é necessário across(all_of(colname))
processar o nome da coluna definida dinamicamente, enquanto select
tenho que tirar aspas usando !!
.
Se eu usar across(all_of())
, select
recebo este erro:
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()`.
Enquanto se eu usar !!
nele group_by
cria uma nova coluna chamada "a"
(aspas duplas incluídas).
EDITAR:
O !!
não funciona por dentro arrange
também.
# This doesn't work
outdf %>%
arrange(desc(!!colname))
Em vez disso, você precisa de across(all_of())
:
outdf %>%
arrange(desc(across(all_of(colname))))
A função
all_of
é uma função auxiliar de seleção , comomatches
econtains
. Nos bastidores, ele apenas converte o nome da coluna em um índice de coluna numérico. Entretanto, a partir datidyselect
versão 1.2.0, os auxiliares de seleção devem ser usados dentro de um contexto de seleção (consulte?`faq-selection-context`
).Isso significa que os auxiliares de seleção podem ser usados diretamente dentro,
select
sem serem agrupadosacross
, pois este já é um contexto de seleção.Com outros verbos como
mutate
egroup_by
, estes não constituem um contexto de seleção, e a funçãoacross
é necessária para converter os índices das colunas em entradas apropriadas para essas funções.Basta usar
select(all_of(colname))
semacross
: