Я склонен против использования apply
в строках data.frame (поскольку любой неверный шаг преобразует все в класс символов). Мне пришлось сделать что-то очень похожее на то, что вы просите в другом коде, и я выбрал mapply
.
Он делает «что-то» с первым элементом 2 (или более) векторов/списков, затем делает то же самое «что-то» со вторым элементом тех же векторов/списков и т. д. «Что-то», конечно, определяется первым аргумент -- функция, похожая на другие *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:
Предыдущие бенчмарки выглядят впечатляюще и убедительно, но не отображают накладные расходы на вызовы по сравнению с эффективностью механизмов обработки больших данных. Вот еще один опыт с большим количеством данных.
Когда отдельные подмножества довольно велики, т. е. меньше «фрагментов» из исходного 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
заняло примерно столько же времени для меньшего набора данных, как и для большего. Хороший.
Есть три вида лжи: ложь, наглая ложь и статистика. (Бенджамин Дизраэли) Это в равной степени относится и к эталонным тестам.
person
r2evans
schedule
06.02.2015
df <- as.data.frame(sample(40))
- person tstev   schedule 06.02.2015apply
автоматически не ускоряет работу (например, см. than-a-for-loop-in-r" title="почему метод применения медленнее, чем цикл for в r">stackoverflow.com/questions/5533246/). С другой стороны, векторизованные решения, вероятно, будут. - person blindjesse   schedule 06.02.2015