ylabel manipulation labs ggplot change r variables tuples variable-assignment assign

r - manipulation - plot title ggplot2



Asignar múltiples nuevas variables en LHS en una sola línea (14)

Quiero asignar múltiples variables en una sola línea en R. ¿Es posible hacer algo como esto?

values # initialize some vector of values (a, b) = values[c(2,4)] # assign a and b to values at 2 and 4 indices of ''values''

Normalmente quiero asignar alrededor de 5-6 variables en una sola línea, en lugar de tener múltiples líneas. ¿Hay una alternativa?


Considere usar la funcionalidad incluida en la base R.

Por ejemplo, cree un marco de datos de 1 fila (digamos V ) e inicialice sus variables en él. Ahora puede asignar múltiples variables a la vez V[,c("a", "b")] <- values[c(2, 4)] , llamar a cada una por su nombre ( V$a ), o usar muchas de ellos al mismo tiempo ( values[c(5, 6)] <- V[,c("a", "b")] ).

Si te vuelves perezoso y no quieres ir a las variables de llamada desde el marco de datos, puedes attach(V) (aunque personalmente nunca lo hago).

# Initialize values values <- 1:100 # V for variables V <- data.frame(a=NA, b=NA, c=NA, d=NA, e=NA) # Assign elements from a vector V[, c("a", "b", "e")] = values[c(2,4, 8)] # Also other class V[, "d"] <- "R" # Use your variables V$a V$b V$c # OOps, NA V$d V$e


¿Quiere decir que quiere volver a asignar elementos en un vector? Si es así, entonces es justo:

values[c(2,4)] <- c(a, b)


Como otros explicaron, no parece haber nada incorporado ... pero podrías diseñar una función de vassign siguiente manera:

vassign <- function(..., values, envir=parent.frame()) { vars <- as.character(substitute(...())) values <- rep(values, length.out=length(vars)) for(i in seq_along(vars)) { assign(vars[[i]], values[[i]], envir) } } # Then test it vals <- 11:14 vassign(aa,bb,cc,dd, values=vals) cc # 13

Sin embargo, una cosa a tener en cuenta es cómo manejar los casos en los que, por ejemplo, se especifican 3 variables y 5 valores o viceversa. Aquí simplemente repito (o trunco) los valores para que tengan la misma longitud que las variables. Tal vez una advertencia sería prudente. Pero permite lo siguiente:

vassign(aa,bb,cc,dd, values=0) cc # 0


Hay una gran respuesta en el Blog de problemas a través de dificultades

Esto se toma desde allí, con modificaciones muy pequeñas.

USANDO LAS SIGUIENTES TRES FUNCIONES (Más una para permitir listas de diferentes tamaños)

# Generic form ''%=%'' = function(l, r, ...) UseMethod(''%=%'') # Binary Operator ''%=%.lbunch'' = function(l, r, ...) { Envir = as.environment(-1) if (length(r) > length(l)) warning("RHS has more args than LHS. Only first", length(l), "used.") if (length(l) > length(r)) { warning("LHS has more args than RHS. RHS will be repeated.") r <- extendToMatch(r, l) } for (II in 1:length(l)) { do.call(''<-'', list(l[[II]], r[[II]]), envir=Envir) } } # Used if LHS is larger than RHS extendToMatch <- function(source, destin) { s <- length(source) d <- length(destin) # Assume that destin is a length when it is a single number and source is not if(d==1 && s>1 && !is.null(as.numeric(destin))) d <- destin dif <- d - s if (dif > 0) { source <- rep(source, ceiling(d/s))[1:d] } return (source) } # Grouping the left hand side g = function(...) { List = as.list(substitute(list(...)))[-1L] class(List) = ''lbunch'' return(List) }


Entonces para ejecutar:

Agrupe el lado izquierdo con la nueva función g() El lado derecho debe ser un vector o una lista Use el operador binario recién creado %=%

# Example Call; Note the use of g() AND `%=%` # Right-hand side can be a list or vector g(a, b, c) %=% list("hello", 123, list("apples, oranges")) g(d, e, f) %=% 101:103 # Results: > a [1] "hello" > b [1] 123 > c [[1]] [1] "apples, oranges" > d [1] 101 > e [1] 102 > f [1] 103

Ejemplo usando listas de diferentes tamaños:

Lado izquierdo más largo

g(x, y, z) %=% list("first", "second") # Warning message: # In `%=%.lbunch`(g(x, y, z), list("first", "second")) : # LHS has more args than RHS. RHS will be repeated. > x [1] "first" > y [1] "second" > z [1] "first"

