r

¿Cuál es la forma más eficiente de seleccionar un conjunto de nombres de variables de un R data.frame?



(5)

¿Quieres decir select ?

sub_df = subset(df, select=c("v1","v2","v3"))

El problema:

A menudo necesito seleccionar un conjunto de variables de un data.frame en R. Mi investigación está en las ciencias sociales y del comportamiento, y es bastante común tener un data.frame con varios cientos de variables (por ejemplo, habrá información de nivel de elemento para una variedad de preguntas de encuesta, elementos demográficos, medidas de rendimiento, etc., etc.).

Como parte de los análisis, a menudo deseo seleccionar un subconjunto de variables. Por ejemplo, podría querer obtener:

  • estadísticas descriptivas para un conjunto de variables
  • matriz de correlación en un conjunto de variables
  • análisis factorial en un conjunto de variables
  • predictores en un modelo lineal

Ahora, sé que hay muchas maneras de escribir el código para seleccionar un subconjunto de variables. Quick-r tiene una buena visión general de las formas comunes de extraer subconjuntos variables de un data.frame .

p.ej,

myvars <- c("v1", "v2", "v3") newdata <- mydata[myvars]

Sin embargo, estoy interesado en la eficiencia de este proceso, particularmente donde podría necesitar extraer aproximadamente 20 variables de un data.frame. La convención de nomenclatura de las variables a menudo no es intuitiva, especialmente cuando has heredado un conjunto de datos de otra persona, por lo que es posible que te preguntes si la variable Gender , gender , sex , GENDER , gender1 , etc. Multiplica esto por 20 variables que necesita ser extraído, y la tarea de memorizar nombres de variables se vuelve más complicada de lo que necesita ser.

Ejemplo concreto

Para hacer concreta la siguiente discusión, bfi archivo bfi data.frame en el paquete psych .

library(psych) data(bfi) df <- bfi head(df, 1) A1 A2 A3 A4 A5 C1 C2 C3 C4 C5 E1 E2 E3 E4 E5 N1 N2 N3 N4 N5 O1 O2 O3 O4 61617 2 4 3 4 4 2 3 3 4 4 3 3 3 4 4 3 4 2 2 3 3 6 3 4 O5 gender education age 61617 3 1 NA 16

  • ¿Cómo puedo seleccionar eficientemente un conjunto arbitrario de variables, que para ser más concreto, elegiré A1, A2, A3, A5, C2, C3, C5, E2, E3, gender, education, age ?

Mi estrategia actual

Actualmente tengo una variedad de estrategias que utilizo. Por supuesto, a veces puedo explotar cosas como la posición numérica de las variables o la convención de nomenclatura y usar grep para seleccionar o paste para construir. Pero a veces necesito una solución más general. He usado lo siguiente a lo largo del tiempo:

1. nombres (df)

En los primeros días, solía llamar a los names(df) , copiar los nombres de las variables citadas y luego editar hasta que tenga lo que quiero.

2. Usa una base de datos

A veces tendré un data.frame separado que almacena cada variable como una fila, y tiene columnas para nombres de variables, etiquetas de variables, y tiene una columna que indica si la variable debe ser retenida para un análisis en particular. Luego puedo filtrar esa variable de include y extraer un vector de nombres de variables. Encuentro esto particularmente útil cuando estoy desarrollando una prueba psicológica y para varias iteraciones quiero incluir o excluir ciertos elementos.

3. dput (nombres (df))

Como Hadley Wickham una vez me señaló que el dput es una buena opción; por ejemplo, dput(names(df)) es mejor que names(df) en que emite una lista que ya está en el formato c("var1", "var2", ...) :

dput(names(df)) c("A1", "A2", "A3", "A4", "A5", "C1", "C2", "C3", "C4", "C5", "E1", "E2", "E3", "E4", "E5", "N1", "N2", "N3", "N4", "N5", "O1", "O2", "O3", "O4", "O5", "gender", "education", "age")

Esto se puede copiar en el script y editar.

Pero puede ser más eficiente

Supongo que el dput es una estrategia de selección de variables bastante buena. La eficiencia del proceso depende en gran medida de lo competente que sea copiando el texto en su secuencia de comandos y luego editando la lista de nombres a los que desee.

Sin embargo, todavía recuerdo la eficacia de los sistemas basados ​​en GUI de selección de variables. Por ejemplo, en SPSS cuando interactúa con un cuadro de diálogo puede señalar y hacer clic con el mouse en las variables que desea del conjunto de datos. Puede presionar la tecla Mayús para seleccionar un rango de variables, puede mantener presionada la tecla Mayús y presionar la tecla hacia abajo para seleccionar una o más variables, y así sucesivamente. Y luego puede presionar Paste y el comando con nombres de variables extraídos se pega en el editor de scripts.

