Soltar columnas del marco de datos por nombre


Tengo un número de columnas que me gustaría eliminar de un marco de datos. Sé que podemos eliminarlos individualmente usando algo como:

df$x <- NULL

Pero esperaba hacer esto con menos órdenes.

También, sé que podría soltar columnas usando indexación de enteros como esta:

df <- df[ -c(1, 3:6, 12) ]

Pero me preocupa que la posición relativa de mis variables pueda cambiar.

Dado lo poderoso que es R, pensé que podría haber una mejor manera de dejar caer cada columna por una.

Author: Henrik, 2011-01-05

19 answers

Puede usar una lista simple de nombres:

DF <- data.frame(
  x=1:10,
  y=10:1,
  z=rep(5,10),
  a=11:20
)
drops <- c("x","z")
DF[ , !(names(DF) %in% drops)]

O, alternativamente, puede hacer una lista de los que mantener y referirse a ellos por su nombre:

keeps <- c("y", "a")
DF[keeps]

EDITAR : Para aquellos que aún no están familiarizados con el argumento drop de la función de indexación, si desea mantener una columna como un marco de datos, haga lo siguiente:

keeps <- "y"
DF[ , keeps, drop = FALSE]

drop=TRUE (o no mencionarlo) soltará dimensiones innecesarias, y por lo tanto devolverá un vector con los valores de la columna y.

 753
Author: Joris Meys,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-26 20:57:39

También está el comando subset, útil si sabes qué columnas quieres:

df <- data.frame(a = 1:10, b = 2:11, c = 3:12)
df <- subset(df, select = c(a, c))

ACTUALIZADO después del comentario de @hadley: Para soltar columnas a, c se puede hacer:

df <- subset(df, select = -c(a, c))
 369
Author: Prasad Chalasani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-08 01:02:57
within(df, rm(x))

Es probablemente más fácil, o para múltiples variables:

within(df, rm(x, y))

O si se trata de data.table s (per Cómo se elimina una columna por nombre en los datos.¿mesa?):

dt[, x := NULL]   # deletes column x by reference instantly

dt[, !"x", with=FALSE]   # selects all but x into a new data.table

O para múltiples variables

dt[, c("x","y") := NULL]

dt[, !c("x", "y"), with=FALSE]

En la versión de desarrollo de data.table (instrucciones de instalación), with = FALSE ya no es necesario:

dt[ , !"x"]
dt[ , !c("x", "y")]
 124
Author: Max Ghenis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:26

Podrías usar %in% así:

df[, !(colnames(df) %in% c("x","bar","foo"))]
 93
Author: Joshua Ulrich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-05 14:40:26

List (NULL) también funciona:

dat <- mtcars
colnames(dat)
# [1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear"
# [11] "carb"
dat[,c("mpg","cyl","wt")] <- list(NULL)
colnames(dat)
# [1] "disp" "hp"   "drat" "qsec" "vs"   "am"   "gear" "carb"
 40
Author: Vincent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-13 20:24:24

Si desea eliminar las columnas por referencia y evitar la copia interna asociada con data.frames, puede usar el paquete data.table y la función :=

Puede pasar los nombres de un vector de caracteres al lado izquierdo del operador :=, y NULL como el RHS.

library(data.table)

df <- data.frame(a=1:10, b=1:10, c=1:10, d=1:10)
DT <- data.table(df)
# or more simply  DT <- data.table(a=1:10, b=1:10, c=1:10, d=1:10) #

DT[, c('a','b') := NULL]

