Seleccionar solo columnas numéricas de un marco de datos


189

Supongamos que tiene un data.frame como este:

x <- data.frame(v1=1:20,v2=1:20,v3=1:20,v4=letters[1:20])

¿Cómo seleccionaría solo aquellas columnas en x que son numéricas?

Respuestas:


289

EDITAR: actualizado para evitar el uso de malos consejos sapply.

Como un marco de datos es una lista, podemos usar las funciones de aplicar lista:

nums <- unlist(lapply(x, is.numeric))  

Luego subconjunto estándar

x[ , nums]

## don't use sapply, even though it's less code
## nums <- sapply(x, is.numeric)

Para una R moderna más idiomática, ahora recomendaría

x[ , purrr::map_lgl(x, is.numeric)]

Menos codey, menos reflejo de las peculiaridades particulares de R, y más directo y robusto de usar en tibbles back-end de base de datos:

dplyr::select_if(x, is.numeric)

10
x[nums]o x[sapply(x,is.numeric)]funciona igual de bien. Y siempre regresan data.frame. Compare x[1]vs x[,1]- primero es data.frame, segundo es un vector. Si uno quiere evitar la conversión, entonces debe usar x[, 1, drop=FALSE].
Marek

¿Alguna forma de seleccionar solo datos continuos? Este método devuelve tanto continuo como entero.
Abandonado el

Cuando no hay una columna numérica, surge el siguiente error undefined columns selected. Cómo lo evitas ?
Yohan Obadia

Los datos continuos de @SoilSciGuy deben ser as.numeric. ¿Quizás tenga datos de factores en forma numérica? Deberías abrir una nueva pregunta.
Brandon Bertelsen

1
@YohanObadia Puedes usar a tryCatch()para lidiar con esto. Por favor considere abrir una nueva pregunta.
Brandon Bertelsen

79

La función del paquete dplyr select_if() es una solución elegante:

library("dplyr")
select_if(x, is.numeric)

44

Filter() del paquete base es la función perfecta para ese caso de uso: simplemente tiene que codificar:

Filter(is.numeric, x)

También es mucho más rápido que select_if():

library(microbenchmark)
microbenchmark(
    dplyr::select_if(mtcars, is.numeric),
    Filter(is.numeric, mtcars)
)

devuelve (en mi computadora) una mediana de 60 microsegundos para Filtery 21 000 microsegundos para select_if(350 veces más rápido).


Esta solución no falla cuando no hay columnas numéricas presentes. ¿Hay algún inconveniente en usarlo?
bli

El filtro solo se aplica a las filas de un marco de datos en lugar de a las columnas. Como tal, esta solución no daría el resultado correcto.
Michael

44
¡@Michael no confunda el filtro del paquete base y el filtro del paquete dplyr!
Kevin Zarca

1
@bli No puedo ver ningún inconveniente de usar Filter. Su entrada es un objeto data.frame y devuelve un data.frame
Kevin Zarca

Simplemente repicando aquí como referencia: lo Filter()que no funciona aquí es reemplazar, por ejemplo Filter(is.numeric,iris) <- 0.5*Filter(is.numeric,iris), no funcionará.
Mobeus Zoom

8

en caso de que solo le interesen los nombres de columna, use esto:

names(dplyr::select_if(train,is.numeric))

5

Este es un código alternativo a otras respuestas:

x[, sapply(x, class) == "numeric"]

con un data.table

x[, lapply(x, is.numeric) == TRUE, with = FALSE]

3
Esto es más un comentario a la respuesta seleccionada, en lugar de una respuesta única.
Brandon Bertelsen

2
Las columnas pueden tener más de una clase.
Rich Scriven el


2

La biblioteca PCAmixdata tiene una función splitmix que divide divisiones cuantitativas (datos numéricos) y cualitativas (datos categóricos) de un marco de datos dado "YourDataframe" como se muestra a continuación:

install.packages("PCAmixdata")
library(PCAmixdata)
split <- splitmix(YourDataframe)
X1 <- split$X.quanti(Gives numerical columns in the dataset) 
X2 <- split$X.quali (Gives categorical columns in the dataset)

2

Otra forma podría ser la siguiente:

#extracting numeric columns from iris datset
(iris[sapply(iris, is.numeric)])

1
Hola Ayushi, esto probablemente fue rechazado porque es una repetición de la primera respuesta, pero este método tiene algunos problemas que se identificaron. Mire los comentarios en la primera respuesta, verá lo que quiero decir.
Brandon Bertelsen

1

Si tiene muchas variables de factores, puede usar la select_iffunción. instale los paquetes dplyr. Hay muchas funciones que separan los datos al satisfacer una condición. Puedes establecer las condiciones.

Úselo así.

categorical<-select_if(df,is.factor)
str(categorical)

2
Parece un duplicado de esta respuesta anterior stackoverflow.com/a/40808873/170352
Brandon Bertelsen

0

Esto no responde directamente a la pregunta, pero puede ser muy útil, especialmente si desea algo como todas las columnas numéricas, excepto su columna de identificación y la variable dependiente.

numeric_cols <- sapply(dataframe, is.numeric) %>% which %>% 
                   names %>% setdiff(., c("id_variable", "dep_var"))

dataframe %<>% dplyr::mutate_at(numeric_cols, function(x) your_function(x))
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.