我有一个巨大的数据集,在那里我使用数据。表包由于快速计算。有这种类型的数据集:
library(data.table)
library(dplyr)
dt <- data.table(
gr1 = rep(LETTERS[1:2], each = 4),
gr2 = rep(letters[3:6], each = 2),
date1 = as.Date(c('2020-01-01', '2020-02-01', '2020-02-01', '2020-02-04', '2020-01-01', '2020-02-01', '2020-02-01', '2020-02-04')),
date2 = as.Date(c('2020-01-05', '2020-02-05', '2020-02-02', '2020-02-07', '2020-01-05', '2020-02-05', '2020-02-02', '2020-02-07')),
value = 1:8
)
dt
gr1 gr2 date1 date2 value
1: A c 2020-01-01 2020-01-05 1
2: A c 2020-02-01 2020-02-05 2
3: A d 2020-02-01 2020-02-02 3
4: A d 2020-02-04 2020-02-07 4
5: B e 2020-01-01 2020-01-05 5
6: B e 2020-02-01 2020-02-05 6
7: B f 2020-02-01 2020-02-02 7
8: B f 2020-02-04 2020-02-07 8
我想对value
列中与同一个gr1
对应的所有gr2
上的日期(日期范围序列的结果)求和。(gr1
之间的独立计算)。
我的解决方法是:
1.创建包含扩展日期范围(date1
和date2
)的date
列的数据集
dt2 <- dt[, .(gr1, gr2, date = seq(date1, date2, by = 'day'), value), by = 1:nrow(dt)]
1.如果date
存在于每个gr1
的所有gr2
上,则使用Reduce
和intersect
函数found here添加is_shared
列
dt2[, date := as.character(date)]
dt3 <- split(dt2, by = 'gr1') %>% lapply(function(x) {
dates <- Reduce(intersect, x[, .(list(unique(date))), gr2]$V1)
x[, is_shared := date %in% dates][]
}) %>% rbindlist()
dt3
gr1 gr2 date value is_shared
1: A c 2020-01-01 1 FALSE
2: A c 2020-01-02 1 FALSE
3: A c 2020-01-03 1 FALSE
4: A c 2020-01-04 1 FALSE
5: A c 2020-01-05 1 FALSE
6: A c 2020-02-01 2 TRUE
7: A c 2020-02-02 2 TRUE
8: A c 2020-02-03 2 FALSE
9: A c 2020-02-04 2 TRUE
10: A c 2020-02-05 2 TRUE
11: A d 2020-02-01 3 TRUE
12: A d 2020-02-02 3 TRUE
13: A d 2020-02-04 4 TRUE
14: A d 2020-02-05 4 TRUE
15: A d 2020-02-06 4 FALSE
16: A d 2020-02-07 4 FALSE
17: B e 2020-01-01 5 FALSE
18: B e 2020-01-02 5 FALSE
19: B e 2020-01-03 5 FALSE
20: B e 2020-01-04 5 FALSE
21: B e 2020-01-05 5 FALSE
22: B e 2020-02-01 6 TRUE
23: B e 2020-02-02 6 TRUE
24: B e 2020-02-03 6 FALSE
25: B e 2020-02-04 6 TRUE
26: B e 2020-02-05 6 TRUE
27: B f 2020-02-01 7 TRUE
28: B f 2020-02-02 7 TRUE
29: B f 2020-02-04 8 TRUE
30: B f 2020-02-05 8 TRUE
31: B f 2020-02-06 8 FALSE
32: B f 2020-02-07 8 FALSE
1.过滤 * 共享日期 * 并按gr1
计算
dt4 <- dt3[is_shared == TRUE][, .(value = sum(value)), by = .(gr1, date)]
dt4
gr1 date value
1: A 2020-02-01 5
2: A 2020-02-02 5
3: A 2020-02-04 6
4: A 2020-02-05 6
5: B 2020-02-01 13
6: B 2020-02-02 13
7: B 2020-02-04 14
8: B 2020-02-05 14
问题:
dt2
的超大尺寸split
和lapply
步骤导致系统崩溃(15Gb RAM和4Gb交换空间)
可能的优化:
- 避免使用dt2和dt3对象,因为要从日期范围中扩展日期。
- 我尝试使用
.I
来创建按行的日期序列,但是我有一个错误'from' must be of length 1
,所以我更改为1:nrow(dt)
,这会创建一个不必要的名为nrow
的列(在后验计算中删除)。 - 不要将
date
转换为dt2
上的字符类(使用%in%
搜索lapply
时需要 - 编辑:**添加大小写
dt <- data.table(
id1 = c(rep(1, 8), rep(2, 4)),
id2 = rep(c(10, 20, 30), each = 4),
id3 = rep(rep(LETTERS[1:2], each = 2), 3),
gr = rep(1:2, 6),
date1 = as.Date(rep(c('2020-01-01', '2020-01-05'), 6)),
date2 = as.Date(rep(c('2020-01-10', '2020-01-12'), 6)),
value = 1:12
)
dt
id1 id2 id3 gr date1 date2 value
1: 1 10 A 1 2020-01-01 2020-01-10 1
2: 1 10 A 2 2020-01-05 2020-01-12 2
3: 1 10 B 1 2020-01-01 2020-01-10 3
4: 1 10 B 2 2020-01-05 2020-01-12 4
5: 1 20 A 1 2020-01-01 2020-01-10 5
6: 1 20 A 2 2020-01-05 2020-01-12 6
7: 1 20 B 1 2020-01-01 2020-01-10 7
8: 1 20 B 2 2020-01-05 2020-01-12 8
9: 2 30 A 1 2020-01-01 2020-01-10 9
10: 2 30 A 2 2020-01-05 2020-01-12 10
11: 2 30 B 1 2020-01-01 2020-01-10 11
12: 2 30 B 2 2020-01-05 2020-01-12 12
- 目的是:**
- 创建/扩展包含
date1
和date2
之间日期的date
列的数据集 - 对于
id1
-id2
-id3
的每个组合,筛选所有gr
上存在的 * 共享 * 日期 - 将对应的
value
相加
3条答案
按热度按时间omjgkv6w1#
另一种可能的解决方案,与OP和@r2evan的解决方案进行基准测试:
OP溶液
备选方案二:
基准:
数据:
对于“真实的病例”数据:
bxjv4tth2#
试试这个
目前还没有(data.table#2146和data.table#3672)
data.table
-内部unnest函数,这些问题中的讨论表明tidyr::unnest
是高效的-在这一点上足以防止自己跳入一个函数。sbdsn5lh3#
下面的方法使用
data.table
非等值连接和链接来避免任何中间结果的具体化。不确定它是否可能在使用完整大小的data.set时遇到内存问题,但我相信它应该是高性能的。至于基准测试,到目前为止@jblood94 * 所展示的结果(以微秒计)* 通常不太可能代表更大数据集的性能。您提供的数据集非常适合以易于理解的方式演示所需的输入和输出,但生成的合成数据集要大得多,其中包含组计数、日期范围长度、并且与当前数据集类似的总体时间跨度将是真正比较性能所必需的。
下面的代码演示了一种生成任意大数据集的方法,并比较了当前提出的方法,每种方法只运行一次。本答案中概述的
data.table
方法和@jblood94的f2()
解决方案都可以很好地扩展。但是,我注意到不同的方法对这种合成数据给出了不同的结果。我不确定第一次的结果是否“正确”。* 非常确定我遇到了比较OP/@jblood94的问题和答案的不同编辑版本的工件。*另外,另一个例子显示了将日期列转换为
data.table
IDate
类如何略微提高性能。函数定义:
100,000个输入行的基准测试: