Seleccione dinámicamente columnas de marco de datos usando $ y un valor de carácter
Tengo un vector de diferentes nombres de columnas y quiero poder recorrer cada uno de ellos para extraer esa columna de un marco de datos. Por ejemplo, considere el conjunto de datos mtcars
y algunos nombres de variables almacenados en un vector de caracteres cols
. Cuando intento seleccionar una variable mtcars
usando un subconjunto dinámico de cols
, ninguno de estos funciona
cols <- c("mpg", "cyl", "am")
col <- cols[1]
col
# [1] "mpg"
mtcars$col
# NULL
mtcars$cols[1]
# NULL
¿Cómo puedo hacer que estos devuelvan los mismos valores que?
mtcars$mpg
Además, ¿cómo puedo recorrer todas las columnas para cols
obtener los valores en algún tipo de bucle?
for(x in seq_along(cols)) {
value <- mtcars[ order(mtcars$cols[x]), ]
}
No puedes hacer ese tipo de subconjuntos con $
. En el código fuente ( R/src/main/subset.c
) dice:
/*El operador del subconjunto $.
Necesitamos asegurarnos de evaluar solo el primer argumento.
El segundo será un símbolo que debe coincidir, no evaluarse.
*/
¿Segundo argumento? ¡¿Qué?! Debes darte cuenta de que $
, como todo lo demás en R, (incluido, por ejemplo , (
etc. ) es una función que toma argumentos y se evalúa. podría reescribirse como+
^
df$V1
`$`(df , V1)
o de hecho
`$`(df , "V1")
Pero...
`$`(df , paste0("V1") )
...por ejemplo, nunca funcionará, ni nada más que deba evaluarse primero en el segundo argumento. Sólo puede pasar una cadena que nunca se evalúa.
En su lugar, utilice [
(o [[
si desea extraer solo una columna como vector).
Por ejemplo,
var <- "mpg"
#Doesn't work
mtcars$var
#These both work, but note that what they return is different
# the first is a vector, the second is a data.frame
mtcars[[var]]
mtcars[var]
Puede realizar el pedido sin bucles, utilizando do.call
para construir la llamada a order
. A continuación se muestra un ejemplo reproducible:
# set seed for reproducibility
set.seed(123)
df <- data.frame( col1 = sample(5,10,repl=T) , col2 = sample(5,10,repl=T) , col3 = sample(5,10,repl=T) )
# We want to sort by 'col3' then by 'col1'
sort_list <- c("col3","col1")
# Use 'do.call' to call order. Seccond argument in do.call is a list of arguments
# to pass to the first argument, in this case 'order'.
# Since a data.frame is really a list, we just subset the data.frame
# according to the columns we want to sort in, in that order
df[ do.call( order , df[ , match( sort_list , names(df) ) ] ) , ]
col1 col2 col3
10 3 5 1
9 3 2 2
7 3 2 3
8 5 1 3
6 1 5 4
3 3 4 4
2 4 3 4
5 5 1 4
1 2 5 5
4 5 3 5
El uso de dplyr proporciona una sintaxis sencilla para ordenar los marcos de datos
library(dplyr)
mtcars %>% arrange(gear, desc(mpg))
Puede resultar útil utilizar la versión NSE como se muestra aquí para permitir crear dinámicamente la lista de clasificación.
sort_list <- c("gear", "desc(mpg)")
mtcars %>% arrange_(.dots = sort_list)
Si entendí correctamente, tiene un vector que contiene nombres de variables y le gustaría recorrer cada nombre y ordenar su marco de datos por ellos. Si es así, este ejemplo debería ilustrarle una solución. El problema principal en el suyo (el ejemplo completo no está completo, así que no estoy seguro de qué más le falta) es que debería estar en order(Q1_R1000[,parameter[X]])
lugar de order(Q1_R1000$parameter[X])
, ya que el parámetro es un objeto externo que contiene un nombre de variable opuesto a una columna directa. de su marco de datos (cuándo $
sería apropiado).
set.seed(1)
dat <- data.frame(var1=round(rnorm(10)),
var2=round(rnorm(10)),
var3=round(rnorm(10)))
param <- paste0("var",1:3)
dat
# var1 var2 var3
#1 -1 2 1
#2 0 0 1
#3 -1 -1 0
#4 2 -2 -2
#5 0 1 1
#6 -1 0 0
#7 0 0 0
#8 1 1 -1
#9 1 1 0
#10 0 1 0
for(p in rev(param)){
dat <- dat[order(dat[,p]),]
}
dat
# var1 var2 var3
#3 -1 -1 0
#6 -1 0 0
#1 -1 2 1
#7 0 0 0
#2 0 0 1
#10 0 1 0
#5 0 1 1
#8 1 1 -1
#9 1 1 0
#4 2 -2 -2