Pregunta

Todavía tratando de entrar en el R de la lógica...¿cuál es la "mejor" manera de desglosar (en LHS) los resultados de una función que devuelve varios valores?

Yo no puedo hacer esto, al parecer:

R> functionReturningTwoValues <- function() { return(c(1, 2)) }
R> functionReturningTwoValues()
[1] 1 2
R> a, b <- functionReturningTwoValues()
Error: unexpected ',' in "a,"
R> c(a, b) <- functionReturningTwoValues()
Error in c(a, b) <- functionReturningTwoValues() : object 'a' not found

debe realmente hacer lo siguiente?

R> r <- functionReturningTwoValues()
R> a <- r[1]; b <- r[2]

o a la R programador escribir algo más parecido a esto:

R> functionReturningTwoValues <- function() {return(list(first=1, second=2))}
R> r <- functionReturningTwoValues()
R> r$first
[1] 1
R> r$second
[1] 2

--- editado para responder a Shane preguntas ---

En realidad no necesito dar nombres para el valor del resultado de las piezas.Me estoy aplicando una función de agregado para el primer componente y otro para el segundo componente (min y max.si era la misma función para ambos componentes no iba a necesitar la división de ellos).

¿Fue útil?

Solución

(1) lista[...]<- Yo había publicado hace más de una década en r-help.Desde entonces se ha añadido a la gsubfn paquete.No es necesario que un operador especial, pero requiere que el lado izquierdo de ser escrito utilizando list[...] como este:

library(gsubfn)  # need 0.7-0 or later
list[a, b] <- functionReturningTwoValues()

Si usted necesita solamente el primero o el segundo componente de todas funcionan demasiado:

list[a] <- functionReturningTwoValues()
list[a, ] <- functionReturningTwoValues()
list[, b] <- functionReturningTwoValues()

(Por supuesto, si usted sólo necesita un valor, a continuación, functionReturningTwoValues()[[1]] o functionReturningTwoValues()[[2]] sería suficiente).

Ver el citado r-help hilo para más ejemplos.

(2) con Si la intención es simplemente combinar los múltiples valores, posteriormente, y los valores de retorno se denomina, a continuación, una alternativa sencilla es el uso de with :

myfun <- function() list(a = 1, b = 2)

list[a, b] <- myfun()
a + b

# same
with(myfun(), a + b)

(3) coloque Otra alternativa es conectar:

attach(myfun())
a + b

AÑADIÓ: with y attach

Otros consejos

De alguna manera me topé con este truco inteligente en Internet ... No estoy seguro de si es desagradable o hermoso, pero te permite crear un & "; mágico &"; operador que le permite descomprimir múltiples valores de retorno en su propia variable. La función := se define aquí , e incluye a continuación para la posteridad:

':=' <- function(lhs, rhs) {
  frame <- parent.frame()
  lhs <- as.list(substitute(lhs))
  if (length(lhs) > 1)
    lhs <- lhs[-1]
  if (length(lhs) == 1) {
    do.call(`=`, list(lhs[[1]], rhs), envir=frame)
    return(invisible(NULL)) 
  }
  if (is.function(rhs) || is(rhs, 'formula'))
    rhs <- list(rhs)
  if (length(lhs) > length(rhs))
    rhs <- c(rhs, rep(list(NULL), length(lhs) - length(rhs)))
  for (i in 1:length(lhs))
    do.call(`=`, list(lhs[[i]], rhs[[i]]), envir=frame)
  return(invisible(NULL)) 
}

Con eso en la mano, puedes hacer lo que buscas:

functionReturningTwoValues <- function() {
  return(list(1, matrix(0, 2, 2)))
}
c(a, b) := functionReturningTwoValues()
a
#[1] 1
b
#     [,1] [,2]
# [1,]    0    0
# [2,]    0    0

No sé cómo me siento al respecto. Quizás le resulte útil en su espacio de trabajo interactivo. Usarlo para construir bibliotecas (reutilizables) (para consumo masivo) podría no ser la mejor idea, pero supongo que eso depende de usted.

... sabes lo que dicen sobre responsabilidad y poder ...

Por lo general, envuelvo el resultado en una lista, que es muy flexible (puede tener cualquier combinación de números, cadenas, vectores, matrices, matrices, listas, objetos en el resultado)

así como:

func2<-function(input) {
   a<-input+1
   b<-input+2
   output<-list(a,b)
   return(output)
}

output<-func2(5)

for (i in output) {
   print(i)
}

[1] 6
[1] 7
functionReturningTwoValues <- function() { 
  results <- list()
  results$first <- 1
  results$second <-2
  return(results) 
}
a <- functionReturningTwoValues()

Creo que esto funciona.

Puedo armar un paquete de R zeallot para abordar este problema.zeallot incluye una asignación múltiple o desembalaje operador de asignación, %<-%.Del lado izquierdo del operador de cualquier número de variables para asignar, construido a partir de las llamadas a c().El lado derecho del operador es un vector, lista, el marco de datos, la fecha, el objeto, o cualquier objeto personalizado con una implementado destructure método (ver ?zeallot::destructure).

Aquí hay un puñado de ejemplos basados en el post original,

library(zeallot)

functionReturningTwoValues <- function() { 
  return(c(1, 2)) 
}

c(a, b) %<-% functionReturningTwoValues()
a  # 1
b  # 2

functionReturningListOfValues <- function() {
  return(list(1, 2, 3))
}

c(d, e, f) %<-% functionReturningListOfValues()
d  # 1
e  # 2
f  # 3

functionReturningNestedList <- function() {
  return(list(1, list(2, 3)))
}

