Интерпретация предупреждения «условие имеет длину > 1» от функции `if`

#r

#r #if-оператор

Вопрос:

У меня есть массив:

 a <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
  

и хотел бы реализовать следующую функцию:

 w<-function(a){
  if (a>0){
    a/sum(a)
  }
  else 1
}
  

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

В противном случае он должен просто записать 1.

Я получаю следующее предупреждающее сообщение:

  Warning message:
 In if (a > 0) { :
 the condition has length > 1 and only the first element will be used
  

Как я могу исправить функцию?

Комментарии:

1. @user1723765 что вы ожидаете получить в результате?

2. итак, в принципе, если a a[a> 0], то следует выполнить / sum (a), а не [a>0] / sum(a)

3. результатом были бы 0s и .166667 и т.д. Для других чисел, Но в итоге у меня все равно был бы весь вектор

4. да, я только что понял. Спасибо!

5. Содержит ли ваш фактический вектор только нули и единицы?

Ответ №1:

может быть, вы хотите ifelse :

 a <- c(1,1,1,1,0,0,0,0,2,2)
ifelse(a>0,a/sum(a),1)

 [1] 0.125 0.125 0.125 0.125 1.000 1.000 1.000 1.000
 [9] 0.250 0.250
  

Комментарии:

1. Предупреждение: ifelse использует столько элементов из вашего решения, сколько элементов в условии! Оно не предупреждает об этом. Например, ifelse(TRUE, 1:5, 5:1) возвращает 1 как ответ, а не 1:5 . ifelse(c(T, T), 1:5, 5:1)` возвращает c(1, 2) и т.д. Используйте с осторожностью.

Ответ №2:

if оператор не векторизован. Для векторизованных операторов if вам следует использовать ifelse . В вашем случае достаточно написать

 w <- function(a){
if (any(a>0)){
  a/sum(a)
}
  else 1
}
  

или короткая векторизованная версия

 ifelse(a > 0, a/sum(a), 1)
  

Это зависит от того, какую функцию вы хотите использовать, потому что первая функция выдает выходной вектор длиной 1 (в части else) и ifelse выдает выходной вектор длиной, равной длине a .

Комментарии:

1. почему, о, почему, если все остальное в R-land векторизовано … ‘if’ нет? Smdh.

2. Ваше решение с if (any()) помогло мне 9 лет спустя. Ты гений. Спасибо!

Ответ №3:

Просто добавляю точку ко всему обсуждению того, почему появляется это предупреждение (раньше мне это было непонятно). Причина, по которой это происходит, как упоминалось ранее, заключается в том, что ‘a’ в данном случае является вектором, а неравенство ‘a>0’ создает другой вектор TRUE и FALSE (где ‘a’ равно > 0 или нет).

Если вы хотите вместо этого проверить, есть ли какое-либо значение ‘a> 0’, вы можете использовать функции — ‘any’ или ‘all’

Лучшие

Ответ №4:

Вот простой способ без ifelse :

 (a/sum(a))^(a>0)
  

Пример:

 a <- c(0, 1, 0, 0, 1, 1, 0, 1)

(a/sum(a))^(a>0)

[1] 1.00 0.25 1.00 1.00 0.25 0.25 1.00 0.25
  

Комментарии:

1. Это превосходит ifelse примерно в 7 раз (для массива из 100000 элементов).

2. Не могли бы вы порекомендовать краткое объяснение / документацию этого ^ оператора (например, как он называется и как он работает). Предпочтительно что-то более простое, чем документация по арифметическим операторам

3. @thefor ecologist Для возведения в степень используется оператор ^ . Команда x ^ y означает: x возведена в степень y . Код 2 ^ 3 будет вычислен 2 * 2 * 2 .

Ответ №5:

Я столкнулся с этим вопросом, когда попытался сделать что-то подобное, где я определял функцию, и она вызывалась с массивом, как указывали другие

Вы могли бы сделать что-то подобное, однако для этого сценария это менее элегантно по сравнению с методом Sven.

 sapply(a, function(x) afunc(x))

afunc<-function(a){
  if (a>0){
    a/sum(a)
  }
  else 1
}
  

Ответ №6:

Используйте lapply функцию после создания вашей функции в обычном режиме.

 lapply(x="your input", fun="insert your function name")
  

lapply выдает список, поэтому используйте unlist функцию, чтобы удалить их из функции

 unlist(lapply(a,w))
  

Комментарии:

1. Вы имеете в виду unlist удаление его из списка, а не функции?

2. да, я это имел в виду, извините за ошибку

Ответ №7:

Я бы сказал, что наиболее эффективным способом является ответ пользователя 1317221_g. Однако, если вы хотите вернуться к основам, то было бы полезно выполнить цикл по длине вашего вектора (поскольку функция if не работает по длине вектора) с использованием функции for.

 w <- c() ##creates empty vector named 'w'
for(i in 1:length(a)){
  if (a[i]>0){
    w[i] <- a[i]/sum(a)
  }
  else 
    w[i] <- 1
}