Entonces, finalmente, la pregunta central

  • ¿Hay un simple dispositivo GUI sin adornos que permite la selección de variables de un data.frame (por ejemplo, algo como guiselect(df) abre una ventana gui para la selección de variables), y devuelve un vector de nombres de variables seleccionado c("var1", "var2", ...) ?
  • ¿Es el dput la mejor opción general para seleccionar un conjunto de nombres de variables en R? ¿O hay un mejor camino?

Actualización (abril de 2017): He publicado mi propio entendimiento de una buena estrategia a continuación .


Personalmente soy fanático de los myvars <- c(...) y luego uso mydf[,myvars] de allí en adelante.

Sin embargo, esto todavía requiere que ingrese los nombres de las variables iniciales (aunque solo sea una vez), y por lo que leí su pregunta, es por este ''nombre de variable de selección'' inicial que es lo que está preguntando.

En un sencillo dispositivo GUI sin adornos: recientemente me presentaron la función de menu , que es exactamente un simple dispositivo GUI sin adornos para seleccionar un objeto de una lista de opciones. Pruebe el menu(names(df),graphics=TRUE) para ver a qué me refiero (devuelve el número de columna). Incluso ofrece una buena interfaz de texto si por alguna razón su sistema no puede hacer los gráficos (intente con graphics=FALSE para ver a qué me refiero).

Sin embargo, esto es de uso limitado para usted, ya que solo puede seleccionar un nombre de columna. Para seleccionar múltiples , puede usar select.list (mencionado en el ?menu Como la alternativa para hacer selecciones múltiples):

# example with iris data (I don''t have ''psych'' package): vars <- select.list(names(iris),multiple=TRUE, title=''select your variable names'', graphics=TRUE)

Esto también toma una opción graphics=TRUE (haga un solo clic en todos los elementos que desee seleccionar). Devuelve los nombres de las variables.


Puede usar select.list() , como este:

DF <- data.frame(replicate(26,list(rnorm(5)))) names(DF) <- LETTERS subDF <- DF[select.list(names(DF), multiple=TRUE)]


Si desea un método que ignore el caso de las variables y quizás elija las variables en función de sus "troncos", utilice el patrón de expresiones regulares apropiado e ignore.case- = TRUE y value = TRUE con grep:

dfrm <- data.frame(var1=1, var2=2, var3=3, THIS=4, Dont=5, NOTthis=6, WANTthis=7) unlist(sapply( c("Want", "these", "var"), function(x) grep(paste("^", x,sep=""), names(dfrm), ignore.case=TRUE, value=TRUE) )) #---------------- Want var1 var2 var3 # Names of the vector "WANTthis" "var1" "var2" "var3" # Values matched > dfrm[desired] WANTthis var1 var2 var3 1 7 1 2 3


Utilizo la siguiente estrategia para hacer la selección de variables en R eficiente.

Usa metadatos para almacenar nombres de variables

Tengo marcos de datos con una fila por variable para ciertos conjuntos de variables. Por ejemplo, podría tener una prueba de personalidad de 100 ítems. Los metadatos incluyen el nombre de la variable en R junto con toda la información de puntuación (por ejemplo, si el ítem se invierte, etc.). A continuación, puedo extraer nombres de variables para los elementos y los nombres de escala de estos metadatos.

Almacenar conjuntos de variables en una lista nombrada

En cada proyecto, tengo una lista llamada v que almacena conjuntos de variables con nombre. Luego, en cualquier análisis que requiera un conjunto de variables, puedo referirme a la lista nombrada. Esto también hace que el código sea más confiable, porque si los nombres de las variables cambian también lo hacen todos sus análisis contingentes. También es bueno para crear consistencia en cómo se ordenan las variables.

Aquí hay un ejemplo simple:

v <- list() v$neo_items <- meta.neo$id v$ds14_items <- meta.ds14$id v$core_items <- c(v$neo_items, v$ds14_items) v$typed_scales <- c("na", "si") v$typed_all <- c("typed_continuous_sum", "na", "si") v$neo_facets <- sort(unique(meta.neo$facet)) v$neo_factors <- c("agreeableness", "conscientiousness", "extraversion", "neuroticism", "openness") v$outcomes_scales <- c("healthbehavior", "socialsupport", "physical_symptoms", "psychological_symptoms")

