Create an empty data.frame
我正在尝试初始化一个没有任何行的data.frame。基本上,我想为每一列指定数据类型并命名它们,但结果并没有创建任何行。
到目前为止,我能做的最好的事情是:
1 2 3 | df <- data.frame(Date=as.Date("01/01/2000", format="%m/%d/%Y"), File="", User="", stringsAsFactors=FALSE) df <- df[-1,] |
这将创建一个data.frame,其中一行包含我想要的所有数据类型和列名,但也会创建一个无用的行,然后需要删除该行。
有更好的方法吗?
只是用空向量初始化它:
1 2 3 4 | df <- data.frame(Date=as.Date(character()), File=character(), User=character(), stringsAsFactors=FALSE) |
下面是另一个具有不同列类型的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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.:
用错误类型的空列初始化
如果您已经有了一个现有的数据帧,比如说拥有所需列的
1 | empty_df = df[FALSE,] |
注意,
我发现这个问题是在寻找如何创建一个空行的新实例,所以我认为它可能对一些人有帮助。
可以在不指定列类型的情况下执行此操作
1 2 3 | df = data.frame(matrix(vector(), 0, 3, dimnames=list(c(), c("Date","File","User"))), stringsAsFactors=F) |
您可以使用带空字符串的
1 2 3 4 5 6 | colClasses = c("Date","character","character") col.names = c("Date","File","User") df <- read.table(text ="", colClasses = colClasses, col.names = col.names) |
或者将
1 | df <- read.csv(text="Date,File,User", colClasses = colClasses) |
感谢理查德·斯克里文的改进
最有效的方法是使用
1 2 3 4 | structure(list(Date = as.Date(character()), File = character(), User = character()), class ="data.frame") # [1] Date File User # <0 rows> (or 0-length row.names) |
与目前公认的答案相比,要将这一点考虑进去,这里有一个简单的基准:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
如果您正在查找短信息:
1 | read.csv(text="col1,col2") |
所以不需要单独指定列名。在填充数据帧之前,将得到默认的列类型logical。
刚刚宣布
1 | table = data.frame() |
当您尝试使用cx1〔10〕的第一行时,它将创建列
我用以下代码创建了空数据帧
1 | df = data.frame(id = numeric(0), jobs = numeric(0)); |
并尝试绑定一些行来填充相同的内容,如下所示。
1 2 | newrow = c(3, 4) df <- rbind(df, newrow) |
但它开始给出错误的列名,如下所示
1 2 | X3 X4 1 3 4 |
解决方法是将newrow转换为df类型,如下所示
1 2 | newrow = data.frame(id=3, jobs=4) df <- rbind(df, newrow) |
现在,在显示列名称时给出正确的数据框,如下所示
1 2 | id nobs 1 3 4 |
如果不介意显式地指定数据类型,可以这样做:
1 2 3 4 5 6 | 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) |
如果要使用动态名称(变量中的列名称)创建空的data.frame,这有助于:
1 2 3 | names <- c("v","u","w") df <- data.frame() for (k in names) df[[k]]<-as.numeric() |
如果需要,也可以更改类型。像:
1 2 3 4 | names <- c("u","v") df <- data.frame() df[[names[1]]] <- as.numeric() df[[names[2]]] <- as.character() |
若要创建空数据帧,请将所需的行数和列数传入以下函数:
1 2 3 4 | create_empty_table <- function(num_rows, num_cols) { frame <- data.frame(matrix(NA, nrow = num_rows, ncol = num_cols)) return(frame) } |
要在指定每个列的类的同时创建空帧,只需将所需数据类型的向量传递到以下函数中:
1 2 3 4 5 6 7 8 9 10 11 | 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) } |
用途如下:
1 | df <- create_empty_table(3, 3, c('character','logical','numeric')) |
它给出:
1 2 3 4 | X1 X2 X3 1 <NA> NA NA 2 <NA> NA NA 3 <NA> NA NA |
要确认您的选择,请运行以下操作:
1 2 3 4 5 6 7 8 9 10 11 | lapply(df, class) #output $X1 [1]"character" $X2 [1]"logical" $X3 [1]"numeric" |
如果您想用许多列声明这样一个
如果所需的列类位于vector
1 2 | library(data.table) setnames(setDF(lapply(colClasses, function(x) eval(call(x)))), col.names) |
速度比较:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 |
它也比以类似方式使用
1 2 3 4 5 6 7 8 9 10 11 12 | 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 2 | library(data.table) data=data.table(a=numeric(), b=numeric(), c=numeric()) |
这个问题并没有具体解决我的问题(在这里概述),但是如果有人想用参数化的列数来解决这个问题,而不是强制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | > 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在相关问题上所说,
...the reason [coercion] occurs [when cbinding matrices and their constituent types] is that a matrix can only have a
single data type. When you cbind 2 matrices, the result is still a
matrix and so the variables are all coerced into a single type before
converting to a data.frame
假设您的列名是动态的,您可以创建一个名为matrix的空行并将其转换为数据帧。
1 2 | nms <- sample(LETTERS,sample(1:10)) as.data.frame(t(matrix(nrow=length(nms),ncol=0,dimnames=list(nms)))) |