如何在循环内的数据框中添加行而不强制所有列都是同一类型?

时间:2016-09-14 14:11:43

标签: r dataframe

假设我想创建一个带有数字列和字符列的数据框:

df<-data.frame()
for(i in 1:26) {
  df<-rbind(df, cbind(x=i, y=toString(i)))
 }
str(df)
'data.frame':   26 obs. of  2 variables:
 $ x: Factor w/ 26 levels "1","2","3","4",..: 1 2 3 4 5 6 7 8 9 10 ...
  ..- attr(*, "names")= chr  "x" "x" "x" "x" ...
 $ y: Factor w/ 26 levels "1","2","3","4",..: 1 2 3 4 5 6 7 8 9 10 ...
  ..- attr(*, "names")= chr  "y" "y" "y" "y" ...
哎呀,我不想要因素。

df2<-data.frame()
for(i in 1:26) {
   df2<-rbind(df2, cbind(x=i, y=toString(i)), stringsAsFactors=FALSE)
  }
str(df2)
'data.frame':   26 obs. of  2 variables:
 $ x: chr  "1" "2" "3" "4" ...
 $ y: chr  "1" "2" "3" "4" ...

现在一切都是一个角色。我可以想出避免这种情况的唯一方法是构造单独的向量,然后在最后形成数据帧:

x<-NULL
y<-NULL
for(i in 1:26) {
  x<-c(x, i)
  y<-c(y, toString(i))
 }
df3<-data.frame(x, y, stringsAsFactors=FALSE)
str(df3)
'data.frame':   26 obs. of  2 variables:
 $ x: int  1 2 3 4 5 6 7 8 9 10 ...
 $ y: chr  "1" "2" "3" "4" ...

但正如您所看到的,这需要额外的代码。如果你有一个包含20列的数据框,你需要在循环之前有20个初始化语句,在循环中需要20个语句来添加到向量。

有没有更简洁的方法来实现这个目标?

2 个答案:

答案 0 :(得分:3)

不要这样做。由于内存管理,在循环中增长对象的速度非常慢。正如评论告诉你的那样,你根本不需要循环遍历行。但是,如果需要执行此操作,则应预先分配向量,将其分配到它们中并在循环之后将它们组合到data.frame中。在循环中使用单独的向量(或者你可以使用向量列表)的原因是data.frame子集分配也很慢。

x <- integer(26)
y <- character(26)
for(i in 1:26) {
  x[i] <- i
  y[i] <- toString(i)
}

df <- data.frame(x, y, stringsAsFactors = FALSE)
str(df)
#'data.frame':  26 obs. of  2 variables:
# $ x: int  1 2 3 4 5 6 7 8 9 10 ...
# $ y: chr  "1" "2" "3" "4" ...

如果你有很多专栏,你至少应该知道他们的课程。然后你可以这样做:

colclasses <- c("integer", "character")
l <- lapply(colclasses, vector, length = 26)
for(i in 1:26) {
  l[[1]][i] <- i
  l[[2]][i] <- toString(i)
}
names(l) <- c("x", "y")
df <- as.data.frame(l, stringsAsFactors = FALSE)

修改

由于您需要简明扼要的内容,请考虑使用lapply

l <- lapply(1:26, function(i) list(x = i, y = toString(i)))
df <- do.call(rbind.data.frame, l)

答案 1 :(得分:-5)

我知道这将被遗忘,但这是我的同事提出的解决方案:

df<-data.frame()
for(i in 1:26) {
    df<-rbind(df, data.frame(x=i, y=toString(i), stringsAsFactors=FALSE))
}
str(df)
'data.frame':   26 obs. of  2 variables:
 $ x: int  1 2 3 4 5 6 7 8 9 10 ...
 $ y: chr  "1" "2" "3" "4" ...

性能可能很差,但这是我正在寻找的那种简洁的解决方案。