Si desea predefinir los nombres como como vector de caracteres fuera de la llamada a [, envuelva el nombre del objeto en () o {} para forzar que el LHS se evalúe en el ámbito de llamada no como un nombre en el ámbito de aplicación de DT.

del <- c('a','b')
DT <- data.table(a=1:10, b=1:10, c=1:10, d=1:10)
DT[, (del) := NULL]
DT <-  <- data.table(a=1:10, b=1:10, c=1:10, d=1:10)
DT[, {del} := NULL]
# force or `c` would also work.   

También puede usar set, lo que evita la sobrecarga de [.data.table, y también funciona para data.frames!

df <- data.frame(a=1:10, b=1:10, c=1:10, d=1:10)
DT <- data.table(df)

# drop `a` from df (no copying involved)

set(df, j = 'a', value = NULL)
# drop `b` from DT (no copying involved)
set(DT, j = 'b', value = NULL)
 36
Author: mnel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-21 01:17:06

Hay una estrategia potencialmente más poderosa basada en el hecho de que grep() devolverá un vector numérico. Si tiene una larga lista de variables como yo en uno de mis conjuntos de datos, algunas variables que terminan en".Un" y otros que terminan en ".B "y solo quieres los que terminan en".A " (junto con todas las variables que no coinciden con ninguno de los patrones, haga esto:

dfrm2 <- dfrm[ , -grep("\\.B$", names(dfrm)) ]

Para el caso en cuestión, usando el ejemplo de Joris Meys, podría no ser tan compacto, pero sería:

DF <- DF[, -grep( paste("^",drops,"$", sep="", collapse="|"), names(DF) )]
 35
Author: 42-,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-24 16:45:59

Por interés, esto marca una de las extrañas inconsistencias de sintaxis múltiples de R. Por ejemplo, dado un marco de datos de dos columnas:

df <- data.frame(x=1, y=2)

Esto da un marco de datos

subset(df, select=-y)

Pero esto da un vector

df[,-2]

Todo esto se explica en ?[ pero no es exactamente el comportamiento esperado. Bueno, al menos no para mí...

 19
Author: jkeirstead,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-02 18:42:27

Otra dplyr respuesta. Si sus variables tienen alguna estructura de nomenclatura común, puede probar starts_with(). Por ejemplo

library(dplyr)
df <- data.frame(var1 = rnorm(5), var2 = rnorm(5), var3 = rnorm (5), 
                 var4 = rnorm(5), char1 = rnorm(5), char2 = rnorm(5))
df
#        var2      char1        var4       var3       char2       var1
#1 -0.4629512 -0.3595079 -0.04763169  0.6398194  0.70996579 0.75879754
#2  0.5489027  0.1572841 -1.65313658 -1.3228020 -1.42785427 0.31168919
#3 -0.1707694 -0.9036500  0.47583030 -0.6636173  0.02116066 0.03983268
df1 <- df %>% select(-starts_with("char"))
df1
#        var2        var4       var3       var1
#1 -0.4629512 -0.04763169  0.6398194 0.75879754
#2  0.5489027 -1.65313658 -1.3228020 0.31168919
#3 -0.1707694  0.47583030 -0.6636173 0.03983268

Si desea soltar una secuencia de variables en el marco de datos, puede usar :. Por ejemplo, si quieres dejar var2, var3, y todas las variables en el medio, te quedarías con var1:

df2 <- df1 %>% select(-c(var2:var3) )  
df2
#        var1
#1 0.75879754
#2 0.31168919
#3 0.03983268
 19
Author: Pat W.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-22 20:37:02

Otra posibilidad:

df <- df[, setdiff(names(df), c("a", "c"))]

O

df <- df[, grep('^(a|c)$', names(df), invert=TRUE)]
 18
Author: scentoni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-11 19:07:36
DF <- data.frame(
  x=1:10,
  y=10:1,
  z=rep(5,10),
  a=11:20
)
DF

Salida:

    x  y z  a
1   1 10 5 11
2   2  9 5 12
3   3  8 5 13
4   4  7 5 14
5   5  6 5 15
6   6  5 5 16
7   7  4 5 17
8   8  3 5 18
9   9  2 5 19
10 10  1 5 20

DF[c("a","x")] <- list(NULL)

Salida:

        y z
    1  10 5
    2   9 5
    3   8 5
    4   7 5
    5   6 5
    6   5 5
    7   4 5
    8   3 5    
    9   2 5
    10  1 5
 18
Author: Kun Ren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-12 07:37:32

Aquí hay una dplyr manera de hacerlo:

#df[ -c(1,3:6, 12) ]  # original
df.cut <- df %>% select(-col.to.drop.1, -col.to.drop.2, ..., -col.to.drop.6)  # with dplyr::select()

Me gusta esto porque es intuitivo leer y entender sin anotación y robusto para columnas que cambian de posición dentro del marco de datos. También sigue el modismo vectorizado usando - para eliminar elementos.

 16
Author: c.gutierrez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-23 19:16:00

Sigo pensando que debe haber un mejor modismo, pero para restar columnas por nombre, tiendo a hacer lo siguiente:

df <- data.frame(a=1:10, b=1:10, c=1:10, d=1:10)

# return everything except a and c
df <- df[,-match(c("a","c"),names(df))]
df
 10
Author: JD Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-05 17:21:58

Hay una función llamada dropNamed() en el paquete BBmisc de Bernd Bischl que hace exactamente esto.

BBmisc::dropNamed(df, "x")

La ventaja es que evita repetir el argumento data frame y por lo tanto es adecuado para canalizar en magrittr (al igual que los enfoques dplyr):

df %>% BBmisc::dropNamed("x")
 10
Author: krlmlr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-04 14:06:22

Solución de Dplyr

Dudo que esto reciba mucha atención aquí abajo, pero si tienes una lista de columnas que quieres eliminar, y quieres hacerlo en una cadena dplyr utilizo one_of() en la cláusula select:

Aquí hay un ejemplo simple y reproducible:

undesired <- c('mpg', 'cyl', 'hp')

mtcars %>%
  select(-one_of(undesired))

La documentación se puede encontrar ejecutando ?one_of o aquí:

Http://genomicsclass.github.io/book/pages/dplyr_tutorial.html

 9
Author: User632716,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-02 14:02:14

Otra solución si no desea utilizar @hadley de arriba: Si "COLUMN_NAME" es el nombre de la columna que desea soltar:

df[,-which(names(df) == "COLUMN_NAME")]
 6
Author: Nick Keramaris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-25 22:57:20

Más allá de select(-one_of(drop_col_names)) demostrado en respuestas anteriores, hay un par de otras dplyr opciones para soltar columnas usando select() que no implican definir todos los nombres de columna específicos (utilizando los datos de muestra de dplyr starwars para alguna variedad de nombres de columna):

library(dplyr)
starwars %>% 
  select(-(name:mass)) %>%        # the range of columns from 'name' to 'mass'
  select(-contains('color')) %>%  # any column name that contains 'color'
  select(-starts_with('bi')) %>%  # any column name that starts with 'bi'
  select(-ends_with('er')) %>%    # any column name that ends with 'er'
  select(-matches('^f.+s$')) %>%  # any column name matching the regex pattern
  select_if(~!is.list(.)) %>%     # not by column name but by data type
  head(2)

# A tibble: 2 x 2
homeworld species
  <chr>     <chr>  
1 Tatooine  Human  
2 Tatooine  Droid 
 2
Author: sbha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-03 02:11:25

Proporcione el marco de datos y una cadena de nombres separados por comas para eliminar:

remove_features <- function(df, features) {
  rem_vec <- unlist(strsplit(features, ', '))
  res <- df[,!(names(df) %in% rem_vec)]
  return(res)
}

Uso :

remove_features(iris, "Sepal.Length, Petal.Width")

introduzca la descripción de la imagen aquí

 0
Author: Cybernetic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-15 16:51:02

Encuentre el índice de las columnas que desea soltar usando which. Dé a estos índices un signo negativo (*-1). Luego subconjunto en esos valores, que los eliminará del dataframe. Este es un ejemplo.

DF <- data.frame(one=c('a','b'), two=c('c', 'd'), three=c('e', 'f'), four=c('g', 'h'))
DF
#  one two three four
#1   a   d     f    i
#2   b   e     g    j

DF[which(names(DF) %in% c('two','three')) *-1]
#  one four
#1   a    g
#2   b    h
 0
Author: milan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-17 11:42:03