我正试图根据给定变量的边界值拆分数据帧,计算边界两侧的内容,并输出矩阵(最好是数据帧)。示例代码如下:
set.seed(1)
tdata <- data.frame(a1=rnorm(100, mean=5, sd=2), a2=rep(0:1, length.out=100))
tall <- sapply(1:9, function(x) {
d <- split(tdata, tdata$a1 <= x)
sapply(d, function (y) {
1 - max(table(y$a2)/nrow(y))
})
})
我的结果:
> allErr
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
FALSE 0.4949495 0.4895833 0.4943820 0.4933333 0.4444444 0.4411765 0.3333333
TRUE 0.0000000 0.2500000 0.4545455 0.4800000 0.4347826 0.4696970 0.4705882
[,8] [,9]
FALSE 0.5 0.5
TRUE 0.5 0.5
我的连续变量是tdata$a1
,我想使用1:9
的边界值在2中每次分割数据帧,对分割的每个部分的a2
执行计算,然后返回。
我的问题是:从优雅的角度来看,最好的方法是什么(查看了plyr
解决方案,但无法避免使用第一个),更重要的是,正确使用我可能不知道的其他R函数。我还担心我的解决方案在使用比我目前拥有的数据帧(约10000行)大得多的数据帧时无法很好地扩展。
脑海中浮现出更多的优雅,但这种修改可能会通过拆分索引向量而不是整个数据帧来帮助您的解决方案更好地扩展:
set.seed(1)
tdata <- data.frame(a1=rnorm(100, mean=5, sd=2), a2=rep(0:1, length.out=100))
tall <- sapply(1:9, function(x) {
d <- split(seq_along(tdata$a2), tdata$a1 <= x)
sapply(d, function (y) {
1 - max(table(tdata$a2[y])/length(y))
})
})
这个玩具示例的性能增益相当小,很可能是因为数据帧只有两列。如果您的实际数据帧具有更多列,则拆分索引向量会带来更多好处。
也不确定优雅,但将内部函数分解为fun0a
,将"split lapply"模式分解为tsplit
,然后整个迭代是
fun0a <- function(x, ...)
1 - max(table(x) / length(x))
tsplit <- function(thresh, x, splt, fun, ...)
lapply(split(x, splt <= thresh), fun, ...)
sapply(1:9, tsplit, data$a2, tdata$a1, fun0a)
这使用内部lapply
而不是sapply
,并直接拆分单列数据,而不是通过索引或整个数据帧。tsplit
和外部sapply在类似的情况下可以重复使用,例如,当内部函数实际上依赖于数据帧时,传递索引(在外部sapplly中计算一次)而不是值
fun0b <- function(i, df, ...)
1 - max(table(df[i,"a2"]) / length(i))
with(tdata,
sapply(1:9, tsplit, seq_along(a1), a1, fun0b, tdata))
tsplit
是tapply
,因此可以实现为
tsplit <- function(thresh, x, splt, fun, ...)
tapply(x, splt <= thresh, fun, ...)