Zastąp wartość w ramce danych na podstawie instrukcji warunkowej ("if")

W ramce danych r zakodowanej poniżej, chciałbym zastąpić wszystkie czasy, które B pojawia się z b.

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

To zapewnia:

   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

Moją początkową próbą było użycie for i if wypowiedzi w ten sposób:

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

Ale jak zapewne widzisz, zastępuje to wszystkie wartości junk$nm na b. Widzę, dlaczego tak się dzieje, ale nie mogę go zastąpić tylko tymi przypadkami śmieci$nm, gdzie oryginalna wartość była B.

Uwaga: udało mi się rozwiązać problem z gsub ale w interesie nauki r nadal chciałbym wiedzieć, jak uzyskać moje oryginalne podejście do pracy (jeśli jest to możliwe)

 132
Author: DQdlM, 2011-04-28

8 answers

Łatwiej przekonwertować nm na znaki, a następnie dokonać zmiany:

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

EDIT: a jeśli rzeczywiście musisz utrzymać nm jako czynniki, dodaj to na końcu:

junk$nm <- as.factor(junk$nm)
 229
Author: diliop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-28 20:50:01

Inny użyteczny sposób zastępowania wartości

library(plyr)
junk$nm <- revalue(junk$nm, c("B"="b"))
 47
Author: Oriol Prat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-11 22:10:29

Krótka odpowiedź brzmi:

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

Spójrz na wektory indeksowe we wstępie R (Jeśli jeszcze go nie przeczytałeś).


EDIT. Jak zauważono w komentarzach To rozwiązanie działa dla wektorów znaków, więc nie na danych.

Dla czynnika najlepszym sposobem jest zmiana poziomu:

levels(junk$nm)[levels(junk$nm)=="B"] <- "b"
 27
Author: Marek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-28 20:37:16

Ponieważ dane, które pokazujesz, są czynnikami, to trochę komplikuje sprawy. odpowiedź @diliop podchodzi do problemu poprzez konwersję do nm na zmienną znakową. Aby wrócić do pierwotnych czynników, wymagany jest kolejny krok.

Alternatywą jest manipulowanie poziomami czynnika w miejscu.

> 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

Jest to dość proste i często zapominam, że istnieje funkcja zastępcza dla levels().

Edit: Jak zauważył @Seth w komentarzach, można to zrobić w jednowarstwowe, bez utraty przejrzystości:

within(junk, levels(nm)[levels(nm) == "B"] <- "b")
 21
Author: Gavin Simpson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-29 08:39:08

Najprostszym sposobem, aby to zrobić w jednym poleceniu jest użycie polecenia which, a także nie trzeba zmieniać czynników na charakter, wykonując to:

junk$nm[which(junk$nm=="B")]<-"b"
 11
Author: user1021713,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-07 13:31:27

Stworzyłeś zmienną czynnika w nm, więc albo musisz tego uniknąć, albo dodać dodatkowy poziom do atrybutów czynnika. Należy również unikać używania <- w argumentach do danych.frame ()

Wariant 1:

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

Opcja 2:

levels(junk$nm) <- c(levels(junk$nm), "b")
junk$nm[junk$nm == "B"] <- "b"
junk
 5
Author: IRTFM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-28 20:18:39

Jeśli pracujesz ze zmiennymi znakowymi (zauważ, że stringsAsFactors jest tutaj false) możesz użyć 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   b   b
# 3   C   c
# 4   D   d
# ...
 2
Author: loki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-20 15:28:44
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)])
}

Wywołanie tej funkcji za pomocą poniższej linii.

d=stata.replace(d,"under20",1,"age<20")
 0
Author: Devendra Karanjit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-08 07:10:03