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?

Brandon Bertelsen
fuente

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)
mdsumner
fuente
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)
Sharon
fuente
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).

Kevin Zarca
fuente
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))
usuario3065757
fuente
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]
Enrique Pérez Herrero
fuente
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
3
library(purrr)
x <- x %>% keep(is.numeric)
Yash Khokale
fuente
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)
usuario1
fuente
2

Otra forma podría ser la siguiente:

#extracting numeric columns from iris datset
(iris[sapply(iris, is.numeric)])
Ayushi
fuente
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)
서영재
fuente
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))
RJMCMC
fuente