Внедрение стандартных правил утилизации - PullRequest
34 голосов
/ 18 февраля 2012

Одной приятной особенностью 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 - векторы, возможно различной длины и неизвестных типов / классов, - существует ли канонический способ получения нового набора векторов, которые перерабатываются в соответствии со стандартными правилами переработки? ? В частности, я не могу предположить, что шаг «сделать что-то» сам по себе сделает правильную переработку, поэтому мне нужно сделать это самому заранее.

Ответы [ 3 ]

22 голосов
/ 18 февраля 2012

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

expand_args <- function(...){
  dots <- list(...)
  max_length <- max(sapply(dots, length))
  lapply(dots, rep, length.out = max_length)
}
8 голосов
/ 18 февраля 2012

Я бы, вероятно, использовал аргумент 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
1 голос
/ 17 августа 2017

Один короткий и грязный способ для числовых аргументов - полагаться на автоматическую утилизацию 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, ...) 
}

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

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