O mutate pode ser usado quando a mutação é condicional (dependendo dos valores de certos valores da coluna)?
Este exemplo ajuda a mostrar o que quero dizer.
structure(list(a = c(1, 3, 4, 6, 3, 2, 5, 1), b = c(1, 3, 4,
2, 6, 7, 2, 6), c = c(6, 3, 6, 5, 3, 6, 5, 3), d = c(6, 2, 4,
5, 3, 7, 2, 6), e = c(1, 2, 4, 5, 6, 7, 6, 3), f = c(2, 3, 4,
2, 2, 7, 5, 2)), .Names = c("a", "b", "c", "d", "e", "f"), row.names = c(NA,
8L), class = "data.frame")
a b c d e f
1 1 1 6 6 1 2
2 3 3 3 2 2 3
3 4 4 6 4 4 4
4 6 2 5 5 5 2
5 3 6 3 3 6 2
6 2 7 6 7 7 7
7 5 2 5 2 6 5
8 1 6 3 6 3 2
Eu esperava encontrar uma solução para o meu problema usando o pacote dplyr (e sim, eu sei que esse código não deve funcionar, mas acho que isso esclarece o propósito) para criar uma nova coluna g:
library(dplyr)
df <- mutate(df,
if (a == 2 | a == 5 | a == 7 | (a == 1 & b == 4)){g = 2},
if (a == 0 | a == 1 | a == 4 | a == 3 | c == 4) {g = 3})
O resultado do código que estou procurando deve ter esse resultado neste exemplo específico:
a b c d e f g
1 1 1 6 6 1 2 3
2 3 3 3 2 2 3 3
3 4 4 6 4 4 4 3
4 6 2 5 5 5 2 NA
5 3 6 3 3 6 2 NA
6 2 7 6 7 7 7 2
7 5 2 5 2 6 5 2
8 1 6 3 6 3 2 3
Alguém tem uma idéia sobre como fazer isso no dplyr? Esse quadro de dados é apenas um exemplo, os quadros de dados com os quais estou lidando são muito maiores. Por causa de sua velocidade, tentei usar o dplyr, mas talvez haja outras maneiras melhores de lidar com esse problema?
dplyr::case_when()
é muito mais claro que umifelse
,Respostas:
Usar
ifelse
Added - if_else: Observe que no dplyr 0.5 existe uma
if_else
função definida; portanto, uma alternativa seria substituirifelse
porif_else
; no entanto, observe que, uma vez queif_else
é mais rígido do queifelse
(ambas as pernas da condição devem ter o mesmo tipo), portantoNA
, nesse caso, teria que ser substituído porNA_real_
.Added - case_when Desde que esta pergunta foi publicada, o dplyr adicionou,
case_when
então outra alternativa seria:Added - arithmetic / na_if Se os valores forem numéricos e as condições (exceto o valor padrão de NA no final) forem mutuamente exclusivas, como é o caso da pergunta, podemos usar uma expressão aritmética para que cada termo seja multiplicado pelo resultado desejado usando
na_if
no final para substituir 0 por NA.fonte
NA
, quero que as linhas que não atendem às condições permaneçam as mesmas?mutate(g = ifelse(condition1, 2, ifelse(condition2, 3, g))
Como você solicita outras maneiras melhores de lidar com o problema, aqui está outra maneira de usar
data.table
:Observe que a ordem das instruções condicionais é revertida para obter
g
corretamente. Não há cópiag
feita, mesmo durante a segunda tarefa - ela é substituída no local .Em dados maiores, isso teria melhor desempenho do que o uso de aninhados
if-else
, pois pode avaliar os casos 'sim' e 'não' , e o aninhamento pode ficar mais difícil de ler / manter o IMHO.Aqui está uma referência em dados relativamente maiores:
Não tenho certeza se essa é uma alternativa que você pediu, mas espero que ajude.
fonte
DT_fun
está modificando sua entrada no local, o benchmark pode não ser bastante justo - além de não receber a mesma entrada da 2ª iteração para frente (o que pode afetar o tempo, uma vez queDT$g
já está alocado?), O resultado também se propaga de voltaans1
e, portanto, pode ( se Deems otimizador de R necessário? Não tenho certeza sobre isso ...) evitar outra cópia queDPLYR_fun
eBASE_fun
necessidade de fazer?data.table
solução é ótima e usodata.table
sempre que realmente preciso de velocidade para operações em tabelas e não quero ir até o C ++. No entanto, é preciso ter muito cuidado com as modificações implementadas!O dplyr agora tem uma função
case_when
que oferece um vetorizado if. A sintaxe é um pouco estranha se comparada com a demosaic:::derivedFactor
que você não pode acessar variáveis da maneira dplyr padrão e precisa declarar o modo de NA, mas é consideravelmente mais rápido quemosaic:::derivedFactor
.EDIT: Se você estiver usando a
dplyr::case_when()
versão anterior à 0.7.0 do pacote, precisará preceder os nomes das variáveis com '.$
' (por exemplo, escreva.$a == 1
dentrocase_when
).Referência : para a referência (reutilizando funções do post de Arun) e reduzindo o tamanho da amostra:
Isto dá:
fonte
case_when
também poderia ser escrito como:df %>% mutate(g = with(., case_when(a %in% c(2,5,7) | (a==1 & b==4) ~ 2L, a %in% c(0,1,3,4) | c==4 ~ 3L, TRUE ~ NA_integer_)))
.$
mais na nova versão do dplyrA
derivedFactor
função domosaic
pacote parece ter sido projetada para lidar com isso. Usando este exemplo, seria semelhante a:(Se você deseja que o resultado seja numérico em vez de um fator, pode encerrar
derivedFactor
umaas.numeric
chamada.)derivedFactor
também pode ser usado para um número arbitrário de condicionais.fonte
.asFactor = F
opção ou usando aderivedVariable
função (similar) no mesmo pacote.recode
partir do dplyr 0.5 fará isso. Ainda não investiguei isso. Veja blog.rstudio.org/2016/06/27/dplyr-0-5-0case_when
agora é uma implementação bastante limpa do caso do estilo SQL quando:Usando dplyr 0.7.4
O manual: http://dplyr.tidyverse.org/reference/case_when.html
fonte