Заменить значение во фрейме данных на основе условного оператора (`if`) - PullRequest
109 голосов
/ 28 апреля 2011

В кадре данных R, закодированном ниже, я хотел бы заменить все времена, когда B появляется на b.

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

это обеспечивает:

   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

Моя первая попытка состояла в том, чтобы использовать операторы for и if, например:

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

, но какЯ уверен, что вы видите, это заменяет ВСЕ значения junk$nm на b.Я могу понять, почему это происходит, но я не могу заставить его заменить только те случаи с мусором $ nm, где исходное значение было B.

ПРИМЕЧАНИЕ. Мне удалось решить проблему сgsub но в интересах изучения РИ все равно хотел бы узнать, как получить мой оригинальный подход к работе (если это возможно)

Ответы [ 8 ]

186 голосов
/ 29 апреля 2011

Проще преобразовать нм в символы, а затем внести изменения:

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

РЕДАКТИРОВАТЬ: И если вам действительно нужно сохранить НМ в качестве факторов, добавьте это в конце:

junk$nm <- as.factor(junk$nm)
36 голосов
/ 14 декабря 2013

еще один полезный способ заменить значения

library(plyr)
junk$nm <- revalue(junk$nm, c("B"="b"))
24 голосов
/ 29 апреля 2011

Краткий ответ:

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

Взгляните на Индексные векторы в R Введение (если вы еще не читали его).


EDIT. Как отмечалось в комментариях, это решение работает для символьных векторов, поэтому не работает с вашими данными.

Для фактора лучшим способом является изменение уровня:

levels(junk$nm)[levels(junk$nm)=="B"] <- "b"
19 голосов
/ 29 апреля 2011

Поскольку данные, которые вы показываете, являются факторами, они немного усложняют ситуацию.Ответ @ diliop решает проблему путем преобразования в nm символьной переменной.Чтобы вернуться к исходным факторам, требуется еще один шаг.

Альтернативой является управление уровнями фактора на месте.

> 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

Это довольно просто, и я часто забываюесть функция замены для levels().

Редактировать: Как отмечено @Seth в комментариях, это можно сделать в одну строку без потери ясности:

within(junk, levels(nm)[levels(nm) == "B"] <- "b")
11 голосов
/ 07 января 2012

Самый простой способ сделать это в одной команде - это использовать команду which, а также не нужно изменять коэффициенты на символы, выполняя это:

junk$nm[which(junk$nm=="B")]<-"b"
5 голосов
/ 29 апреля 2011

Вы создали факторную переменную в nm, поэтому вам нужно либо избегать этого, либо добавить дополнительный уровень к атрибутам фактора.Вам также следует избегать использования <- в аргументах data.frame ()

Опция 1:

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

Опция 2:

levels(junk$nm) <- c(levels(junk$nm), "b")
junk$nm[junk$nm == "B"] <- "b"
junk
1 голос
/ 20 февраля 2018

Если вы работаете с символьными переменными (обратите внимание, что stringsAsFactors здесь ложно), вы можете использовать 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
# ...
0 голосов
/ 08 апреля 2019
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)])
}

Вызовите эту функцию, используя строку ниже.

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