Vervang een waarde in een dataframe op basis van een voorwaardelijke (`if`) instructie

In het R-gegevensframe dat hieronder is gecodeerd, wil ik alle keren vervangen dat B
verschijnt met B.

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

dit biedt:

  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

Mijn eerste poging was om foren ifstatements te gebruiken zoals:

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

maar zoals je zeker kunt zien, vervangt dit ALLE waarden van junk$nmdoor B. Ik begrijp waarom dit dit doet, maar ik krijg het niet voor elkaar om alleen die gevallen van junk$nm te vervangen waar de oorspronkelijke waarde Bwas.

OPMERKING: ik heb het probleem met gsubkunnen oplossen, maar in het belang van het leren van R zou ik toch graag willen weten hoe ik mijn oorspronkelijke aanpak kan laten werken (als het mogelijk is)


Antwoord 1, autoriteit 100%

Gemakkelijker om nm naar tekens te converteren en vervolgens de wijziging aan te brengen:

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

EDIT: En als je inderdaad nm als factoren wilt behouden, voeg dan dit op het einde toe:

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

Antwoord 2, autoriteit 20%

een andere handige manier om waarden te vervangen

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

Antwoord 3, autoriteit 12%

Kort antwoord is:

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

Bekijk Indexvectoren in R Inleiding(als je het nog niet leest).


BEWERKEN. Zoals opgemerkt in opmerkingen, werkt deze oplossing voor karaktervectoren, dus faal op uw gegevens.

De beste manier is om van niveau te veranderen:

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

Antwoord 4, autoriteit 9%

Omdat de gegevens die u laat zien factoren zijn, wordt de zaak een beetje ingewikkelder. @diliop’s Answer benadert het probleem door nmom te zetten in een karaktervariabele. Om terug te keren naar de oorspronkelijke factoren is een volgende stap vereist.

Een alternatief is om de niveaus van de aanwezige factor te manipuleren.

> lev <- with(junk, levels(nm))
> lev[lev == "B"] <- "b"
> junk2 <- within(junk, levels(nm) <- lev)
> junk2
   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

Dat is vrij eenvoudig en ik vergeet vaak dat er een vervangingsfunctie is voor levels().

Bewerken:Zoals @Seth in de opmerkingen opmerkt, kan dit in een one-liner, zonder verlies van duidelijkheid:

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

Antwoord 5, autoriteit 5%

De gemakkelijkste manier om dit in één opdracht te doen, is door de opdracht whichte gebruiken en ook de factoren niet in tekens te veranderen door dit te doen:

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

Antwoord 6, autoriteit 2%

Je hebt een factorvariabele gemaakt in nm, dus je moet dit ofwel vermijden, ofwel een extra niveau toevoegen aan de factorattributen. Vermijd ook het gebruik van <-in de argumenten voor data.frame()

Optie 1:

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

Optie 2:

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

Antwoord 7

Als u met karaktervariabelen werkt (merk op dat stringsAsFactorshier onwaar is), kunt u vervangen:

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   b   b
# 3   C   c
# 4   D   d
# ...

Antwoord 8

stata.replace<-function(data,replacevar,replacevalue,ifs) {
  ifs=parse(text=ifs)
  yy=as.numeric(eval(ifs,data,parent.frame()))
  x=sum(yy)
  data=cbind(data,yy)
  data[yy==1,replacevar]=replacevalue
  message=noquote(paste0(x, " replacement are made"))
  print(message)
  return(data[,1:(ncol(data)-1)])
}

Roep deze functie aan met de onderstaande regel.

d=stata.replace(d,"under20",1,"age<20")

Antwoord 9

Je kunt ook ifelsegebruiken, wat heel eenvoudig te begrijpen is

junk$val <- ifelse(junk$nm == "B", "b", junk$val)

Als je het nog steeds wilt doen via for loopde juiste manier om het te doen

for(i in 1:nrow(junk)){
  if(junk[i, "nm"] == "B"){
    junk[i, "val"] <- "b"
  }
}
junk
> junk
   nm val
1   A   a
2   B   b
3   C   c
4   D   d
5   A   e
6   B   b
7   C   g
8   D   h
9   A   i
10  B   b
11  C   k
12  D   l

Antwoord 10

Ik heb hetzelfde probleem, je kunt ook hetzelfde doen voor elke kolom,

fix_junk <- function(x){
      #x <- as.character(x)
      x[x == "B"] <- "b"
      x
    }
    junk[] <- lapply(junk, fix_junk); junk # junk[] to get a data frame rather than a list
    junk[1:3] <- lapply(junk[1:3], fix_junk); junk

Other episodes