Em um grande dataframe ("myfile") com quatro colunas, tenho que adicionar uma quinta coluna com valores condicionalmente baseados nas primeiras quatro colunas.
Prefira respostas com dplyr
e mutate
, principalmente por causa de sua velocidade em grandes conjuntos de dados.
Meu dataframe é parecido com este:
V1 V2 V3 V4
1 1 2 3 5
2 2 4 4 1
3 1 4 1 1
4 4 5 1 3
5 5 5 5 4
...
Os valores da quinta coluna (V5) são baseados em algumas regras condicionais:
if (V1==1 & V2!=4) {
V5 <- 1
} else if (V2==4 & V3!=1) {
V5 <- 2
} else {
V5 <- 0
}
Agora eu quero usar a mutate
função para usar essas regras em todas as linhas (para evitar loops lentos). Algo assim (e sim, eu sei que não funciona assim!):
myfile <- mutate(myfile, if (V1==1 & V2!=4){V5 = 1}
else if (V2==4 & V3!=1){V5 = 2}
else {V5 = 0})
Este deve ser o resultado:
V1 V2 V3 V4 V5
1 1 2 3 5 1
2 2 4 4 1 2
3 1 4 1 1 0
4 4 5 1 3 0
5 5 5 5 4 0
Como fazer isso dplyr
?
NA
, (NaN, +Inf, -Inf
)?dplyr
, é melhor usardata.table
.Respostas:
Experimente isto:
myfile %>% mutate(V5 = (V1 == 1 & V2 != 4) + 2 * (V2 == 4 & V3 != 1))
dando:
V1 V2 V3 V4 V5 1 1 2 3 5 1 2 2 4 4 1 2 3 1 4 1 1 0 4 4 5 1 3 0 5 5 5 5 4 0
ou isto:
myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, ifelse(V2 == 4 & V3 != 1, 2, 0)))
dando:
V1 V2 V3 V4 V5 1 1 2 3 5 1 2 2 4 4 1 2 3 1 4 1 1 0 4 4 5 1 3 0 5 5 5 5 4 0
Nota
Sugiro que você obtenha um nome melhor para seu quadro de dados. myfile faz parecer que contém um nome de arquivo.
Acima usou esta entrada:
myfile <- structure(list(V1 = c(1L, 2L, 1L, 4L, 5L), V2 = c(2L, 4L, 4L, 5L, 5L), V3 = c(3L, 4L, 1L, 1L, 5L), V4 = c(5L, 1L, 1L, 3L, 4L )), .Names = c("V1", "V2", "V3", "V4"), class = "data.frame", row.names = c("1", "2", "3", "4", "5"))
Atualização 1 Desde que postado originalmente, o dplyr mudou
%.%
para,%>%
então modifiquei a resposta de acordo.A atualização 2 dplyr agora
case_when
oferece outra solução:myfile %>% mutate(V5 = case_when(V1 == 1 & V2 != 4 ~ 1, V2 == 4 & V3 != 1 ~ 2, TRUE ~ 0))
fonte
ifelse
afirmações:myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, 0), V5 = ifelse(V2 == 4 & V3 != 1, 2, V5))
Com
dplyr 0.7.2
, você pode usar acase_when
função muito útil :x=read.table( text="V1 V2 V3 V4 1 1 2 3 5 2 2 4 4 1 3 1 4 1 1 4 4 5 1 3 5 5 5 5 4") x$V5 = case_when(x$V1==1 & x$V2!=4 ~ 1, x$V2==4 & x$V3!=1 ~ 2, TRUE ~ 0)
Expresso com
dplyr::mutate
, dá:x = x %>% mutate( V5 = case_when( V1==1 & V2!=4 ~ 1, V2==4 & V3!=1 ~ 2, TRUE ~ 0 ) )
Observe que
NA
não são tratados de maneira especial, pois podem ser enganosos. A função retornaráNA
apenas quando nenhuma condição for correspondida. Se você colocar uma linha comTRUE ~ ...
, como fiz no meu exemplo, o valor de retorno nunca seráNA
.Portanto, você deve dizer expressivamente
case_when
para colocarNA
onde pertence, adicionando uma instrução comois.na(x$V1) | is.na(x$V3) ~ NA_integer_
. Dica: adplyr::coalesce()
função pode ser muito útil aqui às vezes!Além disso, por favor, note que
NA
por si só, geralmente não trabalho, você tem que colocar especiaisNA
valores:NA_integer_
,NA_character_
ouNA_real_
.fonte
Parece que
derivedFactor
omosaic
pacote foi projetado para isso. Neste exemplo, seria algo como:library(mosaic) myfile <- mutate(myfile, V5 = derivedFactor( "1" = (V1==1 & V2!=4), "2" = (V2==4 & V3!=1), .method = "first", .default = 0 ))
(Se você quiser que o resultado seja numérico em vez de um fator, envolva o
derivedFactor
com umas.numeric
.)Observe que a
.default
opção combinada com.method = "first"
define a condição "else" - essa abordagem é descrita no arquivo de ajuda doderivedFactor
.fonte
.asFactor = F
opção ou usando aderivedVariable
função (semelhante) no mesmo pacote.recode
do dplyr 0.5 vai fazer isso. Eu não investiguei isso ainda. Veja blog.rstudio.org/2016/06/27/dplyr-0-5-0mosaic::derivedFactor
família de funções é muito lenta. Se você descobrir o porquê, responda à minha pergunta do SO sobre isso: stackoverflow.com/questions/33787691/… . Fico feliz em ver em seu outro comentário quedplyr::case_when
é mais rápido - vou ter que mudar para isso.