Страница 1 из 1

Пользовательская функция по разному обрабатывает значения и векторы

Добавлено: 16 июл 2020, 19:48
VistaSV30
Добрый день!

У меня есть функция для вычисления прироста:

Код: Выделить всё

tr <- function(d1, d2){
  if (d1>0) s = round((d2 - d1) / d1 * 100, 1)
  if (s > 99.999) s = paste('\u2b\u432', round(d2 / d1, 1), '\u440\u430\u437\u430')
  return(s)
}
Отдельные значения функция вычисляет корректно, но с векторами такого не получается. Например,
> tr(2,7)
[1] "+в 3.5 раза"

А если использовать векторы в качестве аргументов, то не получается:

Код: Выделить всё

n1 <- sample(0:5, 10, replace = T)
n2 <- sample(0:5, 10, replace = T)

> n1
 [1] 3 5 4 1 3 1 0 0 2 5
> n2
 [1] 5 4 2 3 3 5 2 1 2 2
> tr(n1,n2)
 [1]  66.7 -20.0 -50.0 200.0   0.0 400.0   Inf   Inf   0.0 -60.0
Предупреждения:
1: В if (d1 > 0) s = round((d2 - d1)/d1 * 100, 1) :
  длина условия > 1, будет использован только первый элемент
2: В if (s > 99.999) s = paste("+в", round(d2/d1, 1), "раза") :
  длина условия > 1, будет использован только первый элемент
Может быть как-то по другому надо задавать условия?
Подскажите пожалуйста!

Re: Пользовательская функция по разному обрабатывает значения и векторы

Добавлено: 16 июл 2020, 20:44
gamm
Там же зеленым по русски написано, что нельзя в условие вектор вставлять. Либо цикл, что медленно, либо векторизация: вычислить логический индекс (маску искомых элементов), и использовать ее для изменения. Уже проходили на одном из предыдущих занятий :mrgreen:

Re: Пользовательская функция по разному обрабатывает значения и векторы

Добавлено: 17 июл 2020, 09:02
VistaSV30
Вот так теперь работает как надо:

Код: Выделить всё

 # Прирост
tr <- function(d1, d2, Percent = NULL ){
  s = round((d2 - d1) / d1 * 100, 1)
  s1 <- s
  s2 <- paste('\u2b\u432', sprintf("%1.1f", d2 / d1), '\u440\u430\u437\u430')
  s1[s == 0] <- '\u443\u440\u43e\u432\u2e'
  s1[s == -100] <- "-"
  s1[s >= 100] <- s2[s >= 100]
  s1[is.infinite(s) == TRUE] <- "+"
  return(s1)
}
Сейчас еще придумаю как знак % добавлять

Re: Пользовательская функция по разному обрабатывает значения и векторы

Добавлено: 17 июл 2020, 09:15
gamm
VistaSV30 писал(а):
17 июл 2020, 09:02
То есть, сначала нужно создать вектор из результатов вычислений, а потом функцией which() искать значения по условиям?
нет, вас все время на последовательную обработку тянет. Нужно векторизовать. Уже делали, примерно так

Код: Выделить всё

s<-rep("-",length(d1))
s[d1 == d2] = "уровень"
s[d1 == 0 && d2 == 0] = "-"
s[d1 == 0 && d2 > ] = "+"
s[d1 > 0 && d2 == 0] = "-"

Re: Пользовательская функция по разному обрабатывает значения и векторы

Добавлено: 17 июл 2020, 09:54
VistaSV30
Ой!
Пока исправлял свой вопрос мне уже ответили.

По-моему, теперь сделал как надо. (Если Percent != NULL, то к результату добавляется знак %)

Код: Выделить всё

# Прирост
tr <- function(d1, d2, Percent = NULL ){
  s = round((d2 - d1) / d1 * 100, 1)
  s1 <- s
  s2 <- paste('\u2b\u432', sprintf("%1.1f", d2 / d1), '\u440\u430\u437\u430')
  s1[s == -100] <- "-"
    d1[d1 == 0] <- 1e-10
  s1[(d2/d1)>=2] <- s2[(d2/d1)>=2]
  s1[is.infinite(s) == TRUE] <- "+"
  s1[is.na(s) == TRUE] <- "-"
  s2 <- paste0(s,"%")
  s1[abs(s) < 100 & is.null(Percent) == FALSE] <- s2[abs(s) < 100]
  s1[s == 0] <- '\u443\u440\u43e\u432\u2e'
return(s1)
}

Re: Пользовательская функция по разному обрабатывает значения и векторы

Добавлено: 17 июл 2020, 10:24
nickleb

Код: Выделить всё

TR <- sapply(seq_along(n1), 
             function (i) {tr(n1[i], n2[i])})

Re: Пользовательская функция по разному обрабатывает значения и векторы

Добавлено: 17 июл 2020, 10:42
nickleb
... или через purrr :

Код: Выделить всё

TR <- purrr::map2_chr(n1, n2, tr)

Re: Пользовательская функция по разному обрабатывает значения и векторы

Добавлено: 17 июл 2020, 11:02
nickleb
VistaSV30 писал(а):
16 июл 2020, 19:48
Отдельные значения
... а "отдельные значения" - в Вашем контексте - так это скаляры, которые по R-сути являются векторами длинной единица

Re: Пользовательская функция по разному обрабатывает значения и векторы

Добавлено: 17 июл 2020, 11:03
VistaSV30
Решил все-таки использовать свой вариант функции, сделанный по советам gamm.
Поскольку в итоге планирую все функции собрать в один пакет.

Спасибо еще раз!