Использование switch () в R для замены векторных значений

это должно быть довольно просто, но даже после проверки всей документации и онлайн-примеров я не понимаю.

Я хотел бы использовать switch() для замены значений вектора символов.

поддельный, чрезвычайно простой, воспроизводимый пример:

test<-c("He is", "She has", "He has", "She is")

предположим, я хочу присвоить" 1 "предложениям, включая глагол" быть "и" 2 "предложениям, включая глагол"иметь". Не работает следующее:

test<-switch(test,
                "He is"=1,
                "She is"=1,
                "He has"=2,
                "She has"=2)

сообщение об ошибке :

+ + + + Error in switch(test, `He is` = 1, `She is` = 1, `He has` = 2, `She has` = 2) : 
  EXPR must be a length 1 vector

Я думаю, что EXPR действительно является вектором длины 1, так что случилось?

Я думал, может быть, R ожидал символов в качестве замены, но ни обертывание switch() в "as.integer " или следующая работа:

test<-switch(test,
                "He is"="1",
                "She is"="1",
                "He has"="2",
                "She has"="2")

может быть, он не векторизуется, и я должен сделать цикл? Это все? Было бы разочаровывающе, учитывая силу R-векторизации. Заранее спасибо!

7 ответов


векторизованная форма if и ifelse:

test <- ifelse(test == "He is", 1,
        ifelse(test == "She is", 1,
        ifelse(test == "He has", 2,
        2)))

или

test <- ifelse(test %in% c("He is", "She is"), 1, 2)

switch в основном это способ написания вложенных if -else тесты. Вы должны думать о if и switch as поток управления операторы, а не операторы преобразования данных. Они используются для управления выполнением алгоритма, например для проверки сходимости или выбора пути выполнения. Вы не будете использовать их для прямого управления данными в большинстве обстоятельства.


вот это правильно векторизовать функция, например,переключатель:

# Data vector:
test<-c("He is", "She has", "He has", "She is")

# Vectorized SWITCH:
foo <- Vectorize(function(a) {
  switch(as.character(a),
                      "He is" = 1,
                      "She is" = 1,
                      "He has" = 2,
                      2)

}, "a")

# Result:
foo(test)

  He is She has  He has  She is 
      1       2       2       1

надеюсь, это поможет.


вы могли бы попробовать

test_out <- sapply(1:length(test), function(x) switch(test[x],
             "He is"=1,
             "She is"=1,
             "He has"=2,
             "She has"=2))

или

test_out <- sapply(test, switch,
             "He is"=1,
             "She is"=1,
             "He has"=2,
             "She has"=2)

" векторизация "основана на функции" mapply", тогда как" ifelse " является базовой функцией, которая должна быть уже векторизована. Поэтому с точки зрения производительности "векторизация" может быть медленнее. Легко векторизовать функцию R с семейством "apply", но производительность обычно является проблемой на больших объемах. Лучше использовать базовые функции, оптимизированные для работы с векторами.


Я нашел этот подход наиболее читаемым:

# input
test <-c("He is", "She has", "He has", "She is", "Unknown", "She is")

# mapping
map <- c(
  "He is" = 1, 
  "She has" = 2, 
  "He has" = 2, 
  "She is" = 1)

answer <- map[test]

# output
answer
He is She has  He has  She is    <NA>  She is 
    1       2       2       1      NA       1 

Если test является числовым, должно преобразовать значение в character чтобы использовать это.


хотя я обычно предпочитаю базовые подходы R, есть пакет с векторизованной функцией переключения.

library(broman)

switchv(c("horse", "fish", "cat", "bug"),
horse="fast",
cat="cute",
"what?")

может попробовать так:

 test<-c("He is", "She has", "He has", "She is")
 numbers <-c(1,2,2,1)
 test<-mapply(switch, as.list(test), as.list(numbers))