superponer - Cómo colocar columnas por nombre en un marco de datos
superponer graficas en r (10)
Aquí hay otra solución que puede ser útil para otros. El siguiente código selecciona un pequeño número de filas y columnas de un conjunto de datos de gran tamaño. Las columnas se seleccionan como en una de las respuestas de juba, excepto que utilizo una función de pegado para seleccionar un conjunto de columnas con nombres que se numeran secuencialmente:
df = read.table(text = "
state county city region mmatrix X1 X2 X3 A1 A2 A3 B1 B2 B3 C1 C2 C3
1 1 1 1 111010 1 0 0 2 20 200 4 8 12 NA NA NA
1 2 1 1 111010 1 0 0 4 NA 400 5 9 NA NA NA NA
1 1 2 1 111010 1 0 0 6 60 NA NA 10 14 NA NA NA
1 2 2 1 111010 1 0 0 NA 80 800 7 11 15 NA NA NA
1 1 3 2 111010 0 1 0 1 2 1 2 2 2 10 20 30
1 2 3 2 111010 0 1 0 2 NA 1 2 2 NA 40 50 NA
1 1 4 2 111010 0 1 0 1 1 NA NA 2 2 70 80 90
1 2 4 2 111010 0 1 0 NA 2 1 2 2 10 100 110 120
1 1 1 3 010010 0 0 1 10 20 10 200 200 200 1 2 3
1 2 1 3 001000 0 0 1 20 NA 10 200 200 200 4 5 9
1 1 2 3 101000 0 0 1 10 10 NA 200 200 200 7 8 NA
1 2 2 3 011010 0 0 1 NA 20 10 200 200 200 10 11 12
", sep = "", header = TRUE, stringsAsFactors = FALSE)
df
df2 <- df[df$region == 2, names(df) %in% c(paste("C", seq_along(1:3), sep=''''))]
df2
# C1 C2 C3
# 5 10 20 30
# 6 40 50 NA
# 7 70 80 90
# 8 100 110 120
Tengo un gran conjunto de datos y me gustaría leer columnas específicas o eliminar todas las demás.
data <- read.dta("file.dta")
Selecciono las columnas que no me interesan:
var.out <- names(data)[!names(data) %in% c("iden", "name", "x_serv", "m_serv")]
y que me gustaría hacer algo como:
for(i in 1:length(var.out)) {
paste("data$", var.out[i], sep="") <- NULL
}
para eliminar todas las columnas no deseadas. ¿Es esta la solución óptima?
Aquí hay una solución rápida para esto. Digamos que tienes un marco de datos X con tres columnas A, B y C:
> X<-data.frame(A=c(1,2),B=c(3,4),C=c(5,6))
> X
A B C
1 1 3 5
2 2 4 6
Si quiero eliminar una columna, diga B, solo use grep en los nombres de columna para obtener el índice de la columna, que luego puede usar para omitir la columna.
> X<-X[,-grep("B",colnames(X))]
Su nuevo marco de datos X sería similar al siguiente (esta vez sin la columna B):
> X
A C
1 1 5
2 2 6
La belleza de grep es que puede especificar varias columnas que coincidan con la expresión regular. Si tuviera X con cinco columnas (A, B, C, D, E):
> X<-data.frame(A=c(1,2),B=c(3,4),C=c(5,6),D=c(7,8),E=c(9,10))
> X
A B C D E
1 1 3 5 7 9
2 2 4 6 8 10
Saque las columnas B y D:
> X<-X[,-grep("B|D",colnames(X))]
> X
A C E
1 1 5 9
2 2 6 10
EDITAR: Teniendo en cuenta la sugerencia grepl de Matthew Lundberg en los comentarios a continuación:
> X<-data.frame(A=c(1,2),B=c(3,4),C=c(5,6),D=c(7,8),E=c(9,10))
> X
A B C D E
1 1 3 5 7 9
2 2 4 6 8 10
> X<-X[,!grepl("B|D",colnames(X))]
> X
A C E
1 1 5 9
2 2 6 10
Si intento eliminar una columna que no existe, no debería ocurrir nada:
> X<-X[,!grepl("G",colnames(X))]
> X
A C E
1 1 5 9
2 2 6 10
Cambié el código a:
# read data
dat<-read.dta("file.dta")
# vars to delete
var.in<-c("iden", "name", "x_serv", "m_serv")
# what I''m keeping
var.out<-setdiff(names(dat),var.in)
# keep only the ones I want
dat <- dat[var.out]
De todos modos, la respuesta de juba es la mejor solución para mi problema!
Debe utilizar la indexación o la función de subset
. Por ejemplo :
R> df <- data.frame(x=1:5, y=2:6, z=3:7, u=4:8)
R> df
x y z u
1 1 2 3 4
2 2 3 4 5
3 3 4 5 6
4 4 5 6 7
5 5 6 7 8
Luego puede usar la función which
y el operador -
en la indexación de columnas:
R> df[ , -which(names(df) %in% c("z","u"))]
x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6
O, mucho más simple, use el argumento de select
de la función de subset
: luego puede usar el operador -
directamente en un vector de nombres de columna, ¡e incluso puede omitir las comillas alrededor de los nombres!
R> subset(df, select=-c(z,u))
x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6
Tenga en cuenta que también puede seleccionar las columnas que desee en lugar de eliminar las demás:
R> df[ , c("x","y")]
x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6
R> subset(df, select=c(x,y))
x y
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6
Intenté eliminar una columna mientras utilizaba el paquete data.table
y obtuve un resultado inesperado. Creo que vale la pena publicar lo siguiente. Sólo una pequeña nota de advertencia.
[Editado por Mateo ...]
DF = read.table(text = "
fruit state grade y1980 y1990 y2000
apples Ohio aa 500 100 55
apples Ohio bb 0 0 44
apples Ohio cc 700 0 33
apples Ohio dd 300 50 66
", sep = "", header = TRUE, stringsAsFactors = FALSE)
DF[ , !names(DF) %in% c("grade")] # all columns other than ''grade''
fruit state y1980 y1990 y2000
1 apples Ohio 500 100 55
2 apples Ohio 0 0 44
3 apples Ohio 700 0 33
4 apples Ohio 300 50 66
library(''data.table'')
DT = as.data.table(DF)
DT[ , !names(dat4) %in% c("grade")] # not expected !! not the same as DF !!
[1] TRUE TRUE FALSE TRUE TRUE TRUE
DT[ , !names(DT) %in% c("grade"), with=FALSE] # that''s better
fruit state y1980 y1990 y2000
1: apples Ohio 500 100 55
2: apples Ohio 0 0 44
3: apples Ohio 700 0 33
4: apples Ohio 300 50 66
Básicamente, la sintaxis de data.table
NO es exactamente la misma que data.frame
. De hecho, hay muchas diferencias, ver Preguntas frecuentes 1.1 y Preguntas frecuentes 2.17. ¡Usted ha sido advertido!
No puedo responder tu pregunta en los comentarios debido a la baja puntuación de reputación.
El siguiente código le dará un error porque la función de pegar devuelve una cadena de caracteres
for(i in 1:length(var.out)) {
paste("data$", var.out[i], sep="") <- NULL
}
Aquí hay una posible solución:
for(i in 1:length(var.out)) {
text_to_source <- paste0 ("data$", var.out[i], "<- NULL") # Write a line of your
# code like a character string
eval (parse (text=text_to_source)) # Source a text that contains a code
}
o simplemente hacer:
for(i in 1:length(var.out)) {
data[var.out[i]] <- NULL
}
No utilice -which()
para esto, es extremadamente peligroso. Considerar:
dat <- data.frame(x=1:5, y=2:6, z=3:7, u=4:8)
dat[ , -which(names(dat) %in% c("z","u"))] ## works as expected
dat[ , -which(names(dat) %in% c("foo","bar"))] ## deletes all columns! Probably not what you wanted...
En su lugar, utilice el subconjunto o el !
función:
dat[ , !names(dat) %in% c("z","u")] ## works as expected
dat[ , !names(dat) %in% c("foo","bar")] ## returns the un-altered data.frame. Probably what you want
He aprendido esto de la experiencia dolorosa. No use en exceso lo which()
!
También puedes probar el paquete dplyr
:
R> df <- data.frame(x=1:5, y=2:6, z=3:7, u=4:8)
R> df
x y z u
1 1 2 3 4
2 2 3 4 5
3 3 4 5 6
4 4 5 6 7
5 5 6 7 8
R> library(dplyr)
R> dplyr::select(df2, -c(x, y)) # remove columns x and y
z u
1 3 4
2 4 5
3 5 6
4 6 7
5 7 8
Primero , puede usar la indexación directa (con vectores booleanos) en lugar de volver a acceder a los nombres de columna si está trabajando con el mismo marco de datos; será más seguro según lo señalado por Ista, y más rápido de escribir y ejecutar. Entonces lo que solo necesitarás es:
var.out.bool <- !names(data) %in% c("iden", "name", "x_serv", "m_serv")
y luego, simplemente reasignar datos:
data <- data[,var.out.bool] # or...
data <- data[,var.out.bool, drop = FALSE] # You will need this option to avoid the conversion to an atomic vector if there is only one column left
Segundo , más rápido de escribir, puede asignar directamente NULL a las columnas que desea eliminar:
data[c("iden", "name", "x_serv", "m_serv")] <- list(NULL) # You need list() to respect the target structure.
Finalmente , puede usar subconjunto (), pero en realidad no se puede usar en el código (incluso el archivo de ayuda advierte sobre él). Específicamente, un problema para mí es que si desea utilizar directamente la función de eliminación de susbset (), debe escribir sin comillas la expresión correspondiente a los nombres de columna:
subset( data, select = -c("iden", "name", "x_serv", "m_serv") ) # WILL NOT WORK
subset( data, select = -c(iden, name, x_serv, m_serv) ) # WILL
Como beneficio adicional , aquí hay un pequeño punto de referencia de las diferentes opciones, que muestra claramente que el subconjunto es el más lento, y que el primer método de reasignación es el más rápido:
re_assign(dtest, drop_vec) 46.719 52.5655 54.6460 59.0400 1347.331
null_assign(dtest, drop_vec) 74.593 83.0585 86.2025 94.0035 1476.150
subset(dtest, select = !names(dtest) %in% drop_vec) 106.280 115.4810 120.3435 131.4665 65133.780
subset(dtest, select = names(dtest)[!names(dtest) %in% drop_vec]) 108.611 119.4830 124.0865 135.4270 1599.577
subset(dtest, select = -c(x, y)) 102.026 111.2680 115.7035 126.2320 1484.174
El código está abajo:
dtest <- data.frame(x=1:5, y=2:6, z = 3:7)
drop_vec <- c("x", "y")
null_assign <- function(df, names) {
df[names] <- list(NULL)
df
}
re_assign <- function(df, drop) {
df <- df [, ! names(df) %in% drop, drop = FALSE]
df
}
res <- microbenchmark(
re_assign(dtest,drop_vec),
null_assign(dtest,drop_vec),
subset(dtest, select = ! names(dtest) %in% drop_vec),
subset(dtest, select = names(dtest)[! names(dtest) %in% drop_vec]),
subset(dtest, select = -c(x, y) ),
times=5000)
plt <- ggplot2::qplot(y=time, data=res[res$time < 1000000,], colour=expr)
plt <- plt + ggplot2::scale_y_log10() +
ggplot2::labs(colour = "expression") +
ggplot2::scale_color_discrete(labels = c("re_assign", "null_assign", "subset_bool", "subset_names", "subset_drop")) +
ggplot2::theme_bw(base_size=16)
print(plt)
df2 <- df[!names(df) %in% c("c1", "c2")]