Заменить значение в кадре данных на основе условного (`if`) оператора в R

В кадре данных 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, но в интересах обучения R я все еще хотел бы знать, как получить мой оригинальный подход к работе (если это возможно)

Ответ 1

Легче преобразовать nm в символы и затем внести изменения:

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

EDIT: И если вам действительно нужно поддерживать nm как факторы, добавьте это в конец:

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

Ответ 2

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

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

Ответ 3

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

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

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


ИЗМЕНИТЬ. Как замечено в комментариях, это решение работает для символьных векторов, поэтому вы теряете свои данные.

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

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

Ответ 4

Поскольку данные, которые вы показываете, являются факторами, это немного усложняет ситуацию. @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")

Ответ 5

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

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

Ответ 6

Вы создали переменную фактора в 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