我正在尝试避免使用for()
循环来解决我的问题。让我们说我有两个向量,为了简单起见:x1 <- c(1,10,30)
和x2 <- c(11,31,40)
。这些向量包含指向我df
中某些区间的参考点,每个区间都有变量,在这种情况下,每个变量有40个观察值。所以:
df(x1[1]:x2[1])
将成为前十个观察结果。 df(x1[2]:x2[2])
将是接下来的20个观察,最后一个(30,40)代表最后10个。我想计算多个统计数据,例如mean
,std
和variance
,对于每个间隔。 for()
- 循环可以解决问题,但速度非常慢。我正在查看apply
函数,但我似乎无法弄明白。 mean(df[x1:x2])
也没有做到这一点,因为它只取x1
和x2
的第一个值。
有什么建议吗?
- tstev
答案 0 :(得分:2)
我倾向于在data.frame的行上使用apply
(因为任何错误的步骤都会将所有内容转换为字符类)。我必须做一些与您在其他代码中提出的问题非常相似的内容,并且我选择了mapply
。
它有&#34;某事&#34;使用2个(或更多)向量/列表的第一个元素,然后执行相同的&#34;某些事情&#34;与相同的向量/列表的第二个元素等。&#34;东西&#34;当然是由第一个参数定义的 - 一个函数,类似于其他*apply
函数。
set.seed(42)
x1 <- c(1,10,30)
x2 <- c(11,31,40)
df <- as.data.frame(sample(40))
ret <- mapply(function(a,b) df[a:b,], x1, x2)
ret
## [[1]]
## [1] 37 40 11 31 24 19 26 5 22 32 14
## [[2]]
## [1] 32 14 21 27 7 13 36 25 3 38 12 35 23 18 17 2 8 6 29 30 10 15
## [[3]]
## [1] 10 15 39 4 33 1 28 34 9 16 20
从这里开始,应用您想要的任何其他统计摘要是微不足道的:
sapply(ret, function(x) c(mean=mean(x), sd=sd(x)))
## [,1] [,2] [,3]
## mean 23.72727 19.13636 19.00000
## sd 10.95528 11.14107 12.87633
(或者您可以随时扩展mapply
调用以直接调用这些其他函数。)
编辑#1 :
根据@docendo discimus的建议,Map
(mapply
与SIMPLIFY=FALSE
)稍快一些。为了比较:
set.seed(3)
x1 <- c(1,11,31)
x2 <- c(10,30,40)
df1 <- data.frame(V1 = sample(40))
df2 <- df1[,,drop = FALSE]
df3 <- df1[,,drop = FALSE]
grp <- rep(seq_along(x1), (x2-x1) + 1L)
df2 <- cbind(df2, grp)
library(data.table)
library(dplyr)
library(microbenchmark)
microbenchmark(dt=setDT(df1)[, list(mean(V1), sd(V1), var(V1)), by = grp],
dplyr=df2 %>% group_by(grp) %>% summarise_each(funs(mean, sd, var)),
mapplyT=mapply(function(a,b) { x <- df3[a:b,]; c(mean(x), sd(x), var(x)); }, x1, x2, SIMPLIFY=TRUE),
mapplyF=mapply(function(a,b) { x <- df3[a:b,]; c(mean(x), sd(x), var(x)); }, x1, x2, SIMPLIFY=FALSE),
Map=Map(function(a,b) { x <- df3[a:b,]; c(mean(x), sd(x), var(x)); }, x1, x2))
## Unit: microseconds
## expr min lq mean median uq max neval
## dt 925.964 1006.9570 1176.5629 1081.4810 1184.7870 2582.434 100
## dplyr 1843.449 1967.0590 2154.9829 2042.2515 2185.2745 3839.960 100
## mapplyT 208.398 237.8500 272.8850 260.8315 286.2685 511.846 100
## mapplyF 187.424 208.6205 237.6805 225.1320 247.2215 445.801 100
## Map 191.441 215.7610 240.9025 231.6025 258.6005 441.785 100
我明确提供了data.frame的深层副本,因为setDT
修改了data.frame(其效率),但是mapply
和Map
无法应对data.table。 (我将mean
,sd
,var
添加到我的mapply
来电中,以便将苹果与苹果进行比较。)
编辑#2 :
之前的基准测试看起来令人印象深刻且具有决定性,但并未描述呼叫的开销与大数据引擎的效率。这是另一个有更多数据的事情。
当各个子集相当大时 - 即更少&#34;块&#34;来自源data.frame - 性能趋于平衡。在这里,我用k
控制块大小:
n <- 4000
k <- 100
x1 <- c(1, sort(sample(n, size = n/k - 1)))
x2 <- c(x1[-1] - 1, n)
df1 <- data.frame(V1 = sample(n))
df2 <- df1[,,drop = FALSE]
df3 <- df1[,,drop = FALSE]
grp <- rep(seq_along(x1), (x2-x1) + 1L)
df2 <- cbind(df2, grp)
microbenchmark(dt=setDT(df1)[, list(mean(V1), sd(V1), var(V1)), by = grp],
dplyr=df2 %>% group_by(grp) %>% summarise_each(funs(mean, sd, var)),
mapplyT=mapply(function(a,b) { x <- df3[a:b,]; c(mean(x), sd(x), var(x)); }, x1, x2, SIMPLIFY=TRUE),
mapplyF=mapply(function(a,b) { x <- df3[a:b,]; c(mean(x), sd(x), var(x)); }, x1, x2, SIMPLIFY=FALSE),
Map=Map(function(a,b) { x <- df3[a:b,]; c(mean(x), sd(x), var(x)); }, x1, x2))
## Unit: milliseconds
## expr min lq mean median uq max neval
## dt 2.133063 2.297282 2.549046 2.435618 2.655842 4.305396 100
## dplyr 2.145558 2.401482 2.643981 2.552090 2.720102 4.374118 100
## mapplyT 2.599392 2.775883 3.135473 2.926045 3.156978 5.430832 100
## mapplyF 2.498540 2.738398 3.079050 2.882535 3.094057 7.041340 100
## Map 2.624382 2.725680 3.158272 2.894808 3.184869 6.533956 100
但是,如果块大小减少,那么性能已经很好的dplyr
会提前出现:
n <- 4000
k <- 10
x1 <- c(1, sort(sample(n, size = n/k - 1)))
x2 <- c(x1[-1] - 1, n)
df1 <- data.frame(V1 = sample(n))
df2 <- df1[,,drop = FALSE]
df3 <- df1[,,drop = FALSE]
grp <- rep(seq_along(x1), (x2-x1) + 1L)
df2 <- cbind(df2, grp)
microbenchmark(dt=setDT(df1)[, list(mean(V1), sd(V1), var(V1)), by = grp],
dplyr=df2 %>% group_by(grp) %>% summarise_each(funs(mean, sd, var)),
mapplyT=mapply(function(a,b) { x <- df3[a:b,]; c(mean(x), sd(x), var(x)); }, x1, x2, SIMPLIFY=TRUE),
mapplyF=mapply(function(a,b) { x <- df3[a:b,]; c(mean(x), sd(x), var(x)); }, x1, x2, SIMPLIFY=FALSE),
Map=Map(function(a,b) { x <- df3[a:b,]; c(mean(x), sd(x), var(x)); }, x1, x2))
## Unit: milliseconds
## expr min lq mean median uq max neval
## dt 11.494443 12.45187 14.163123 13.716532 14.655883 62.424668 100
## dplyr 2.729696 3.05501 3.286876 3.148276 3.324098 4.832414 100
## mapplyT 25.195579 27.67426 28.488846 28.319758 29.247729 32.897811 100
## mapplyF 25.455742 27.42816 28.713237 28.038622 28.958785 76.587224 100
## Map 25.184870 27.32730 28.737281 28.198155 28.768237 77.830470 100
如果您注意到,dplyr
对于较小的数据集所花费的时间与较大的数据集大致相同。好的。
有三种谎言:谎言,该死的谎言和统计数据。(Benjamin Disraeli)这同样适用于基准测试。
答案 1 :(得分:1)
使用Map
来自each
包的有用plyr
的好机会:
library(plyr)
Map(function(u,v) each(mean, sd, var)(df[u:v,1]), x1, x2)
#[[1]]
# mean sd var
#17.90000 10.15929 103.21111
#[[2]]
# mean sd var
#19.14286 12.18313 148.42857
#[[3]]
# mean sd var
#24.81818 10.78720 116.36364
数据:强>
x1 <- c(1,10,30)
x2 <- c(10,30,40)
set.seed(3)
df <- as.data.frame(sample(40))
答案 2 :(得分:1)
以下是您问题的解决方案:
x1 <- c(1,10,30)
x2 <- c(10,30,40)
df <- as.data.frame(sample(40))
df2 <- data.frame(x1,x2)
apply(df2,1, function(x) mean(df[x[1]:x[2],]))
只需将mean()
替换为sd()
或var()
即可获得标准差或差异。如果na.rm=TRUE
中缺少数据,请不要忘记df
参数。
答案 3 :(得分:1)
也许代替for循环你可以使用两次申请?可以将所需的计算包装到函数中(在我的示例中为compute_mean
),然后可以在x1
和x2
的索引对上调用此函数。鉴于x1
和x2
长度相同,使用lapply很容易
x1 <- c(1,10,30)
x2 <- c(10,30,40)
df <- as.data.frame(sample(40))
compute_mean <- function(df, ind1, ind2, i){
result <- apply( df[c(ind1[i]:ind2[i]), , drop = F], 2, mean )
return(result)
}
unlist(lapply(c(1:length(x1)), function(x){
out <- compute_mean(df = df, ind1 = x1, ind2 = x2, i = x)
return(out)
}))