Crea un data.frame vacío

Estoy intentando inicializar un data.frame sin filas. Básicamente, quiero especificar los tipos de datos para cada columna y nombrarlos, pero no tengo ninguna fila creada como resultado.

Lo mejor que he podido hacer hasta ahora es algo así como:

df <- data.frame(Date=as.Date("01/01/2000", format="%m/%d/%Y"), File="", User="", stringsAsFactors=FALSE) df <- df[-1,] 

Lo cual crea un data.frame con una sola fila que contiene todos los tipos de datos y nombres de columna que yo quería, pero también crea una fila inútil que luego necesita ser eliminada.

¿Hay una mejor manera de hacer esto?

Simplemente inicialízalo con vectores vacíos:

 df <- data.frame(Date=as.Date(character()), File=character(), User=character(), stringsAsFactors=FALSE) 

Aquí hay otro ejemplo con diferentes tipos de columnas:

 df <- data.frame(Doubles=double(), Ints=integer(), Factors=factor(), Logicals=logical(), Characters=character(), stringsAsFactors=FALSE) str(df) > str(df) 'data.frame': 0 obs. of 5 variables: $ Doubles : num $ Ints : int $ Factors : Factor w/ 0 levels: $ Logicals : logi $ Characters: chr 

NB:

Inicializar un data.frame con una columna vacía del tipo incorrecto no evita nuevas adiciones de filas que tienen columnas de diferentes tipos.
Este método es un poco más seguro en el sentido de que tendrá los tipos de columna correctos desde el principio, por lo tanto, si su código se basa en alguna comprobación de tipo de columna, funcionará incluso con un data.frame con cero filas.

Si ya tiene un dataframe existente , digamos df que tiene las columnas que desea, entonces puede simplemente crear un dataframe vacío eliminando todas las filas:

 empty_df = df[FALSE,] 

Observe que df todavía contiene los datos, pero empty_df no.

Encontré esta pregunta buscando cómo crear una nueva instancia con filas vacías, así que creo que podría ser útil para algunas personas.

Puede hacerlo sin especificar tipos de columnas

 df = data.frame(matrix(vector(), 0, 3, dimnames=list(c(), c("Date", "File", "User"))), stringsAsFactors=F) 

Puede usar read.table con una cadena vacía para el text entrada de la siguiente manera:

 colClasses = c("Date", "character", "character") col.names = c("Date", "File", "User") df <- read.table(text = "", colClasses = colClasses, col.names = col.names) 

Alternativamente, especificando los col.names como una cadena:

 df <- read.csv(text="Date,File,User", colClasses = colClasses) 

Gracias a Richard Scriven por la mejora

La forma más eficiente de hacerlo es usar la structure para crear una lista que tenga la clase "data.frame" :

 structure(list(Date = as.Date(character()), File = character(), User = character()), class = "data.frame") # [1] Date File User # <0 rows> (or 0-length row.names) 

Para poner esto en perspectiva en comparación con la respuesta actualmente aceptada, aquí hay un punto de referencia simple:

 s <- function() structure(list(Date = as.Date(character()), File = character(), User = character()), class = "data.frame") d <- function() data.frame(Date = as.Date(character()), File = character(), User = character(), stringsAsFactors = FALSE) library("microbenchmark") microbenchmark(s(), d()) # Unit: microseconds # expr min lq mean median uq max neval # s() 58.503 66.5860 90.7682 82.1735 101.803 469.560 100 # d() 370.644 382.5755 523.3397 420.1025 604.654 1565.711 100 

Si buscas acortamiento:

 read.csv(text="col1,col2") 

por lo que no necesita especificar los nombres de las columnas por separado. Obtendrá el tipo de columna predeterminado lógico hasta que complete el dataframe.

Creé un dataframe vacío usando el siguiente código

 df = data.frame(id = numeric(0), jobs = numeric(0)); 

y trató de enlazar algunas filas para poblar el mismo de la siguiente manera.

 newrow = c(3, 4) df <- rbind(df, newrow) 

pero comenzó a dar nombres de columna incorrectos de la siguiente manera

  X3 X4 1 3 4 

La solución a esto es convertir newrow a type df de la siguiente manera

 newrow = data.frame(id=3, jobs=4) df <- rbind(df, newrow) 

ahora da el dataframe correcto cuando se muestra con los nombres de columna de la siguiente manera

  id nobs 1 3 4 

Solo declara

 table = data.frame() 

cuando tratas de rbind la primera línea, creará las columnas

