mtcars - ¿Cómo se eliminan las columnas de un data.frame?
r data frame mtcars (11)
No tanto ''¿Cómo ...?'' pero más ''¿Cómo PUEDES ...?''
Si tiene un archivo que alguien le da con 200 columnas, y desea reducirlo a las pocas que necesita para el análisis, ¿cómo lo hace? ¿Una solución ofrece beneficios sobre otra?
Suponiendo que tenemos un marco de datos con columnas col1, col2 a col200. Si solo quería 1-100 y luego 125-135 y 150-200, podría:
dat$col101 <- NULL
dat$col102 <- NULL # etc
o
dat <- dat[,c("col1","col2",...)]
o
dat <- dat[,c(1:100,125:135,...)] # shortest probably but I don''t like this
o
dat <- dat[,!names(dat) %in% c("dat101","dat102",...)]
¿Me falta algo más? Sé que esto es visualmente subjetivo, pero es una de esas cosas esenciales en las que puedes sumergirte y empezar a hacerlo de una manera y caer en el hábito cuando hay formas mucho más eficientes. Muy parecido a esta pregunta sobre which .
EDITAR:
¿O existe una forma fácil de crear un vector viable de nombres de columna? name (dat) no los imprime con comas intermedias, que necesita en los ejemplos de código anteriores, por lo que si imprime los nombres de esa manera, tiene espacios en todas partes y tiene que poner comas manualmente ... ¿Hay alguna comando que le dará "col1", "col2", "col3", ... como resultado para que pueda obtener fácilmente lo que desea?
A veces me gusta hacer esto usando identificadores de columna en su lugar.
df <- data.frame(a=rnorm(100),
b=rnorm(100),
c=rnorm(100),
d=rnorm(100),
e=rnorm(100),
f=rnorm(100),
g=rnorm(100))
as.data.frame (nombres (df))
names(df)
1 a
2 b
3 c
4 d
5 e
6 f
7 g
Eliminando las columnas "c" y "g"
df[,-c(3,7)]
Esto es especialmente útil si tiene data.frames que son grandes o tienen nombres de columna largos que no desea escribir. O nombres de columnas que siguen un patrón, porque entonces puedes usar seq () para eliminar.
RE: tu edición
No necesariamente tiene que poner "" alrededor de una cadena, ni "," para crear un vector de caracteres. Encuentro este pequeño truco útil:
x <- unlist(strsplit(
''A
B
C
D
E'',"/n"))
De http://www.statmethods.net/management/subset.html
# exclude variables v1, v2, v3
myvars <- names(mydata) %in% c("v1", "v2", "v3")
newdata <- mydata[!myvars]
# exclude 3rd and 5th variable
newdata <- mydata[c(-3,-5)]
# delete variables v3 and v5
mydata$v3 <- mydata$v5 <- NULL
Pensé que era realmente inteligente hacer una lista de "no incluir"
La función select()
de dplyr es potente para subconjunto de columnas. Ver ?select_helpers
para obtener una lista de enfoques.
En este caso, donde tiene un prefijo común y números secuenciales para los nombres de columna, puede usar num_range
:
library(dplyr)
df1 <- data.frame(first = 0, col1 = 1, col2 = 2, col3 = 3, col4 = 4)
df1 %>%
select(num_range("col", c(1, 4)))
#> col1 col4
#> 1 1 4
De manera más general, puede usar el signo menos en select()
para soltar columnas, como:
mtcars %>%
select(-mpg, -wt)
Finalmente, a su pregunta "¿hay alguna manera fácil de crear un vector viable de nombres de columna?" - Sí, si necesita editar una lista de nombres manualmente, use dput
para obtener una lista citada y separada por comas que pueda manipular fácilmente:
dput(names(mtcars))
#> c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am",
#> "gear", "carb")
Para eliminar columnas individuales, solo dat$x <- NULL
.
Para eliminar varias columnas, pero menos de aproximadamente 3-4, usaré dat$x <- dat$y <- dat$z <- NULL
.
Para más que eso, usaré un subset
, con nombres negativos (!):
subset(mtcars, , -c(mpg, cyl, disp, hp))
Para los tipos de archivos grandes que tiendo a obtener, generalmente ni siquiera haría esto en R. Usaría el comando cut
en Linux para procesar los datos antes de que lleguen a R. Esto no es una crítica de R, solo una preferencia por usar algunas herramientas Linux muy básicas como grep, tr, cut, sort, uniq y ocasionalmente sed & awk (o Perl) cuando hay algo que hacer con las expresiones regulares.
Otra razón para utilizar los comandos estándar de GNU es que puedo devolverlos a la fuente de los datos y solicitarles que filtren previamente los datos para que no obtenga datos extraños. La mayoría de mis colegas son competentes con Linux, menos conocen R.
(Actualizado) Un método que me gustaría usar antes de tiempo es emparejar mmap
con un archivo de texto y examinar los datos in situ , en lugar de leerlo en RAM. He hecho esto con C, y puede ser increíblemente rápido.
Para mayor claridad, a menudo uso el argumento de selección en el subset
. Con las personas más nuevas, aprendí que mantener la cantidad de comandos que necesitan para reducir al mínimo ayuda a la adopción. A medida que aumenten sus habilidades, también lo hará su capacidad de codificación. Y el subconjunto es uno de los primeros comandos que le muestro a las personas cuando necesitan seleccionar datos dentro de un criterio dado.
Algo como:
> subset(mtcars, select = c("mpg", "cyl", "vs", "am"))
mpg cyl vs am
Mazda RX4 21.0 6 0 1
Mazda RX4 Wag 21.0 6 0 1
Datsun 710 22.8 4 1 1
....
Estoy seguro de que esto probará más lento que la mayoría de las otras soluciones, pero rara vez estoy en el punto donde los microsegundos hacen la diferencia.
Puede usar la función setdiff
:
Si hay más columnas para guardar que eliminar: suponga que desea eliminar 2 columnas, digamos col1, col2 desde un data.frame DT; puedes hacer lo siguiente:
DT<-DT[,setdiff(names(DT),c("col1","col2"))]
Si hay más columnas para eliminar que mantener: suponga que desea mantener solo col1 y col2:
DT<-DT[,c("col1","col2")]
Si ya tiene un vector de nombres, que hay varias formas de crear, puede usar fácilmente la función de subconjunto para guardar o soltar un objeto.
dat2 <- subset(dat, select = names(dat) %in% c(KEEP))
En este caso, KEEP es un vector de nombres de columna que está pre-creado. Por ejemplo:
#sample data via Brandon Bertelsen
df <- data.frame(a=rnorm(100),
b=rnorm(100),
c=rnorm(100),
d=rnorm(100),
e=rnorm(100),
f=rnorm(100),
g=rnorm(100))
#creating the initial vector of names
df1 <- as.matrix(as.character(names(df)))
#retaining only the name values you want to keep
KEEP <- as.vector(df1[c(1:3,5,6),])
#subsetting the intial dataset with the object KEEP
df3 <- subset(df, select = names(df) %in% c(KEEP))
Lo que resulta en:
> head(df)
a b c d
1 1.05526388 0.6316023 -0.04230455 -0.1486299
2 -0.52584236 0.5596705 2.26831758 0.3871873
3 1.88565261 0.9727644 0.99708383 1.8495017
4 -0.58942525 -0.3874654 0.48173439 1.4137227
5 -0.03898588 -1.5297600 0.85594964 0.7353428
6 1.58860643 -1.6878690 0.79997390 1.1935813
e f g
1 -1.42751190 0.09842343 -0.01543444
2 -0.62431091 -0.33265572 -0.15539472
3 1.15130591 0.37556903 -1.46640276
4 -1.28886526 -0.50547059 -2.20156926
5 -0.03915009 -1.38281923 0.60811360
6 -1.68024349 -1.18317733 0.42014397
> head(df3)
a b c e
1 1.05526388 0.6316023 -0.04230455 -1.42751190
2 -0.52584236 0.5596705 2.26831758 -0.62431091
3 1.88565261 0.9727644 0.99708383 1.15130591
4 -0.58942525 -0.3874654 0.48173439 -1.28886526
5 -0.03898588 -1.5297600 0.85594964 -0.03915009
6 1.58860643 -1.6878690 0.79997390 -1.68024349
f
1 0.09842343
2 -0.33265572
3 0.37556903
4 -0.50547059
5 -1.38281923
6 -1.18317733
Solo dirigiéndome a la edición.
@nichoops, no necesita los nombres de las columnas en un vector de caracteres delimitado por comas. Estás pensando en esto al revés. Cuando tu lo hagas
vec <- c("col1", "col2", "col3")
estás creando un vector de caracteres. El ,
simplemente separa los argumentos tomados por la función c()
cuando defines ese vector. names()
y funciones similares devuelven un vector de caracteres de nombres.
> dat <- data.frame(col1 = 1:3, col2 = 1:3, col3 = 1:3)
> dat
col1 col2 col3
1 1 1 1
2 2 2 2
3 3 3 3
> names(dat)
[1] "col1" "col2" "col3"
Es mucho más fácil y menos propenso a errores seleccionar los elementos de los names(dat)
que procesar su salida a una cadena separada por comas que puede cortar y pegar.
Digamos que queremos columnas col1
y col2
, names(dat)
subconjuntos names(dat)
, que solo conservan los que queremos:
> names(dat)[c(1,3)]
[1] "col1" "col3"
> dat[, names(dat)[c(1,3)]]
col1 col3
1 1 1
2 2 2
3 3 3
Puedes hacer lo que quieras, pero R siempre imprimirá el vector en la pantalla entre comillas "
:
> paste(''"'', names(dat), ''"'', sep = "", collapse = ", ")
[1] "/"col1/", /"col2/", /"col3/""
> paste("''", names(dat), "''", sep = "", collapse = ", ")
[1] "''col1'', ''col2'', ''col3''"
entonces este último puede ser más útil. Sin embargo, ahora tienes que cortar y pasar de esa cuerda. Es mucho mejor trabajar con objetos que devuelven lo que desea y usar rutinas de subconjuntos estándar para mantener lo que necesita.
Utilice read.table con instancias colClasses de "NULL" para evitar crearlas en primer lugar:
## example data and temp file
x <- data.frame(x = 1:10, y = rnorm(10), z = runif(10), a = letters[1:10], stringsAsFactors = FALSE)
tmp <- tempfile()
write.table(x, tmp, row.names = FALSE)
(y <- read.table(tmp, colClasses = c("numeric", rep("NULL", 2), "character"), header = TRUE))
x a
1 1 a
2 2 b
3 3 c
4 4 d
5 5 e
6 6 f
7 7 g
8 8 h
9 9 i
10 10 j
unlink(tmp)
Utilizo el data.table ''s :=
para eliminar columnas instantáneamente independientemente del tamaño de la tabla.
DT[, coltodelete := NULL]
o
DT[, c("col1","col20") := NULL]
o
DT[, (125:135) := NULL]
o
DT[, (variableHoldingNamesOrNumbers) := NULL]
Cualquier solución que use <-
o un subset
copiará toda la tabla. data.table ''s :=
simplemente modifica el vector interno de punteros a las columnas, en su lugar. Esa operación es por lo tanto (casi) instantánea.