不幸的是我被困住了,需要你的帮助。
我正在初始化一个数据框并尝试在循环中用新行填充它。它几乎可以正常工作,只有第一行得到一个" NA"对于row.names值。任何人都可以为此提出解决方案和/或解释为什么会发生这种情况吗?
我在这个问题的答案中使用了f3方法:How to append rows to an R data frame
示例:
df <- data.frame( "Type" = character(),
"AvgError" = numeric(),
"StandardDeviation"= numeric (),
stringsAsFactors=FALSE)
for (i in 1:3){
df[nrow(df) + 1, ]$Type <- paste("Test", as.character(format(round(i, 2), nsmall = 2)))
df[nrow(df), ]$AvgError <- i/10
df[nrow(df), ]$StandardDeviation <- i/100
}
df
Type AvgError StandardDeviation
NA Test 1.00 0.1 0.01
2 Test 2.00 0.2 0.02
3 Test 3.00 0.3 0.03
如果我可以提供更多信息,请发表评论,我会尽力提供。谢谢你的帮助。
编辑:好的,到目前为止的讨论。我理解(之前已经知道)这不是最好的方法,因为它比功能方法慢得多,但在这种情况下执行时间并不重要。 @MrFlick在评论中提供了一种解决方法,只需在末尾重命名row.names(rownames(df)<-1:nrow(df)
)。无论如何这有帮助,但它仍然让我感到不满意,因为它没有治疗原因但只处理症状。
答案 0 :(得分:1)
通过一次附加一行来增加数据帧会使代码效率低下,因为您需要在每次迭代时继续为数据框重新分配整个空间。特别是当您增长到大对象大小时,这可能会导致代码非常慢。您可以在R inferno的第2轮中阅读有关此问题的所有内容。
例如,考虑您的代码与类似的代码,分别计算数据框的每一行,然后在最后将它们组合在一起do.call
和rbind
:
OP <- function(vals) {
df <- data.frame( "Type" = character(),
"AvgError" = numeric(),
"StandardDeviation"= numeric (),
stringsAsFactors=FALSE)
for (i in vals){
df[nrow(df) + 1, ]$Type <- paste("Test", as.character(format(round(i, 2), nsmall = 2)))
df[nrow(df), ]$AvgError <- i/10
df[nrow(df), ]$StandardDeviation <- i/100
}
row.names(df) <- vals
df
}
josilber <- function(vals) {
ret <- do.call(rbind, lapply(vals, function(x) {
data.frame(Type=paste("Test", as.character(format(round(x, 2), nsmall = 2))),
AvgError = x/10,
StandardDeviation = x/100,
stringsAsFactors=FALSE)
}))
ret
}
all.equal(OP(1:10000), josilber(1:10000))
# [1] TRUE
system.time(OP(1:10000))
# user system elapsed
# 17.849 1.325 19.147
system.time(josilber(1:10000))
# user system elapsed
# 4.685 0.027 4.713
等待直到结束每行合并的代码比连续附加到数据帧的代码长4倍的代码快4倍。基本上你已经为内存重新分配引入了15秒的延迟,这与每行计算无关,而且仅适用于10,000行的数据帧。对于长度为20,000的数据帧,浪费的计算最多为64秒:
system.time(OP(1:20000))
# user system elapsed
# 70.755 7.065 77.717
system.time(josilber(1:20000))
# user system elapsed
# 12.502 0.968 13.470
正如评论中所指出的,有更快的方法来构建这些特定的数据框(使用向量化函数一次计算每个变量),但我将我的函数josilber
限制为计算每一行的代码一个接一个地证明追加可能仍会产生重大的性能影响。