dplyr::跨性能和dplyr::汇总到data.table效率
dplyr::跨性能和dplyr::汇总到data.table效率,r,dplyr,data.table,out-of-memory,R,Dplyr,Data.table,Out Of Memory,dplyr不喜欢我的大数据集,因此我尝试将以下简单代码转换为最有效的数据。表等效: library(tidyverse) data(iris) iris$year <- rep(c(2000, 3000), each = 25) iris$color <- rep(c("red", "green","blue"), each = 50) iris$letter <- as.factor(rep(c("A&
dplyr
不喜欢我的大数据集,因此我尝试将以下简单代码转换为最有效的数据。表
等效:
library(tidyverse)
data(iris)
iris$year <- rep(c(2000, 3000), each = 25)
iris$color <- rep(c("red", "green","blue"), each = 50)
iris$letter <- as.factor(rep(c("A", "B", "C"), each = 50))
head(iris, 3)
iris %>%
group_by(Species, year) %>%
summarise(across(c(-Sepal.Length, -Sepal.Width), dplyr::first),
across(c(Sepal.Length, Sepal.Width), dplyr::last)) %>%
ungroup
库(折叠)
运行时非常令人印象深刻!很好的概述。对于数据。表
,我们可以使用
nm1 <- c("Petal.Length", "Petal.Width", "color", "letter")
nm2 <- c("Sepal.Length", "Sepal.Width")
as.data.table(iris)[, c(lapply(.SD[, nm1, with = FALSE], first),
lapply(.SD[, nm2, with = FALSE], last)), .(Species, year)]
或者另一个选项是
collapse
library(collapse)
collap(iris, ~ Species + year, custom = list(ffirst = nm1, flast = nm2))
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species year color letter
#1 4.8 3.4 1.4 0.2 setosa 2000 red A
#2 5.0 3.3 1.6 0.2 setosa 3000 red A
#3 6.4 2.9 4.7 1.4 versicolor 2000 green B
#4 5.7 2.8 4.4 1.4 versicolor 3000 green B
#5 6.7 3.3 6.0 2.5 virginica 2000 blue C
#6 5.9 3.0 6.0 1.8 virginica 3000 blue C
使用
data.table
,我们可以使用
nm1 <- c("Petal.Length", "Petal.Width", "color", "letter")
nm2 <- c("Sepal.Length", "Sepal.Width")
as.data.table(iris)[, c(lapply(.SD[, nm1, with = FALSE], first),
lapply(.SD[, nm2, with = FALSE], last)), .(Species, year)]
或者另一个选项是
collapse
library(collapse)
collap(iris, ~ Species + year, custom = list(ffirst = nm1, flast = nm2))
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species year color letter
#1 4.8 3.4 1.4 0.2 setosa 2000 red A
#2 5.0 3.3 1.6 0.2 setosa 3000 red A
#3 6.4 2.9 4.7 1.4 versicolor 2000 green B
#4 5.7 2.8 4.4 1.4 versicolor 3000 green B
#5 6.7 3.3 6.0 2.5 virginica 2000 blue C
#6 5.9 3.0 6.0 1.8 virginica 3000 blue C
1)sqldfsqldf
可以通过指定外部数据库名称(请参见下面使用的dbname=
参数)在R之外执行计算,以便中间计算的R内存限制不会影响它。您也可以在不使用dbname=
参数的情况下尝试它,以防您确实有足够的内存
library(sqldf)
# enclose each argument in [...] and then create comma separated string
varString <- function(...) toString(sprintf("[%s]", c(...)))
firstVar <- varString("Petal.Length", "Petal.Width", "color", "letter")
lastVar <- varString("Sepal.Length", "Sepal.Width")
byVar <- varString("Species", "year")
fn$sqldf("
with first_data as (select min(rowid), $byVar, $firstVar from iris group by $byVar),
last_data as (select max(rowid), $byVar, $lastVar from iris group by $byVar)
select $byVar, $firstVar, $lastVar from first_data left join last_data using($byVar)
", dbname = tempfile())
2)Base R此解决方案仅使用Base R。为每个物种和年份组合计算唯一密钥的行可能需要修改以用于其他数据
key <- as.integer(iris$Species) + as.integer(iris$year)
i <- !duplicated(key)
j <- !duplicated(key, fromLast = TRUE)
data.frame(
iris[i, c("Species", "year", "Petal.Length", "Petal.Width")],
iris[j, c("Sepal.Length", "Sepal.Width")]
)
key1)sqldfsqldf
可以通过指定外部数据库名称(请参见下面使用的dbname=
参数)在R之外执行计算,以便中间计算的R内存限制不会影响它。您也可以在不使用dbname=
参数的情况下尝试它,以防您确实有足够的内存
library(sqldf)
# enclose each argument in [...] and then create comma separated string
varString <- function(...) toString(sprintf("[%s]", c(...)))
firstVar <- varString("Petal.Length", "Petal.Width", "color", "letter")
lastVar <- varString("Sepal.Length", "Sepal.Width")
byVar <- varString("Species", "year")
fn$sqldf("
with first_data as (select min(rowid), $byVar, $firstVar from iris group by $byVar),
last_data as (select max(rowid), $byVar, $lastVar from iris group by $byVar)
select $byVar, $firstVar, $lastVar from first_data left join last_data using($byVar)
", dbname = tempfile())
2)Base R此解决方案仅使用Base R。为每个物种和年份组合计算唯一密钥的行可能需要修改以用于其他数据
key <- as.integer(iris$Species) + as.integer(iris$year)
i <- !duplicated(key)
j <- !duplicated(key, fromLast = TRUE)
data.frame(
iris[i, c("Species", "year", "Petal.Length", "Petal.Width")],
iris[j, c("Sepal.Length", "Sepal.Width")]
)
key谢谢,如果使用这种方法分组只有一行,我想不会有问题?@user63230使用lappy
和by
是一种标准方法。唯一的区别是,我们通过对lappy的两个调用来组合两组列,然后连接(c
)仍然在我的真实数据集上运行的输出,这令人惊讶,因为它没有那么大(~300万行80列)。我感觉我的数据可能有问题。我现在得走了,但我会回来的it@user63230尝试使用一个lappy
并检查它是否快速,即out1collapse
非常出色,请参见上面的计时。我很惊讶dplyr
版本甚至无法完成。谢谢,如果使用此方法分组只有一行,我想不会有任何问题?@user63230使用lapply
和by
是一种标准方法。唯一的区别是,我们通过对lappy的两个调用来组合两组列,然后连接(c
)仍然在我的真实数据集上运行的输出,这令人惊讶,因为它没有那么大(~300万行80列)。我感觉我的数据可能有问题。我现在得走了,但我会回来的it@user63230尝试使用一个lappy
并检查它是否快速,即out1collapse
非常出色,请参见上面的计时。我很惊讶dplyr
版本甚至无法完成。感谢此解决方案,请参阅上面的计时注意,问题指出问题在于数据的大小,而不是速度。我认为是数据集的大小导致dplyr
速度变慢。运行+15小时后,rstudio被中止。当我尝试一个稍微简单一点的版本时,只需调用summary\u at
,我就试着运行它,这会让我的整个电脑慢下来,我不得不杀死它。数据没有此类问题。table
collapse
或sqldf
添加了一个基本的R解决方案。感谢此解决方案,请参阅上面的计时注意,问题指出问题在于数据的大小,而不是速度。我认为是数据集的大小导致了dplyr
变慢。运行+15小时后,rstudio被中止。当我尝试一个稍微简单一点的版本时,只需调用summary\u at
,我就试着运行它,这会让我的整个电脑慢下来,我不得不杀死它。数据没有此类问题。表
折叠
或sqldf
添加了一个基本的R解决方案。您能否提供完整的再现性基准测试代码。请注意,当我使用问题中的数据对sqldf进行基准测试时,没有bname的sqldf的运行速度是df的两倍。因为我不能包含真实数据,很难完全复制,但我已经包含了microbenchmark
代码,在sqldf中最后出现的真实数据应该是答案中的最后一个数据。修复了,这是一个输入错误!能否提供完整的再现性基准测试代码。请注意,当我使用问题中的数据对sqldf进行基准测试时,没有bname的sqldf的运行速度是df的两倍。因为我不能包含真实数据,很难完全复制,但我已经包含了microbenchmark
代码,在sqldf中最后出现的真实数据应该是答案中的最后一个数据。修复了,这是一个输入错误!