Créer un data.frame vide

J’essaie d’initialiser un data.frame sans lignes. En gros, je souhaite spécifier les types de données pour chaque colonne et les nommer, mais aucune ligne ne doit être créée.

Le mieux que j’ai pu faire jusqu’à présent est quelque chose comme:

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

Ce qui crée un data.frame avec une seule ligne contenant tous les types de données et les noms de colonne que je voulais, mais crée également une ligne inutile qui doit ensuite être supprimée.

Y a-t-il une meilleure manière de faire cela?

Il suffit de l’initialiser avec des vecteurs vides:

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

Voici un autre exemple avec différents types de colonnes:

 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:

L'initialisation d'un data.frame avec une colonne vide du type incorrect n'empêche pas d'autres ajouts de lignes comportant des colonnes de types différents.
Cette méthode est juste un peu plus sûre dans la mesure où vous aurez les types de colonnes corrects dès le début, donc si votre code repose sur une vérification de type de colonne, cela fonctionnera même avec un data.frame avec zéro ligne.

Si vous avez déjà un bloc de données existant , disons df qui a les colonnes souhaitées, vous pouvez simplement créer un bloc de données vide en supprimant toutes les lignes:

 empty_df = df[FALSE,] 

Notez que df contient toujours les données mais que empty_df ne le contient pas.

J’ai trouvé cette question en cherchant comment créer une nouvelle instance avec des lignes vides, donc je pense que cela pourrait être utile pour certaines personnes.

Vous pouvez le faire sans spécifier les types de colonne

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

Vous pouvez utiliser read.table avec une chaîne vide pour le text entrée comme suit:

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

Vous pouvez également spécifier les col.names sous forme de chaîne:

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

Merci à Richard Scriven pour l'amélioration

Le moyen le plus efficace de le faire est d’utiliser la structure pour créer une liste ayant la classe "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) 

Pour mettre cela en perspective par rapport à la réponse actuellement acceptée, voici un repère 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 vous cherchez de l’essoufflement:

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

vous n’avez donc pas besoin de spécifier les noms de colonne séparément. Vous obtenez le type de colonne par défaut logique jusqu’à ce que vous remplissiez le bloc de données.

J’ai créé un bloc de données vide en utilisant le code suivant

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

et essayé de lier certaines lignes pour remplir les mêmes comme suit.

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

mais il a commencé à donner des noms de colonne incorrects comme suit

  X3 X4 1 3 4 

La solution consiste à convertir newrow en df comme suit

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

donne maintenant le bloc de données correct lorsqu'il est affiché avec les noms de colonne comme suit

  id nobs 1 3 4 

Déclarez juste

 table = data.frame() 

quand vous essayez de rbind la première ligne, il va créer les colonnes

Si vous voulez créer un data.frame vide avec des noms dynamics (noms de variable dans une variable), cela peut aider:

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

Vous pouvez également modifier les types si vous en avez besoin. comme:

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

Si vous voulez déclarer un tel data.frame avec beaucoup de colonnes, il sera probablement difficile de taper manuellement toutes les classes de colonnes. Surtout si vous pouvez utiliser rep , cette approche est facile et rapide (environ 15% plus rapide que l’autre solution qui peut être généralisée comme ceci):

Si vos classes de colonne souhaitées se trouvent dans une colClasses vecteur, vous pouvez effectuer les opérations suivantes:

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

lapply donnera une liste de la longueur désirée, dont chaque élément est simplement un vecteur vide comme numeric() ou integer() .

setDF convertit cette list en référence à un data.frame .

setnames ajoute les noms souhaités par référence.

Comparaison de vitesse:

 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 

C'est aussi plus rapide que d'utiliser la structure de la même manière:

 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 cela ne vous dérange pas de ne pas spécifier explicitement les types de données, vous pouvez le faire de cette manière:

 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) 

Pour créer un bloc de données vide , indiquez le nombre de lignes et de colonnes nécessaires dans la fonction suivante:

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

Pour créer un cadre vide en spécifiant la classe de chaque colonne , il suffit de transmettre un vecteur des types de données souhaités avec la fonction suivante:

 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) } 

Utilisez comme suit:

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

Qui donne:

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

Pour confirmer vos choix, exécutez les opérations suivantes:

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

Supposons que vos noms de colonne soient dynamics, vous pouvez créer une masortingce nommée vide et la transformer en un bloc de données.

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