wake-up-neo.net

Erstellen Sie einen leeren data.frame

Ich versuche, ein data.frame ohne Zeilen zu initialisieren. Grundsätzlich möchte ich die Datentypen für jede Spalte angeben und benennen, aber keine Zeilen als Ergebnis erstellen lassen.

Das Beste, was ich bisher konnte, ist so etwas wie:

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

Dadurch wird ein data.frame mit einer einzelnen Zeile erstellt, die alle Datentypen und Spaltennamen enthält, die ich wollte, aber es wird auch eine unbrauchbare Zeile erstellt, die dann entfernt werden muss.

Gibt es einen besseren Weg, dies zu tun?

440
Jeff Allen

Initialisiere es einfach mit leeren Vektoren:

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

Hier ist ein anderes Beispiel mit verschiedenen Spaltentypen:

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 

N.B .:

Das Initialisieren eines data.frame mit einer leeren Spalte des falschen Typs verhindert nicht das weitere Hinzufügen von Zeilen mit Spalten unterschiedlichen Typs.
Diese Methode ist nur ein bisschen sicherer in dem Sinne, dass Sie von Anfang an die richtigen Spaltentypen haben, also Ihren Code stützt sich auf eine Überprüfung des Spaltentyps, sie funktioniert sogar mit einem data.frame mit Nullzeilen.

587
digEmAll

Wenn Sie bereits einen vorhandenen Datenrahmen haben, sagen wir df mit den gewünschten Spalten, dann können Sie einfach einen leeren Datenrahmen erstellen, indem Sie alle Zeilen entfernen:

empty_df = df[FALSE,]

Beachten Sie, dass df immer noch die Daten enthält, empty_df jedoch nicht.

Ich habe diese Frage gefunden, um eine neue Instanz mit leeren Zeilen zu erstellen. Daher denke ich, dass sie für einige Leute hilfreich sein kann.

109
toto_tico

Sie können dies tun, ohne Spaltentypen anzugeben

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

Sie könnten read.table mit einer leeren Zeichenfolge für die Eingabe text wie folgt verwenden:

colClasses = c("Date", "character", "character")
col.names = c("Date", "File", "User")

df <- read.table(text = "",
                 colClasses = colClasses,
                 col.names = col.names)

Alternativ können Sie den col.names als Zeichenfolge angeben:

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

Vielen Dank an Richard Scriven für die Verbesserung

51
Rentrop

Am effizientesten ist es, mit structure eine Liste mit der Klasse "data.frame" zu erstellen:

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

Um dies im Vergleich zur derzeit akzeptierten Antwort zu relativieren, hier ein einfacher Maßstab:

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
22
Thomas

Einfach deklarieren

table = data.frame()

wenn Sie in der ersten Zeile rbind versuchen, werden die Spalten erstellt

18
Daniel Fischer

Wenn Sie nach Kürze suchen:

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

sie müssen die Spaltennamen also nicht separat angeben. Sie erhalten den Standardspaltentyp logisch, bis Sie den Datenrahmen füllen.

16
marc

Ich habe einen leeren Datenrahmen mit folgendem Code erstellt

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

und haben versucht, einige Zeilen zu binden, um sie wie folgt zu füllen.

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

aber es begann, falsche Spaltennamen wie folgt zu vergeben

  X3 X4
1  3  4

Die Lösung hierfür besteht darin, newrow wie folgt in df zu konvertieren

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

gibt nun den korrekten Datenrahmen aus, wenn die Spaltennamen wie folgt angezeigt werden

  id nobs
1  3   4 
10
Shrikant Prabhu

Um einen leeren Datenrahmen zu erstellen, übergeben Sie die Anzahl der benötigten Zeilen und Spalten an die folgende Funktion:

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

Um einen leeren Rahmen zu erstellen während Sie die Klasse jeder Spalte angeben, übergeben Sie einfach einen Vektor der gewünschten Datentypen an die folgende Funktion:

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

