【发布时间】:2017-06-28 02:23:17
【问题描述】:
我正在尝试从两个较小的数据集模拟一个新数据集。对我来说保持边缘很重要 从最终数据集中这些较小的数据集中计数。希望这个可重现的例子能解释什么 我是说。
构建虚假数据
library(data.table) # 1.10.5
set.seed(123)
meanVal <- 40
demoDat
这里我模拟了一些年龄和性别数据。每个位置总是有 2 个性别级别和 100 个年龄级别。
demoDat <- CJ(with(CJ(letters,letters[1:5]), paste0(V1,V2)), c("M","F"), 0:99)
setnames(demoDat, c("Location","Gender","Age"))
demoDat[, Val := rpois(.N, meanVal)]
Location Gender Age Val
1: aa F 0 36
2: aa F 1 47
3: aa F 2 29
---
25998: ze M 97 45
25999: ze M 98 38
26000: ze M 99 39
时间日期
此代码模拟时间数据维度。在这种情况下,日期按周间隔,但实际数据不必遵守这种统一性。数周可能会丢失。
timeDat <- with(demoDat, CJ(unique(Location), seq(from=as.Date("2016-01-01"),by=7,length.out = 52)))
setnames(timeDat, c("Location","Date"))
totals <- demoDat[, .(Val=sum(Val)), by=.(Location)]
timeDat[totals, Val := rmultinom(1:.N, i.Val, prob=rep(1,.N)), by=.EACHI,on=.(Location)]
Location Date Val
1: aa 2016-01-01 176
2: aa 2016-01-08 143
3: aa 2016-01-15 143
---
6758: ze 2016-12-09 165
6759: ze 2016-12-16 142
6760: ze 2016-12-23 156
快速对账
每个位置都应该有一个 Val 列,在 demoDat 和 timeDat 数据集中总计相同。
timeDat[, sum(Val), by=.(Location)][order(-V1)][1:5]
# Location V1
# 1: jb 8229
# 2: xb 8223
# 3: ad 8179
# 4: nc 8176
# 5: gd 8173
demoDat[, sum(Val), by=.(Location)][order(-V1)][1:5]
# Location V1
# 1: jb 8229
# 2: xb 8223
# 3: ad 8179
# 4: nc 8176
# 5: gd 8173
所需的最终数据集
接下来,我想创建一个包含Age、Gender 和Date 变量的数据集。但我需要从demoDat 和timeDat 数据集中维护我的Val 边际总和。
我有一个策略可以完成这项任务,但它占用了相当多的 RAM。我可以采用另一种策略来一次在每个组内执行扩展吗?也许使用
.EACHI?
扩展两个数据集并合并
这是操作中昂贵的部分。数据集已扩展,因此行数等于sum(Val)。如果sum(Val) 是> 500,000,000,这可能会很昂贵。特别是因为对第二个数据集重复该操作。我希望使用.EACHI,这样只会扩展组内的数据,这应该会大大降低内存占用。
library(pryr)
memUsed <- mem_used()
demoDatBig <- demoDat[rep(1:.N, Val), .(Location, Gender, Age, ID=rowid(Location))]
timeDatBig <- timeDat[rep(1:.N, Val), .(Location, Date, ID=rowid(Location))]
demoDatBig[timeDatBig, Date := i.Date, on=.(Location, ID)]
finalBigDat <- demoDatBig[, .(Val=.N), by=.(Location, Gender, Age, Date)]
mem_used() - memUsed
# 47 MB
所以这个操作占用了 47 MB 的 RAM,但是如果我增加 meanVal,它会显着增加。我希望在最大的Location 和ID 组上使用与此操作相同的功能所需的尽可能多的 RAM。我认为使用.EACHI 可以做到这一点,但我不确定如何。
结果数据表
Location Gender Age Date Val
1: aa F 0 2016-01-01 36
2: aa F 1 2016-01-01 47
3: aa F 2 2016-01-01 29
4: aa F 3 2016-01-01 40
5: aa F 4 2016-01-01 24
---
32430: ze M 96 2016-12-16 7
32431: ze M 96 2016-12-23 34
32432: ze M 97 2016-12-23 45
32433: ze M 98 2016-12-23 38
32434: ze M 99 2016-12-23 39
该解决方案有望通过这些测试
#### Test 1
test1 <- finalBigDat[, .(Val = sum(Val)), by=.(Location, Gender, Age)]
test1[demoDat, ValCheck := i.Val, on=.(Location, Gender, Age)]
test1[Val != ValCheck]
#Empty data.table (0 rows) of 5 cols: Location,Gender,Age,Val,ValCheck
#### Test 2
test2 <- finalBigDat[, .(Val = sum(Val)), by=.(Location, Date)]
test2[timeDat, ValCheck := i.Val, on=.(Location, Date)]
test2[Val != ValCheck]
#Empty data.table (0 rows) of 4 cols: Location,Date,Val,ValCheck
结果
我浏览了这两种解决方案并跟踪了两者的内存和系统时序。这两种解决方案都很棒,并且是对我目前拥有的解决方案的巨大升级。 @swihart 的解决方案可以难以置信地扩展到大 meanVal,所以我选择了这个作为接受的答案。当meanVal 没有那么大时,Heather 的回答会有所帮助。大大小小的meanVal 都经常出现,所以我都需要。
meanVal Ans Time Mem Rows
1: 40 Mike.Gahan 0.6245470 secs 44.54293 32434
2: 40 Heather Turner 0.6391492 secs 38.65355 1352000
3: 40 swihart 11.1602619 secs 66.97550 1352000
4: 400 Mike.Gahan 2.593275 secs 437.23832 32611
5: 400 Heather Turner 1.303993 secs 38.79871 1352000
6: 400 swihart 11.736836 secs 66.97550 1352000
7: 4000 Mike.Gahan 30.390986 secs 4364.51501 32629
8: 4000 Heather Turner 6.279249 secs 38.79871 1352000
9: 4000 swihart 11.427965 secs 66.97550 1352000
10: 20000 Mike.Gahan -------did not finish----------
11: 20000 Heather Turner 23.78948 secs 36.30617 1352000
12: 20000 swihart 11.53811 secs 66.97550 1352000
13: 30000 Mike.Gahan -------did not finish----------
14: 30000 Heather Turner 537.6459 secs 57.15375 1352000
15: 30000 swihart 11.970013 secs 66.97474 1352000
【问题讨论】:
-
请在“占用相当多的内存”上填写数字,您希望提高多少? 10%? 90%?特别是请隔离哪一行中的哪个表达式正在浪费 RAM。请参阅有关内存分析的现有问题。如果需要,您可以随时使用 HDFS 等磁盘支持的存储。
-
meanVal应该是 40,而不是 400,对吗? -
是的..每个位置总是有 2 个性别级别和 100 个年龄级别。
-
没有。时间点不会遵守网格。
-
您对上面的语言不清楚 - 占用 RAM 的不是进程(本身) - 最终对象正在占用 RAM。
?mem_used显示 R 当前正在使用的内存,而不是给定进程使用的最大内存量。这也可以通过在您的“大”data.tables 上使用object.size来验证 - 您会看到它们正在占用您的内存。那么 - 您是想让创建行为更高效,还是希望生成的对象占用更少的 RAM?
标签: r performance memory data.table