Есть ли элементарный способ заменить целочисленное кодирование уровней R метками?

Это мой первый вопрос здесь, поэтому я надеюсь, что он подходит для этого форума. Любые предложения о том, как улучшить вопрос или заголовок, будут очень признательны.

Данный

> experiment <- data.frame(old=factor(c("z","z","z","z","z"),levels=c("x","y","z")),
new=factor(c("y","z","x",NA,NA),levels=c("x","y","z")))
> experiment
  old  new
1   z    y
2   z    z
3   z    x
4   z <NA>
5   z <NA>

Я хотел бы обновить старое с новым именно тогда, когда новое не NA. Команда

> experiment$old <- ifelse(is.na(experiment$new),experiment$old,experiment$new)

Кажется, это то, что я хочу, за исключением того, что я получаю целочисленное кодирование уровней R, а не сами метки:

> experiment
  old  new
1   2    y
2   3    z
3   1    x
4   3 <NA>
5   3 <NA>

Есть ли какой-то элементарный способ перевести целочисленное кодирование уровней R обратно в метки? я надеялся получить

> experiment
  old  new
1   y    y
2   z    z
3   x    x
4   z <NA>
5   z <NA>

вместо этого в качестве вывода.

Большое спасибо.


person Wes    schedule 20.04.2018    source источник


Ответы (3)


Это использует целые значения в качестве индекса в `levels (experiment $ old):

> experiment$old <- levels(experiment$old)[
                       ifelse(is.na(experiment$new),experiment$old,experiment$new)] 
> experiment
  old  new
1   y    y
2   z    z
3   x    x
4   z <NA>
5   z <NA>
person IRTFM    schedule 20.04.2018

ifelse() не будет работать, потому что он сбрасывает атрибуты. Это хорошо, потому что столбцы имеют одинаковые уровни факторов. Мы можем использовать within() следующим образом:

within(experiment, { old[!is.na(new)] <- new[!is.na(new)] })
#   old  new
# 1   y    y
# 2   z    z
# 3   x    x
# 4   z <NA>
# 5   z <NA>
person Rich Scriven    schedule 20.04.2018
comment
Спасибо, @Rich Scriven, но когда я попробовал это в своем реальном проекте, R просто завис. Должно ли это решение хорошо масштабироваться? - person Wes; 23.04.2018

Решение состоит в том, чтобы использовать dplyr::coalesce для замены NA в new соответствующим значением old, а затем присвоить его обратно old.

library(dplyr)

experiment %>% mutate(old = coalesce(new, old))

#   old  new
# 1   y    y
# 2   z    z
# 3   x    x
# 4   z <NA>
# 5   z <NA>

Данные:

experiment <- data.frame(old=factor(c("z","z","z","z","z"), levels=c("x","y","z")),
                     new=factor(c("y","z","x",NA,NA),levels=c("x","y","z")))
person MKR    schedule 20.04.2018