c(f, c(g, h)) %<-% functionReturningNestedList()
f  # 1
g  # 2
h  # 3

functionReturningTooManyValues <- function() {
  return(as.list(1:20))
}

c(i, j, ...rest) %<-% functionReturningTooManyValues()
i     # 1
j     # 2
rest  # list(3, 4, 5, ..)

Retirar el paquete viñeta para obtener más información y ejemplos.

No hay una respuesta correcta a esta pregunta. Realmente depende de lo que estés haciendo con los datos. En el sencillo ejemplo anterior, sugeriría encarecidamente:

  1. Mantenga las cosas lo más simple posible.
  2. Siempre que sea posible, es una buena práctica mantener sus funciones vectorizadas. Eso proporciona la mayor cantidad de flexibilidad y velocidad a largo plazo.

¿Es importante que los valores 1 y 2 anteriores tengan nombres? En otras palabras, ¿por qué es importante en este ejemplo que 1 y 2 se llamen a y b, en lugar de solo r [1] y r [2]? Una cosa importante para entender en este contexto es que a y b son también ambos vectores de longitud 1. Por lo tanto, realmente no está cambiando nada en el proceso de hacer esa asignación, aparte de tener 2 vectores nuevos que no necesitan subíndices para hacer referencia:

> r <- c(1,2)
> a <- r[1]
> b <- r[2]
> class(r)
[1] "numeric"
> class(a)
[1] "numeric"
> a
[1] 1
> a[1]
[1] 1

También puede asignar los nombres al vector original si prefiere hacer referencia a la letra que al índice:

> names(r) <- c("a","b")
> names(r)
[1] "a" "b"
> r["a"]
a 
1 

[Editar] Dado que aplicará min y max a cada vector por separado, sugeriría usar una matriz (si ayb tendrán la misma longitud y el mismo tipo de datos) o marco de datos (si ayb tendrán la misma longitud pero pueden ser diferentes tipos de datos) o bien use una lista como en su último ejemplo (si pueden tener diferentes longitudes y tipos de datos).

> r <- data.frame(a=1:4, b=5:8)
> r
  a b
1 1 5
2 2 6
3 3 7
4 4 8
> min(r$a)
[1] 1
> max(r$b)
[1] 8

Las listas parecen perfectas para este propósito. Por ejemplo, dentro de la función que tendría

x = desired_return_value_1 # (vector, matrix, etc)

y = desired_return_value_2 # (vector, matrix, etc)

returnlist = list(x,y...)

}  # end of function

programa principal

x = returnlist[[1]]

y = returnlist[[2]]

Sí a su segunda y tercera pregunta: eso es lo que debe hacer, ya que no puede tener múltiples "valores" a la izquierda de una tarea.

¿Qué tal usar asignar?

functionReturningTwoValues <- function(a, b) {
  assign(a, 1, pos=1)
  assign(b, 2, pos=1)
}

Puede pasar los nombres de la variable que desea pasar por referencia.

> functionReturningTwoValues('a', 'b')
> a
[1] 1
> b
[1] 2

Si necesita acceder a los valores existentes, lo contrario de assign es get.

[A] Si cada uno de los foo y bar, que es un número único, entonces no hay nada de malo con c(foo,bar);y usted puede también el nombre de los componentes:c(Foo=foo,Bar=bar).Así que usted podría tener acceso a los componentes del resultado 'res' como res[1], res[2];o, en el denominado caso, como res["Foo"], res["BAR"].

[B] Si foo y bar son vectores de la misma longitud y tipo, entonces no hay nada de malo con la devolución del cbind(foo,bar) o rbind(foo,bar);asimismo connombre.En el 'cbind' caso, el acceso foo y bar como res[,1], res[,2] o como res[,"Foo"], res ["Bar"].Usted podría también prefieren regresar a un dataframe en lugar de una matriz:

data.frame(Foo=foo,Bar=bar)

y acceder a ellos como res$Foo, res$Bar.Esto también funcionaría bien si foo y bar eran de la misma longitud, pero no del mismo tipo (por ejemplo,foo es un vector de números, la barra de un vector de cadenas de caracteres).

[C] Si foo y bar son lo suficientemente diferentes que no combinan muy bien como arriba, a continuación, debería definitivamente devolver una lista.

Por ejemplo, la función de ajuste de un modelo lineal y también el cálculo de los valores de la predicción, por lo que podría tener

LM<-lm(....) ; foo<-summary(LM); bar<-LM$fit

y entonces usted return list(Foo=foo,Bar=bar) y, a continuación, acceder al resumen como res$Foo, los valores de predicción como res$Bar

fuente: http://r.789695.n4.nabble.com/How-to-return-multiple-values-in-a-function-td858528.html

Si desea devolver la salida de su función al Entorno global, puede usar list2env, como en este ejemplo:

myfun <- function(x) { a <- 1:x
                       b <- 5:x
                       df <- data.frame(a=a, b=b)

                       newList <- list("my_obj1" = a, "my_obj2" = b, "myDF"=df)
                       list2env(newList ,.GlobalEnv)
                       }
    myfun(3)

Esta función creará tres objetos en su entorno global:

> my_obj1
  [1] 1 2 3

> my_obj2
  [1] 5 4 3

> myDF
    a b
  1 1 5
  2 2 4
  3 3 3

Para obtener múltiples salidas de una función y mantenerlas en el formato deseado, puede guardar las salidas en su disco duro (en el directorio de trabajo) desde la función y luego cargarlas desde fuera de la función:

myfun <- function(x) {
                      df1 <- ...
                      df2 <- ...
                      save(df1, file = "myfile1")
                      save(df2, file = "myfile2")
}
load("myfile1")
load("myfile2")
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top