Подтвердить что ты не робот

Внедрение стандартных правил утилизации

Одна приятная особенность R, связанная с присущей ей векторизованной природе, - это правило утилизации, описанное в разделе Введение в R в разделе 2.2.

Векторы, встречающиеся в одном выражении, не обязательно должны иметь одинаковую длину. Если это не так, значение выражения представляет собой вектор с той же длиной, что и самый длинный вектор, который встречается в выражении. Более короткие векторы в выражении перерабатываются так часто, как нужно (возможно, дробно), пока они не совпадут с длиной самого длинного вектора. В частности, константа просто повторяется.

Большинство стандартных функций используют это, но код, который делает это, похоронен в базовом C-коде.

Существует ли канонический способ реализации стандартных правил утилизации для функции полностью в R-коде? То есть, учитывая такую ​​функцию, как

mock <- function(a, b, c) {
    # turn a, b, and c into appropriate recycled versions

    # do something with recycled a, b, and c in some appropriately vectorized way
}

где a, b и c - векторы, возможно, различной длины и неизвестных типов/классов, существует ли канонический способ получить новый набор векторов, которые перерабатываются в соответствии со стандартными правилами утилизации? В частности, я не могу предположить, что шаг "сделать что-то" будет выполнять надлежащую переработку, поэтому мне нужно сделать это заранее.

4b9b3361

Ответ 1

Я использовал это в прошлом,

expand_args <- function(...){
  dots <- list(...)
  max_length <- max(sapply(dots, length))
  lapply(dots, rep, length.out = max_length)
}

Ответ 2

Я бы использовал аргумент length.out rep(), чтобы выполнить большую часть реальной работы.

Вот пример, который создает функцию better.data.frame() (ее действительно следует называть "better".data.frame()), которая не накладывает ограничений на длины векторов, которые она передала в качестве аргументов. В этом случае я перерабатываю все векторы на длину самого длинного, но вы можете, очевидно, адаптировать это, чтобы удовлетворить ваши собственные потребности в утилизации!

better.data.frame <- function(...) {
    cols <- list(...)
    names(cols) <- sapply(as.list(match.call()), deparse)[-1]

    # Find the length of the longest vector
    # and then recycle all columns to that length.
    n <- max(sapply(cols, length))
    cols <- lapply(cols, rep, length.out = n)

    as.data.frame(cols)
}

# Try it out
a <- Sys.Date() + 0:9
b <- 1:3
c <- letters[1:4]

data.frame(a,b,c)
# Error in data.frame(a, b, c) : 
#   arguments imply differing number of rows: 10, 3, 4

better.data.frame(a,b,c)
#             a b c
# 1  2012-02-17 1 a
# 2  2012-02-18 2 b
# 3  2012-02-19 3 c
# 4  2012-02-20 1 d
# 5  2012-02-21 2 a
# 6  2012-02-22 3 b
# 7  2012-02-23 1 c
# 8  2012-02-24 2 d
# 9  2012-02-25 3 a
# 10 2012-02-26 1 b

Ответ 3

Один короткий и грязный маршрут для численных аргументов - полагаться на автоматическую переработку cbind. Например:

f.abc <- function(a,b,c) {

     df.abc <- as.data.frame( suppressWarnings( cbind(a=a, b=b, c=c) ) )

     #Then use, for example, with() to use a, b and c inside the data frame, 
     #or apply(df.abc,1, ...) 
}

Он сильно полагается на отсутствие других законных причин для предупреждений.