Verwenden Sie wie folgt:

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

Welches gibt:

   X1  X2 X3
1 <NA> NA NA
2 <NA> NA NA
3 <NA> NA NA

Führen Sie Folgendes aus, um Ihre Auswahl zu bestätigen:

lapply(df, class)

#output
$X1
[1] "character"

$X2
[1] "logical"

$X3
[1] "numeric"
4
Cybernetic

Wenn Sie einen leeren data.frame mit dynamischen Namen (Spaltennamen in einer Variablen) erstellen möchten, kann dies helfen:

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

Sie können bei Bedarf auch die Typen ändern. mögen:

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

Wenn es Ihnen nichts ausmacht, Datentypen nicht explizit anzugeben, können Sie dies folgendermaßen tun:

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)
3
Odysseus Ithaca

Wenn Sie einen solchen data.frame mit vielen Spalten deklarieren möchten, ist es wahrscheinlich mühsam, alle Spaltenklassen von Hand einzugeben. Insbesondere, wenn Sie rep verwenden können, ist dieser Ansatz einfach und schnell (etwa 15% schneller als die andere Lösung, die wie folgt verallgemeinert werden kann):

Befinden sich Ihre gewünschten Spaltenklassen in einem Vektor colClasses, haben Sie folgende Möglichkeiten:

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

lapply führt zu einer Liste der gewünschten Länge, wobei jedes Element einfach ein leerer typisierter Vektor wie numeric() oder integer() ist.

setDF konvertiert dieses list anhand eines data.frame.

setnames fügt die gewünschten Namen als Referenz hinzu.

Geschwindigkeitsvergleich:

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 

Es ist auch schneller als die Verwendung von structure auf ähnliche Weise:

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
2
MichaelChirico

Mit data.table können wir Datentypen für jede Spalte angeben.

library(data.table)    
data=data.table(a=numeric(), b=numeric(), c=numeric())
1
Rushabh Patel

Sie können auch extrahieren Sie die Metadaten (Spaltennamen und -typen) aus einem Datenrahmen (z. B. wenn Sie einen BUG steuern, der nur bei bestimmten Eingaben ausgelöst wird und einen leeren Dummy-Datenrahmen benötigt ):

colums_and_types <- sapply(df, class)

# prints: "c('col1', 'col2')"
print(dput(as.character(names(colums_and_types))))

# prints: "c('integer', 'factor')"
dput(as.character(as.vector(colums_and_types)))

Verwenden Sie dann den read.table, um den leeren Datenrahmen zu erstellen

read.table(text = "",
   colClasses = c('integer', 'factor'),
   col.names = c('col1', 'col2'))
0
toto_tico

Angenommen, Ihre Spaltennamen sind dynamisch, können Sie eine leere Matrix mit Zeilennamen erstellen und in einen Datenrahmen umwandeln.

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

Diese Frage ging nicht speziell auf meine Bedenken ein (skizziert hier ), aber falls jemand dies mit einer parametrisierten Anzahl von Spalten und ohne Zwang tun möchte:

> require(dplyr)
> dbNames <- c('a','b','c','d')
> emptyTableOut <- 
    data.frame(
        character(), 
        matrix(integer(), ncol = 3, nrow = 0), stringsAsFactors = FALSE
    ) %>% 
    setNames(nm = c(dbNames))
> glimpse(emptyTableOut)
Observations: 0
Variables: 4
$ a <chr> 
$ b <int> 
$ c <int> 
$ d <int>

Wie Divibisan zu der damit verbundenen Frage sagt,

... der Grund, warum [Zwang] auftritt [beim Verknüpfen von Matrizen und ihren konstituierenden Typen], ist, dass eine Matrix nur einen einzigen Datentyp haben kann. Wenn Sie 2 Matrizen binden, ist das Ergebnis immer noch eine Matrix, und daher werden die Variablen vor der Konvertierung in einen data.frame-Typ zu einem einzigen Typ zusammengefasst

0
d8aninja