为什么这不是一个例子?每行都有相同的值和警告
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
答案 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