Estou tentando transferir meu entendimento do plyr para o dplyr, mas não consigo descobrir como agrupar por várias colunas.
# make data with weird column names that can't be hard coded
data = data.frame(
asihckhdoydkhxiydfgfTgdsx = sample(LETTERS[1:3], 100, replace=TRUE),
a30mvxigxkghc5cdsvxvyv0ja = sample(LETTERS[1:3], 100, replace=TRUE),
value = rnorm(100)
)
# get the columns we want to average within
columns = names(data)[-3]
# plyr - works
ddply(data, columns, summarize, value=mean(value))
# dplyr - raises error
data %.%
group_by(columns) %.%
summarise(Value = mean(value))
#> Error in eval(expr, envir, enclos) : index out of bounds
O que estou perdendo para traduzir o exemplo plyr em uma sintaxe do tipo dplyr?
Edit 2017 : Dplyr foi atualizado, então uma solução mais simples está disponível. Veja a resposta atualmente selecionada.
group_by_
Agora você pode usar o explicado emvignette("nse")
.dots
. Aqui está a solução adaptada da resposta da @hadley abaixo: #df %>% group_by_(.dots=list(quote(asihckhdoydk), quote(a30mvxigxkgh))) %>% summarise(n = n())
Respostas:
Desde que esta pergunta foi publicada, o dplyr adicionou versões com escopo de
group_by
( documentação aqui ). Isso permite que você use as mesmas funções que usariaselect
, da seguinte forma:O resultado da sua pergunta de exemplo é o esperado (veja a comparação do plyr acima e o resultado abaixo):
Observe que, como
dplyr::summarize
apenas retira uma camada de agrupamento de cada vez, você ainda tem alguns agrupamentos na mistura resultante (que às vezes pode pegar as pessoas de surpresa posteriormente). Se você deseja estar absolutamente seguro de comportamentos inesperados de agrupamento, sempre poderá adicionar%>% ungroup
ao seu pipeline depois de resumir.fonte
0.7.0
disponibilizar o sistema de aspas entre aspas também com várias colunas?.dots
argumentos paragroup_by()
tais como:data %>% group_by(.dots = columns) %>% summarize(value = mean(value))
.one_of()
faz alguma coisa aqui? Eu acho que é redundante nesse contexto, pois a expressão está envolta em uma chamada paravars()
.one_of()
é redundante neste contextoselect
sintaxe, consulte a novaacross
função: dplyr.tidyverse.org/reference/across.html No seu caso, seria algo parecido com istosummarize(across(all_of(c(''value_A", "value_B")), mean))
Para escrever o código na íntegra, aqui está uma atualização da resposta de Hadley com a nova sintaxe:
resultado:
fonte
asihckhdoydk
...dots <- lapply(names(df)[-3], function(x) as.symbol(x))
para criar o.dots
argumento.dots=
foi o passo crucial. se alguém souber por que isso é necessário nagroup_by
ligação, você pode editar esta resposta? agora é um pouco inescrutável.vignette("nse")
indica que há três maneiras de citar aceitáveis: fórmula, citação e caractere. A menos que você esteja preocupado com o ambiente em que ele se retirará, provavelmente você pode se safargroup_by_(.dots=grp_cols)
O suporte para isso no dplyr é atualmente bastante fraco, eventualmente acho que a sintaxe será algo como:
Mas isso provavelmente não estará lá por um tempo (porque eu preciso pensar em todas as consequências).
Enquanto isso, você pode usar
regroup()
, o que leva uma lista de símbolos:Se você tiver um vetor de caracteres de nomes de colunas, poderá convertê-los na estrutura correta com
lapply()
eas.symbol()
:fonte
as.symbol
resolve isso. Obrigado! Caso isso ajude no desenvolvimento: esse cenário é realmente comum para mim. Agregue um resultado numérico em todas as combinações das outras variáveis.regroup
também está obsoleto (pelo menos a partir da versão 0.4.3).A especificação de sequência de colunas em
dplyr
agora é suportada por variantes dasdplyr
funções com nomes terminando em um sublinhado. Por exemplo, correspondente àgroup_by
função, existe umagroup_by_
função que pode receber argumentos de string. Esta vinheta descreve a sintaxe dessas funções em detalhes.O fragmento a seguir resolve de maneira clara o problema que o @sharoz originalmente colocou (observe a necessidade de escrever o
.dots
argumento):(Observe que o dplyr agora usa o
%>%
operador e%.%
está obsoleto).fonte
Até o dplyr ter suporte total para argumentos de string, talvez essa essência seja útil:
https://gist.github.com/skranz/9681509
Ele contém várias funções de wrapper, como s_group_by, s_mutate, s_filter, etc. que usam argumentos de string. Você pode misturá-los com as funções normais do dplyr. Por exemplo
fonte
Funciona se você passar os objetos (bem, você não é, mas ...), e não como um vetor de caractere:
onde
df
estava seudata
.?group_by
diz:que eu interpreto para significar não as versões dos nomes dos personagens, mas como você se referiria a eles
foo$bar
;bar
não é citado aqui. Ou como você se referiria às variáveis em uma fórmula:foo ~ bar
.O @Arun também menciona que você pode fazer:
Mas você não pode passar algo que não avaliado é o nome de uma variável no objeto de dados.
Suponho que isso se deva aos métodos internos que Hadley está usando para procurar as coisas que você passa através do
...
argumento.fonte
fonte
Um caso (minúsculo) que está faltando nas respostas aqui, que eu queria tornar explícito, é quando as variáveis a serem agrupadas são geradas dinamicamente no meio do caminho em um pipeline:
Isso basicamente mostra como usar
grep
em conjunto comgroup_by_(.dots = ...)
para conseguir isso.fonte
Exemplo geral de uso do
.dots
argumento como entrada de vetor de caracteres para adplyr::group_by
função:Ou sem um nome codificado para a variável de agrupamento (conforme solicitado pelo OP):
Com o exemplo do OP:
Veja também a vinheta dplyr sobre programação, que explica pronomes, quase-cotação, quosures e tidyeval.
fonte