Почему операторы ifelse в R не могут возвращать векторы?


118

Время от времени я обнаружил, что ifelse-операторы R. Например:

ifelse(TRUE,1,2)
# [1] 1
ifelse(FALSE,1,2)
# [1] 2

Но меня несколько смущает следующее поведение.

ifelse(TRUE,c(1,2),c(3,4))
# [1] 1
ifelse(FALSE,c(1,2),c(3,4))
# [1] 3

Это вариант дизайна, который выше моей зарплаты?


1
немного странный дизайн для ifelse, учитывая тот факт, что простой if else работает.
— 2сб

4
ifelse - векторизованная функция. Их следует использовать для разных задач.
— marbel

Ответы:


99

В документации ifelseговорится:

ifelseвозвращает значение с той же формой, testкоторая заполнена с элементами , выбранными из либо yesили в noзависимости от того , элемент testявляется TRUEили FALSE.

Поскольку вы передаете тестовые значения длины 1, вы получаете результаты длины 1. Если вы передаете более длинные тестовые векторы, вы получите более длинные результаты:

> ifelse(c(TRUE, FALSE), c(1, 2), c(3, 4))
[1] 1 4

So ifelseпредназначен для конкретной цели тестирования вектора логических значений и возврата вектора той же длины, заполненного элементами, взятыми из (вектора) yesи noаргументов.

Это обычная путаница из-за имени функции, когда if () {} else {}вместо этого вам нужна обычная конструкция.


16
Возможно, то, что вы действительно хотели для второго набора утверждений, было if (TRUE) c(1,2) else c(3,4).
— Джонатан Чанг,

69

Держу пари, вам нужен простой ifоператор вместо ifelse- в R ifэто не просто структура потока управления, она может возвращать значение:

> if(TRUE) c(1,2) else c(3,4)
[1] 1 2
> if(FALSE) c(1,2) else c(3,4)
[1] 3 4

@ Кен, у меня это работает, хотя я получаю то, что мне нужно, постоянное предупреждение, " Warning in if (req(inputval) == "All") { : the condition has length > 1 and only the first element will be used"что мне делать, чтобы избавиться от этого предупреждения?
— user5249203 05

1
@ user5249203, вопрос и ответ Кена относятся к случаю, когда условие представляет собой одно значение, т. е. вектор длины 1. Предупреждение указывает, что в req(inputval)нем больше элементов. Чтобы получить одно значение, функции any()или all()могут быть полезны.
— Uwe

12

Обратите внимание, что вы можете обойти проблему, если назначите результат внутри ifelse:

ifelse(TRUE, a <- c(1,2), a <- c(3,4))
a
# [1] 1 2

ifelse(FALSE, a <- c(1,2), a <- c(3,4))
a
# [1] 3 4

3
IMHO, это обнадеживает неправильное использование векторизованной ifelse()функции вместо потока управления if ... else ...для назначения. Если условие - одно TRUEили FALSEзначение, я бы предпочел написать a <- if (TRUE) c(1,2) else c(3,4)илиif (TRUE) a <- c(1,2) else a <- c(3,4)
— Уве

1
@Uwe, хотя я не думаю, что разница в производительности при использовании ifelseвместо if... elseв случае одного условия действительно может быть проблемой и ifelseможет быть предпочтительнее в некоторых случаях внутри кода (простое предположение здесь), я не могу с вами не согласиться ;-). Я просто хотел показать свой путь ifelse.
— Cath

9

да, я думаю, что ifelse () действительно разработан для случаев, когда у вас есть большой длинный вектор тестов и вы хотите сопоставить каждый с одним из двух вариантов. Например, я часто использую цвета для plot () следующим образом:

plot(x,y, col = ifelse(x>2,  'red', 'blue'))

Если у вас большой длинный вектор тестов , но хотел пар для выходов, вы можете использовать sapply()или plyr«S llply()или что - то, возможно.


4

Иногда пользователю просто нужен switchоператор вместо ifelse. В таком случае:

condition <- TRUE
switch(2-condition, c(1, 2), c(3, 4))
#### [1] 1 2

(это еще один вариант синтаксиса ответа Кена Уильямса)


4

Вот подход, аналогичный предложенному Катом, но он может работать с существующими заранее заданными векторами.

Он основан на использовании следующего get():

a <- c(1,2)
b <- c(3,4)
get(ifelse(TRUE, "a", "b"))
# [1] 1 2

4

используйте `if`, например

> `if`(T,1:3,2:4)
[1] 1 2 3

Это единственный ответ, который действительно может обеспечить ожидаемую функциональность ifelse.
— sus_mlm

2

В вашем случае было бы полезно использовать if_elsefrom dplyr: if_elseболее строгий, чем ifelse, и выдает ошибку для вашего случая:

library(dplyr)
if_else(TRUE,c(1,2),c(3,4))
#> `true` must be length 1 (length of `condition`), not 2

0

Найдено на каждом дропре :

ifelse(rep(TRUE, length(c(1,2))), c(1,2),c(3,4))
#>[1] 1 2

Может воспроизвести результат вашего состояния, чтобы вернуть желаемую длину

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.