Замініть значення в кадрі даних на основі умовного ("if") оператора


122

У кадрі даних 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але в інтересах вивчення RI все ж хотілося б знати, як отримати свій оригінальний підхід до роботи (якщо це можливо)


1
ви можете додати stringsAsFactors = FALSE до початкової конструкції data.frame.
Джимміб

@jimmyb Чому? Фактори є корисними та необхідними, якщо моделювати з більшості модельних кодів R. Правильний спосіб вирішити це - визнати, що дані є фактором. Якщо ви не хочете / не потребуєте цієї конверсії, ви можете робити так, як ви говорите. Якщо ви хочете, щоб цей фактор був, то є прості способи зробити маніпуляцію, яку хоче виконати Кенні.
Гевін Сімпсон

1
Тому фактори були більш популярними через продуктивність, однак тепер, коли рядки незмінні і хеширують значення факторів, менш очевидні, оскільки більшість базових функцій R просто перетворюють їх (хоча і з попередженнями) безпосередньо. Я думаю, що фактори призводять до значної кількості помилок, які я знаходжу в кодах R людей.
jimmyb

Відповіді:


217

Простіше конвертувати nm в символи, а потім внести зміни:

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

EDIT: І якщо вам дійсно потрібно підтримувати nm як фактори, додайте це врешті:

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

4
as.character () робить життя набагато простішим при роботі з факторами. +1
Брендон Бертелсен

4
що робити, якщо у вас є кілька стовпців?
geodex


25

Коротка відповідь:

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

Погляньте на індексні вектори в R Introduction (якщо ви ще цього не прочитали).


EDIT. Як зауважено в коментарях, це рішення працює для векторів символів, тому не вдається отримати ваші дані.

Для фактору найкращий спосіб - це змінити рівень:

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

Короткий додаток: Використання% у% дійсно допомагає, якщо у вас є правий бік, як c("B","C"). Робити junk$nm[junk$nm == "B"]- це кращий спосіб.
Тіло

1
О, ще одне, важливе доповнення: Для цього потрібно спочатку додати рівень фактора bдо коефіцієнта nm. Версія diliop насправді є кращою, якщо ви хочете працювати з персонажами, а не факторами. (Завжди подумайте про тип, який мають ваші змінні спочатку!)
Thilo,

це не працює над даними, створеними @Kenny, оскільки дані є чинниками. Ви забули крок або у вас є глобальна настройка припинити перетворення символів у фактори?
Гевін Сімпсон

4
@Thilo Одним з важливих відмінностей між %in%і ==в NAзверненні: c(1,2,NA)==1дає , TRUE, FALSE, NAале c(1,2,NA) %in% 1дає TRUE, FALSE, FALSE. І так, я забув перевірити, чи це працює: /
Марек

20

Оскільки дані, які ви показуєте, є чинниками, вони дещо ускладнюють справи. Відповідь @ 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")

6
Приємно. Я не знав про функцію заміни для levels(). Як щодо одного лайнера junk <- within(junk, levels(nm)[levels(nm)=="B"] <- "b")?

Але ви називаєте це двічі :)
Марек

2
@Marek ляпає головою Просто іде, щоб показати, що не слід відповідати на коментарі щодо SO, коли вони вже минули перед сном. Давайте спробуємо ще раз ...
Гевін Сімпсон,

@Seth Справді - приємно. Не впевнений, чому я розділив кроки? Можливо, для експозиції ...
Гевін Сімпсон

11

Найпростіший спосіб зробити це в одній команді - використовувати whichкоманду, а також не потрібно змінювати чинників на характер, виконуючи це:

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

5

Ви створили змінну фактора, nmтому вам або потрібно уникати цього чи додавати додатковий рівень до атрибутів фактора. Вам також слід уникати використання <-в аргументах даних.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

@DWin дякую за ваш внесок у проблему та необхідність врахування типу змінної. Я прийняв відповідь @ diliop, оскільки це був перший робочий. Я знаю, що над <- vs = є багато питань, але (якщо на нього можна коротко відповісти) чому слід = використовувати data.frame?
DQdlM

Вам не потрібно додавати bяк рівень, просто змініть рівень, який має Bбути b.
Гевін Сімпсон

@KennyPeanuts: назва стовпця - це одне питання. Подивіться a <- data.frame(x<-1:10). Назва його стовпця не є xскоріше безладним x....1.10. Краще використовувати data.frame (x = 1: 10). Тоді ви знаєте, як називається ваша колонка.
IRTFM

@Gavin: простіше додати, ніж замінити, а ще простіше не зробити його чинником.
IRTFM

@Dwin простіше? Я не згоден - див. Свою відповідь на щось просте. Додавання рівнів може вас наздогнати, скажімо, при моделюванні, з predict()яким будете скаржитися, якщо рівні факторів у нових даних не збігаються з тими, які використовувались для моделі. Очистити в довгостроковій перспективі, щоб правильно форматувати дані, як потрібно, ніж покладатися на скорочення. Я погоджуюся, що може бути простіше не зробити це чинником, але якщо він вже є, або він повинен бути одним для вправ моделювання ...
Гевін Сімпсон,

1

Якщо ви працюєте зі змінними символів (зверніть увагу, що stringsAsFactorsтут помилково), ви можете використовувати заміну:

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
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")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.