Algunos puntos se pueden ver en el ejemplo anterior:

  • A menudo, las listas de variables se generarán a partir de los metadatos que he almacenado por separado. Entonces, por ejemplo, tengo los nombres de variable para los 240 itms de la prueba de neo personalidad almacenada en meta.neo$id
  • En algunos casos, los nombres de variables se pueden derivar de metadatos. Por ejemplo, una de las columnas en mis metadatos para una prueba de personalidad indica a qué escala pertenece el elemento, y los nombres de las variables se derivan de esa columna tomando el valor unique de esa columna.
  • En algunos casos, los conjuntos de variables son la combinación de conjuntos más pequeños. Por ejemplo, puede tener un conjunto de predictores, un conjunto de resultados y un conjunto que combine predictores y resultados. La división en predictores y resultados podría ser útil para algunos modelos de regresión, y el conjunto combinado podría ser útil para una matriz de correlación o un análisis factorial.
  • Para más listas ad hoc de variables, todavía uso dput(names(df) donde df es mi data.frame para generar el vector de nombres de caracteres que luego se almacena en una lista de variables.
  • Estas listas de variables generalmente se colocan después de que cargues tus datos, pero antes de consumirlos. De esta forma, pueden usarse para la preparación de datos, y ciertamente están disponibles cuando comienzas a ejecutar análisis (por ejemplo, modelos predictivos, correlaciones, estadísticas descriptivas, etc.).
  • La belleza de las listas de variables es que puedes usar autocoplamientos en RStudio. Por lo tanto, no necesita recordar los nombres de las variables ni los nombres de las listas de variables. Simplemente escriba v$ y presione tab o v$ y alguna parte del nombre de la lista.

Usando listas de variables

Usar listas de variables es bastante directo, pero algunas funciones en R especifican los nombres de las variables de manera diferente.

El escenario simple y estándar implica suministrar la lista de nombres de variables al subconjunto data.frame. Por ejemplo,

cor(data[,v$mylist]) cor(data[,v$predictors], data[,v$outcomes])

Es un poco más complicado para las funciones que requieren fórmulas. Puede necesitar escribir una función. Por ejemplo:

v <- list() v$predictors <- c("cyl", "disp") f <- as.formula(paste("mpg ~", paste(v$predictors, collapse = " + "))) lm(f, mtcars)

También puede usar listas de variables en funciones como sapply y lapply (y presumiblemente los equivalentes tidyverse). Por ejemplo,

Crea una tabla descriptiva de estadísticas con:

sapply(mydata[, v$outcomes], function(X) c(mean = mean(X), sd = sd(X)))

dput sigue siendo útil

Para las variables ad hoc o incluso cuando solo está escribiendo el código para crear una lista de variables, la dput sigue siendo muy útil.

El código estándar es dput(names(df)) donde df es su data.frame. Así por ejemplo:

dput(names(mtcars))

Produce

c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear", "carb")

Luego puede editar esta cadena para extraer las variables que necesita. Esto tiene el beneficio adicional de que reduce los errores de tipeo en su código. Y este es un punto realmente importante. No quiere perder mucho tiempo tratando de depurar código que fue simplemente el resultado de un error tipográfico. Además, el mensaje de error Rs al escribir incorrectamente un nombre de variable es horrible. Solo dice "columnas indefinidas seleccionadas". No te dice qué nombres de variables estaban equivocados.

Si tiene una gran cantidad de variables, también puede usar un rango de funciones de búsqueda de cadenas para extraer un subconjunto de los nombres de las variables:

Por ejemplo

> library(psych) > dput(names(bfi)) #all items c("A1", "A2", "A3", "A4", "A5", "C1", "C2", "C3", "C4", "C5", "E1", "E2", "E3", "E4", "E5", "N1", "N2", "N3", "N4", "N5", "O1", "O2", "O3", "O4", "O5", "gender", "education", "age") > dput(grep("^..$", names(bfi), value = TRUE)) # two letter variable names c("A1", "A2", "A3", "A4", "A5", "C1", "C2", "C3", "C4", "C5", "E1", "E2", "E3", "E4", "E5", "N1", "N2", "N3", "N4", "N5", "O1", "O2", "O3", "O4", "O5") > dput(grep("^E.$", names(bfi), value = TRUE)) # E items c("E1", "E2", "E3", "E4", "E5") > dput(grep(".5$", names(bfi), value = TRUE)) # 5th items c("A5", "C5", "E5", "N5", "O5")

Limpiar nombres de variables existentes y usar una convención de nomenclatura

Cuando recibo un archivo de datos de otra persona, los nombres de las variables a menudo carecen de convenciones o usan convenciones que hacen que trabajar con las variables sea menos útil en R. Algunas reglas que uso:

  • hacer que todas las variables estén en minúsculas (tener que pensar en variables de mayúsculas y minúsculas es simplemente molesto)
  • hacer que los nombres de variables sean intrínsecamente significativos (algunos otros programas utilizan etiquetas de variables para almacenar datos significativos; R realmente no usa etiquetas)
  • Mantenga las variables a una longitud apropiada (es decir, no demasiado largas). Hasta 10 caracteres está bien. Más de 20 se pone molesto.

Todos estos pasos generalmente hacen que la selección de variables sea más fácil porque hay menos inconsistencias para recordar.

Utilice la terminación de tabulación para nombres de variables individuales

Para las variables individuales, generalmente utilizo la autocompletación desde el marco de datos. Por ejemplo, df$ y presione la pestaña.

Intento usar un estilo de codificación que me permita usar la autocompletación tanto como sea posible. No me gustan las funciones que requieren que sepa el nombre de la variable sin utilizar autocompletar. Por ejemplo, al subconjunto de un data.frame, prefiero

df[ df$sample == "control", ]

a

subset(df, sample == "control")

porque puedo autocompletar el nombre de la variable "muestra" en el ejemplo superior, pero no en el segundo.