Substitua um valor em um quadro de dados com base em uma instrução condicional (`if`)

No quadro de dados R codificado abaixo, gostaria de replace todas as vezes que B aparece com b .

 junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12]) colnames(junk) <- c("nm", "val") 

isso fornece:

  nm val 1 A a 2 B b 3 C c 4 D d 5 A e 6 B f 7 C g 8 D h 9 A i 10 B j 11 C k 12 D l 

Minha tentativa inicial foi usar uma declaração if e if assim:

 for(i in junk$nm) if(i %in% "B") junk$nm <- "b" 

mas como eu tenho certeza que você pode ver, isso substitui TODOS os valores de junk$nm por b . Eu posso ver porque isso está fazendo isso, mas não consigo substituí-lo apenas pelos casos de lixo $ nm, onde o valor original era B

NOTA: Consegui resolver o problema com o gsub mas no interesse de aprender, o RI ainda gostaria de saber como fazer a minha abordagem original funcionar (se for possível)

Mais fácil converter nm em caracteres e depois fazer a mudança:

 junk$nm <- as.character(junk$nm) junk$nm[junk$nm == "B"] <- "b" 

EDIT: E se de fato você precisar manter nm como fatores, adicione isso no final:

 junk$nm <- as.factor(junk$nm) 

Outra maneira útil de replace valores

  library(plyr) revalue(junk$nm, c("B"="b")) 

Resposta curta é:

 junk$nm[junk$nm %in% "B"] <- "b" 

Dê uma olhada nos vetores Index em R Introduction (se você ainda não leu).


EDITAR. Conforme observado nos comentários, essa solução funciona para vetores de caracteres, portanto, falhe em seus dados.

Para fator melhor maneira é mudar de nível:

 levels(junk$nm)[levels(junk$nm)=="B"] <- "b" 

Como os dados que você mostra são fatores, isso complica um pouco as coisas. @ Resposta do diliop aborda o problema convertendo para nm para uma variável de caractere. Para voltar aos fatores originais, é necessário mais um passo.

Uma alternativa é manipular os níveis do fator no lugar.

 > lev <- with(junk, levels(nm)) > lev[lev == "B"] <- "b" > junk2 <- within(junk, levels(nm) <- lev) > junk2 nm val 1 A a 2 bb 3 C c 4 D d 5 A e 6 bf 7 C g 8 D h 9 A i 10 bj 11 C k 12 D l 

Isso é bastante simples e muitas vezes esqueço que existe uma function de substituição para os levels() .

Edit: Como observado por @Seth nos comentários, isso pode ser feito em um one-liner, sem perda de clareza:

 within(junk, levels(nm)[levels(nm) == "B"] <- "b") 

A maneira mais fácil de fazer isso em um comando é usar o comando e também não é necessário alterar os fatores em caracteres, fazendo isso:

 junk$nm[which(junk$nm=="B")]<-"b" 

Você criou uma variável de fator em nm então você precisa evitar fazer isso ou adicionar um nível adicional aos atributos do fator. Você também deve evitar usar <- nos argumentos para data.frame ()

Opção 1:

 junk <- data.frame(x = rep(LETTERS[1:4], 3), y =letters[1:12], stringsAsFactors=FALSE) junk$nm[junk$nm == "B"] <- "b" 

Opção 2:

 levels(junk$nm) <- c(levels(junk$nm), "b") junk$nm[junk$nm == "B"] <- "b" junk 

Se você está trabalhando com variables ​​de caracteres (observe que stringsAsFactors é false aqui), você pode usar replace:

 junk <- data.frame(x <- rep(LETTERS[1:4], 3), y <- letters[1:12], stringsAsFactors = FALSE) colnames(junk) <- c("nm", "val") junk$nm <- replace(junk$nm, junk$nm == "B", "b") junk # nm val # 1 A a # 2 bb # 3 C c # 4 D d # ...