Отправить "неклассифицированную" переменную в качестве параметров функции? - PullRequest
1 голос
/ 07 февраля 2020

или

Как создать собственную переменную '...'?

Функции часто возвращают указанную c структуру (или класс). Иногда параметры функции также являются частью возвращаемой структуры. После манипуляции с результатом, как я могу отправить его в качестве параметров функции (или снова той же функции)?

Очень короткий псевдо-пример:

res1 <- power.t.test(alot of parameters)
res1b <- res1
res1b$some.parameter <- new-value
res2 <- power.t.test(parameters = unclass(res1b))

Это общий вопрос , на которую я наткнулся при попытке решить конкретную c проблему. Я включаю код, чтобы, надеюсь, прояснить мой вопрос:

set.seed(42); data <- rnorm(20) #to be able to reproduce

# Calculate how many pairs I need to find a difference of 1 ----
ptt1 <- power.t.test(delta = 1, sd = sd(data), sig.level = 0.05, power = 0.8, type = "paired", alternative = "two.sided")
# Paired t test power calculation
# 
# n = 15.55315
# delta = 1
# sd = 1.312628
# sig.level = 0.05
# power = 0.8
# alternative = two.sided
# 
# NOTE: n is number of *pairs*, sd is std.dev. of *differences* within pairs

# However, I wishing to know the exact power when changing n to next greater integer ----
ptt1$n <- ceiling(ptt1$n)
ptt1$power <- NULL
unclass(ptt1)
# $n
# [1] 16
# $delta
# [1] 1
# $sd
# [1] 1.312628
# $sig.level
# [1] 0.05
# $alternative
# [1] "two.sided"
# $note
# [1] "n is number of *pairs*, sd is std.dev. of *differences* within pairs"
# $method
# [1] "Paired t test power calculation"

# This is a solution ----
power.t.test.power <- function(ptt) {
  power.t.test(n = ceiling(ptt$n), delta = ptt$delta, sd = ptt$sd, sig.level = ptt$sig.level, type = ptt$type, alternative = ptt$alternative)
}

ptt1$type <- "paired" #power.t.test output (of class "power.htest") misses this named element
power.t.test.power(ptt1)
# Paired t test power calculation 
# 
# n = 16
# delta = 1
# sd = 1.312628
# sig.level = 0.05
# power = 0.8126338
# alternative = two.sided
# 
# NOTE: n is number of *pairs*, sd is std.dev. of *differences* within pairs

# BUT I WISHED that any of this would work, but all gives the same error ----
power.t.test(ptt1)
power.t.test(unclass(ptt1))
power.t.test(unlist(ptt1))
# Error in power.t.test(ptt1) : 
#   exactly one of 'n', 'delta', 'sd', 'power', and 'sig.level' must be NULL

Ответы [ 3 ]

0 голосов
/ 07 февраля 2020

Вы можете использовать purrr::lift, чтобы изменить функцию от принятия аргументов как ... до принятия списка:

## power.t.test2 accepts arguments as a single list
power.t.test2 <- purrr::lift( power.t.test )

## Modify outputs as needed
ptt1$n <- ceiling(ptt1$n)
ptt1$power <- NULL

## Reduce to a set of arguments that are accepted by the function
a <- intersect(names(ptt1), formalArgs(power.t.test))

## Use the version that accepts the list
power.t.test2( ptt1[a] )
0 голосов
/ 07 февраля 2020

Я вижу, что вы уже приняли другой ответ, но только для записи:

do.call - это способ вызова функции и передачи списка вместо отдельных аргументов. В этом случае это будет выглядеть так:

do.call(power.t.test,as.list(ptt1))

Если вы хотите передать только некоторые аргументы, вы можете задать вектор с именами, которые появляются в списке аргументов для функции:

do.call(power.t.test,as.list(ptt1[names(ptt1) %in% formalArgs(power.t.test)]))
0 голосов
/ 07 февраля 2020

Вот одно решение, возможно, не оптимальное: указание результата в виде списка всех параметров и результата и обработка пропущенных аргументов с помощью unlist первого:

af <- function(v1, v2 = NULL, v3 = NULL, v4 = NULL, res = NULL){

    if(is.null(v2)){
        cat("v2 null")
        v1 <- unlist(v1)
        v2 <- v1[2] ; v3 <- v1[3] ; res <- v1[5] ;

        v4 <- ifelse(is.null(res), v4, res)
        v1 <- v1[1]
    }
    return(list(v1 = v1, 
            v2 = v2, 
            v3 = v3, 
            v4 = v4, res = v1 + v2 + v3 + v4 ) )
}

r1 <- af(1, 1, 1, 1)
r1
af(r1)
...