Si desea crear un data.frame vacío con nombres dynamics (colnames en una variable), esto puede ayudar:

 names <- c("v","u","w") df <- data.frame() for (k in names) df[[k]]<-as.numeric() 

También puede cambiar los tipos si lo necesita. me gusta:

 names <- c("u", "v") df <- data.frame() df[[names[1]]] <- as.numeric() df[[names[2]]] <- as.character() 

Si desea declarar un data.frame con tantas columnas, probablemente será un dolor escribir todas las clases de columna a mano. Especialmente si puede hacer uso de rep , este enfoque es fácil y rápido (aproximadamente un 15% más rápido que la otra solución que se puede generalizar de esta manera):

Si las clases de columna deseadas están en un vector colClasses , puede hacer lo siguiente:

 library(data.table) setnames(setDF(lapply(colClasses, function(x) eval(call(x)))), col.names) 

lapply dará como resultado una lista de la longitud deseada, cada elemento de la cual es simplemente un vector vacío como numeric() o integer() .

setDF convierte esta list por referencia a un data.frame .

setnames agrega los nombres deseados por referencia.

Comparación de velocidad:

 classes <- c("character", "numeric", "factor", "integer", "logical","raw", "complex") NN <- 300 colClasses <- sample(classes, NN, replace = TRUE) col.names <- paste0("V", 1:NN) setDF(lapply(colClasses, function(x) eval(call(x)))) library(microbenchmark) microbenchmark(times = 1000, read = read.table(text = "", colClasses = colClasses, col.names = col.names), DT = setnames(setDF(lapply(colClasses, function(x) eval(call(x)))), col.names)) # Unit: milliseconds # expr min lq mean median uq max neval cld # read 2.598226 2.707445 3.247340 2.747835 2.800134 22.46545 1000 b # DT 2.257448 2.357754 2.895453 2.401408 2.453778 17.20883 1000 a 

También es más rápido que usar la structure de una manera similar:

 microbenchmark(times = 1000, DT = setnames(setDF(lapply(colClasses, function(x) eval(call(x)))), col.names), struct = eval(parse(text=paste0( "structure(list(", paste(paste0(col.names, "=", colClasses, "()"), collapse = ","), "), class = \"data.frame\")")))) #Unit: milliseconds # expr min lq mean median uq max neval cld # DT 2.068121 2.167180 2.821868 2.211214 2.268569 143.70901 1000 a # struct 2.613944 2.723053 3.177748 2.767746 2.831422 21.44862 1000 b 

Si no le importa no especificar los tipos de datos explícitamente, puede hacerlo de esta manera:

 headers<-c("Date","File","User") df <- as.data.frame(matrix(,ncol=3,nrow=0)) names(df)<-headers #then bind incoming data frame with col types to set data types df<-rbind(df, new_df) 

Para crear un dataframe vacío , pase el número de filas y columnas necesarias en la siguiente función:

 create_empty_table <- function(num_rows, num_cols) { frame <- data.frame(matrix(NA, nrow = num_rows, ncol = num_cols)) return(frame) } 

Para crear un marco vacío mientras se especifica la clase de cada columna , simplemente pase un vector de los tipos de datos deseados a la siguiente función:

 create_empty_table <- function(num_rows, num_cols, type_vec) { frame <- data.frame(matrix(NA, nrow = num_rows, ncol = num_cols)) for(i in 1:ncol(frame)) { print(type_vec[i]) if(type_vec[i] == 'numeric') {frame[,i] <- as.numeric(df[,i])} if(type_vec[i] == 'character') {frame[,i] <- as.character(df[,i])} if(type_vec[i] == 'logical') {frame[,i] <- as.logical(df[,i])} if(type_vec[i] == 'factor') {frame[,i] <- as.factor(df[,i])} } return(frame) } 

Use de la siguiente manera:

 df <- create_empty_table(3, 3, c('character','logical','numeric')) 

Lo que da:

  X1 X2 X3 1  NA NA 2  NA NA 3  NA NA 

Para confirmar sus elecciones, ejecute lo siguiente:

 lapply(df, class) #output $X1 [1] "character" $X2 [1] "logical" $X3 [1] "numeric" 

Supongamos que los nombres de sus columnas son dynamics, puede crear una matriz vacía con nombre de fila y transformarla en un dataframe.

 nms <- sample(LETTERS,sample(1:10)) as.data.frame(t(matrix(nrow=length(nms),ncol=0,dimnames=list(nms))))