首页 文章

创建一个空的data.frame

提问于
浏览
384

我正在尝试初始化没有任何行的data.frame . 基本上,我想为每个列指定数据类型并命名它们,但不会创建任何行作为结果 .

到目前为止我能做的最好的事情是这样的:

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

这会创建一个data.frame,其中包含我想要的所有数据类型和列名的单行,但也会创建一个无用的行,然后需要将其删除 .

有一个更好的方法吗?

14 回答

  • 15

    如果你想声明这样一个包含许多列的 data.frame ,那么手动输入所有列类可能会很麻烦 . 特别是如果你可以使用 rep ,这种方法简单快捷(比其他可以像这样推广的解决方案快15%):

    如果所需的列类位于向量 colClasses 中,则可以执行以下操作:

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

    lapply 将产生一个所需长度的列表,其中每个元素只是一个空的类型向量,如 numeric()integer() .

    setDF 通过引用将 list 转换为 data.frame .

    setnames 通过引用添加所需的名称 .

    速度比较:

    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
    

    它也比以类似方式使用 structure 更快:

    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
    
  • 1

    create an empty data frame ,将所需的行数和列数传入以下函数:

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

    要创建一个空框 while specifying the class of each column ,只需将所需数据类型的向量传递给以下函数:

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

    使用方法如下:

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

    这使:

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

    要确认您的选择,请运行以下命令:

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

    如果您不介意不明确指定数据类型,可以这样做:

    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)
    
  • 20

    如果您 already have an existent data frame ,让我们说 df 具有您想要的列,那么您可以通过删除所有行来创建一个空数据框:

    empty_df = df[FALSE,]
    

    请注意 df 仍包含数据,但 empty_df 不包含 .

    我发现这个问题正在寻找如何创建一个空行的新实例,所以我认为它可能对某些人有帮助 .

  • 10

    我使用以下代码创建了空数据框

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

    并尝试绑定一些行以填充相同如下 .

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

    但它开始提供不正确的列名,如下所示

    X3 X4
    1  3  4
    

    解决方案是将newrow转换为df类型,如下所示

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

    现在使用列名显示正确的数据框,如下所示

    id nobs
    1  3   4
    
  • 0

    如果要创建具有动态名称(变量中的colnames)的空data.frame,这可以帮助:

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

    如果需要,您也可以更改类型 . 喜欢:

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

    只需用空向量初始化它:

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

    这是另一个具有不同列类型的示例:

    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. :

    使用错误类型的空列初始化 data.frame 不会阻止进一步添加具有不同类型列的行 .
    从某种意义上说,这种方法从一开始就具有正确的列类型,因此如果您的代码依赖于某些列类型检查,它甚至可以使用零行的 data.frame .

  • 47

    您无需指定列类型即可完成此操作

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

    假设您的列名称是动态的,您可以创建一个空的行命名矩阵并将其转换为数据框 .

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

    最有效的方法是使用 structure 创建一个类为 "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)
    

    与目前接受的答案相比,这是一个简单的基准:

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

    您可以使用带有空字符串的 read.table 作为输入 text ,如下所示:

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

    或者将 col.names 指定为字符串:

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

    感谢Richard Scriven的改进

  • 70

    只是声明

    table = data.frame()
    

    当你尝试 rbind 第一行时,它将创建列

  • 3

    如果您正在寻找短缺:

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

    所以您不需要单独指定列名 . 在填充数据框之前,您将获得默认的列类型逻辑 .

  • 3

    这个问题没有具体解决我的问题(概述here)但是如果有人想用参数化的列数而不是强制来做这件事:

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

    作为divibisan陈述相关问题,

    ... [强制]发生的原因[当cbinding矩阵及其组成类型]是矩阵只能有一种数据类型 . 当您绑定2个矩阵时,结果仍然是矩阵,因此在转换为data.frame之前,变量都被强制转换为单个类型 .

相关问题