如何在不重复函数调用的情况下为data.frame分配多个列

时间:2013-10-22 21:36:22

标签: r dataframe

为什么这不是一个例子?每行都有相同的值和警告

data <- data.frame(id = 1:10)
slowCall <- function(id) data.frame(b = rep(id, 3), c = runif(3))
data[,c("d", "e")] <- sapply(data$id, function(id) {
 tmp <- slowCall(id)
 list(sum(tmp$b), min(tmp$c))
})

Warning message:
In `[<-.data.frame`(`*tmp*`, , c("d", "e"), value = list(3L, 0.104784948984161,  :
 provided 20 variables to replace 2 variables
print(data)
   id d         e
1   1 3 0.1047849
2   2 3 0.1047849
3   3 3 0.1047849
4   4 3 0.1047849
5   5 3 0.1047849
6   6 3 0.1047849
7   7 3 0.1047849
8   8 3 0.1047849
9   9 3 0.1047849
10 10 3 0.1047849

3 个答案:

答案 0 :(得分:0)

你可以尝试这样的事情。首先,矢量化assign函数(按@Joran的answer here),然后稍微修改代码。

# vectorize
assignVec <- Vectorize("assign",c("x","value"))

library(plyr)
set.seed(1) # this is just here for reproducibility

data <- data.frame(id = 1:10)
slowCall <- function(id) data.frame(b = rep(id, 3), c = runif(3))

# I store this as `tmp` just to make the code below look cleaner
tmp <- mlply(sapply(data$id, function(id) {
    tmp <- slowCall(id)
    list(sum(tmp$b), min(tmp$c))
}), c)

# here's the key part:
data <- within(data, assignVec(c('d','e'), tmp, envir=environment()))

输出:

> data
   id          e  d
1   1 0.26550866  3
2   2 0.20168193  6
3   3 0.62911404  9
4   4 0.06178627 12
5   5 0.38410372 15
6   6 0.49769924 18
7   7 0.38003518 21
8   8 0.12555510 24
9   9 0.01339033 27
10 10 0.34034900 30

注意:我调用plyr::mlply将您的sapply输出放入列表中。

但更简单的答案是将操作的右侧更改为:

data[,c("d", "e")] <- as.data.frame(t(sapply(data$id, function(id) {
 tmp <- slowCall(id)
 list(sum(tmp$b), min(tmp$c))
})))

会给你相同的结果。

答案 1 :(得分:0)

这里的问题是sapply返回的矩阵包含单元素列表而不是数值。将您的list更改为c并转置输出,然后就可以了。

data[, c("d", "e")] <- t(sapply(data$id, function(id) {
  tmp <- slowCall(id)
  c(sum(tmp$b), min(tmp$c))
}))

答案 2 :(得分:0)

这是添加两列不同数据类型(例如字符和数字)的通用方法。它使用列表和转置列表(通过this answer)。

这里,这个答案将保留两个输出的整数和数字类型。

rowwise <- lapply(data$id, function(id) {
  tmp <- slowCall(id)
  list(sum(tmp$b), min(tmp$c))
})
colwise <- lapply(seq_along(rowwise[[1]]), function(i) lapply(rowwise, "[[", i))

data[,c("d", "e")] <- colwise