Lado derecho más largo

g(j, k) %=% list("first", "second", "third") # Warning message: # In `%=%.lbunch`(g(j, k), list("first", "second", "third")) : # RHS has more args than LHS. Only first2used. > j [1] "first" > k [1] "second"


He intentado la solución de Hadd E. Nuff para el problema similar. Lanza un error "argumento" nm "falta, sin valor predeterminado". Intenté "list2env (setNames (as.list (rep (2,5)), letters [1: 5]), .GlobalEnv)", cumplió mi propósito, es decir, asignar cinco 2s a las primeras cinco letras.


Me temo que la solución elegent que está buscando (como c(a, b) = c(2, 4) ) desafortunadamente no existe. ¡Pero no te rindas, no estoy seguro! La solución más cercana que puedo pensar es esta:

attach(data.frame(a = 2, b = 4))

o si le molestan las advertencias, desactívelas:

attach(data.frame(a = 2, b = 4), warn = F)

Pero supongo que no estás satisfecho con esta solución, yo tampoco estaría ...


Otra versión con recursión:

let <- function(..., env = parent.frame()) { f <- function(x, ..., i = 1) { if(is.null(substitute(...))){ if(length(x) == 1) x <- rep(x, i - 1); stopifnot(length(x) == i - 1) return(x); } val <- f(..., i = i + 1); assign(deparse(substitute(x)), val[[i]], env = env); return(val) } f(...) }

ejemplo:

> let(a, b, 4:10) [1] 4 5 6 7 8 9 10 > a [1] 4 > b [1] 5 > let(c, d, e, f, c(4, 3, 2, 1)) [1] 4 3 2 1 > c [1] 4 > f [1] 1

Mi version:

let <- function(x, value) { mapply( assign, as.character(substitute(x)[-1]), value, MoreArgs = list(envir = parent.frame())) invisible() }

ejemplo:

> let(c(x, y), 1:2 + 3) > x [1] 4 > y [1]


Si su único requisito es tener una sola línea de código, entonces qué tal:

> a<-values[2]; b<-values[4]


Tuve un problema similar recientemente y aquí estaba mi intento de usar purrr::walk2

purrr::walk2(letters,1:26,assign,envir =parent.frame())


Una opción potencialmente peligrosa (en la medida en que la assign sea ​​arriesgada) sería Vectorize assign :

assignVec <- Vectorize("assign",c("x","value")) #.GlobalEnv is probably not what one wants in general; see below. assignVec(c(''a'',''b''),c(0,4),envir = .GlobalEnv) a b 0 4 > b [1] 4 > a [1] 0

O supongo que podría vectorizarlo usted mismo manualmente con su propia función utilizando mapply que quizás use un valor predeterminado razonable para el argumento de envir . Por ejemplo, Vectorize devolverá una función con las mismas propiedades de entorno de assign , que en este caso es namespace:base , o simplemente podría establecer envir = parent.env(environment(assignVec)) .


esta es mi idea Probablemente la sintaxis es bastante simple:

`%tin%` <- function(x, y) { mapply(assign, as.character(substitute(x)[-1]), y, MoreArgs = list(envir = parent.frame())) invisible() } c(a, b) %tin% c(1, 2)

da así:

> a Error: object ''a'' not found > b Error: object ''b'' not found > c(a, b) %tin% c(1, 2) > a [1] 1 > b [1] 2

esto no está bien probado sin embargo.


Arreglé un paquete R de Zeallot para abordar este problema. zeallot incluye un operador ( %<-% ) para desempacar, asignar múltiples y desestructurar. El LHS de la expresión de asignación se genera utilizando llamadas a c() . El RHS de la expresión de asignación puede ser cualquier expresión que devuelva o sea un vector, lista, lista anidada, marco de datos, cadena de caracteres, objeto de fecha u objetos personalizados (suponiendo que exista una implementación de destructure ).

Aquí está la pregunta inicial reelaborada usando zeallot (última versión, 0.0.5).

library(zeallot) values <- c(1, 2, 3, 4) # initialize a vector of values c(a, b) %<-% values[c(2, 4)] # assign `a` and `b` a #[1] 2 b #[1] 4

Para obtener más ejemplos e información, puede consultar la vignette paquete.



R> values = c(1,2,3,4) R> a <- values[2]; b <- values[3]; c <- values[4] R> a [1] 2 R> b [1] 3 R> c [1] 4