【发布时间】:2016-09-14 11:08:23
【问题描述】:
我想知道是否有一种方法可以将函数应用于 data.frame 的每一行以保留列类?让我们看一个例子来阐明我的意思:
test <- data.frame(startdate = as.Date(c("2010-03-07", "2013-09-13", "2011-11-12")),
enddate = as.Date(c("2010-03-23", "2013-12-01", "2012-01-05")),
nEvents = c(123, 456, 789))
假设我想通过在 startdate 和 enddate 之间插入所有日期来扩展 data.frame test 并分配这些天的事件数。我的第一次尝试是这样的:
eventsPerDay1 <- function(row) {
n_days <- as.numeric(row$enddate - row$startdate) + 1
data.frame(date = seq(row$startdate, row$enddate, by = "1 day"),
nEvents = rmultinom(1, row$nEvents, rep(1/n_days, n_days)))
}
apply(test, 1, eventsPerDay1)
然而,这是不可能的,因为apply 在test 上调用as.matrix,因此它被转换为字符矩阵并且所有列类都丢失了。
我已经找到了两种解决方法,您可以在下面找到,所以我的问题更多的是哲学性质。
library(magrittr)
############# Workaround 1
eventsPerDay2 <- function(startdate, enddate, nEvents) {
n_days <- as.numeric(enddate - startdate) + 1
data.frame(date = seq(startdate, enddate, by = "1 day"),
nEvents = rmultinom(1, nEvents, rep(1/n_days, n_days)))
}
mapply(eventsPerDay2, test$startdate, test$enddate, test$nEvents, SIMPLIFY = F) %>%
do.call(rbind, .)
############# Workaround 2
seq_along(test) %>%
lapply(function(i) test[i, ]) %>%
lapply(eventsPerDay1) %>%
do.call(rbind, .)
我对变通办法的“问题”如下:
- 解决方法 1:这可能不是最好的理由,但我就是不喜欢
mapply。它与其他*apply函数的签名不同(因为参数的顺序不同),我总觉得for循环会更清晰。 - 解决方法 2:虽然非常灵活,但我认为乍一看并不清楚发生了什么。
那么有谁知道一个函数,它的调用看起来像apply(test, 1, eventsPerDay1) 并且可以工作?
【问题讨论】:
-
如果要保留类,请使用
lapply循环遍历行序列,而不是apply -
@akrun 感谢您的建议,但这不正是我在“解决方法 2”中所做的吗?如果不是,请详细说明您的意思。谢谢!
-
是的,你是对的。我使用
data.table发布了一个解决方案。请检查这是否使它变得更好 -
解决方法 1 是最好的。
apply()用于处理矩阵(如果传入 data.frame,它会通过as.matrix进行转换),矩阵只能有一个原子数据表。不要将apply()与data.frames一起使用。