lapply 在大型 data.table 上使用大型列表

Posted

技术标签:

【中文标题】lapply 在大型 data.table 上使用大型列表【英文标题】:lapply with a large list over a large data.table 【发布时间】:2018-03-30 16:47:09 【问题描述】:

我正在处理一个相当大的数据集“mutualhold”(约 170 行),其中包含 16881 个独特投资基金的月度信息,每个基金都有许多不同的持股。

dput(head(mutualhold,5))
structure(list(crsp_portno = c(1003678L, 1003678L, 1003678L, 
1003678L, 1003678L), report_dt = c("31/12/2001", "31/12/2001", 
"31/12/2001", "31/12/2001", "31/12/2001"), eff_dt = c("31/12/2001", 
"31/12/2001", "31/12/2001", "31/12/2001", "31/12/2001"), percent_tna = c(3.88, 
3.47, 2.64, 2.5, 2.48), cusip = c("36960410", "59491810", "30231G10", 
"93114210", "17296710"), permno = c(12060L, 10107L, 11850L, 55976L, 
70519L)), .Names = c("crsp_portno", "report_dt", "eff_dt", "percent_tna", 
"cusip", "permno"), class = c("data.table", "data.frame"), row.names = c(NA, 
-5L), .internal.selfref = <pointer: 0x00000000047d0788>)

dput(tail(mutualhold,5))
structure(list(crsp_portno = c(1050207L, 1050207L, 1050207L, 
1050207L, 1050207L), report_dt = c("30/11/2017", "30/11/2017", 
"30/11/2017", "30/11/2017", "30/11/2017"), eff_dt = c("21/12/2017", 
"21/12/2017", "21/12/2017", "21/12/2017", "21/12/2017"), percent_tna = c(0.03, 
0.03, 0.03, 0.03, 0.02), cusip = c("92553P20", "65122910", "90187B40", 
"05722G100", "G5785G10"), permno = c(91063L, 60986L, 93070L, 
NA, 14011L)), .Names = c("crsp_portno", "report_dt", "eff_dt", 
"percent_tna", "cusip", "permno"), class = c("data.table", "data.frame"
), row.names = c(NA, -5L), .internal.selfref = <pointer: 0x00000000047d0788>)

我的目标是提取列“report_dt”、“cusip”和“percent_tna”“crsp_portno”并将它们存储在一个列表中。最终列表的长度应为 16881,并包含 data.tables,其中包含每个“crsp_portno”的提取值。我的第一个预感是用 lapply 做到这一点,这当然是可能的:

require(data.table)
sample <- list(1003678L, 1050207L)
tnas <- lapply(sample, function(x) mutualhold[crsp_portno %in% x, .(report_dt, percent_tna, cusip)])

这是可行的,但速度很慢,我不知道我是否能够使用结果列表有效地执行进一步的操作。我非常感谢有关执行此类操作的更有效方法的建议,如有必要,我可以提供更大的样本,但此数据不公开,因此很遗憾我无法在此处分享。

【问题讨论】:

【参考方案1】:

编辑:根据@Frank 的建议,您可以在拆分数据表时使用by 而不是f 作为参数名称。

crsp_portno拆分数据

split(x = setDT(mutualhold)[, .(report_dt, cusip, percent_tna, crsp_portno)], by = 'crsp_portno' )

数据:

mutualhold <- structure(list(crsp_portno = c(1003678L, 1003678L, 1003678L, 1003678L, 1003678L), report_dt = c("31/12/2001", "31/12/2001", "31/12/2001", "31/12/2001", "31/12/2001"), eff_dt = c("31/12/2001", "31/12/2001", "31/12/2001", "31/12/2001", "31/12/2001"), percent_tna = c(3.88, 3.47, 2.64, 2.5, 2.48), cusip = c("36960410", "59491810", "30231G10", "93114210", "17296710"), permno = c(12060L, 10107L, 11850L, 55976L, 70519L)), .Names = c("crsp_portno", "report_dt", "eff_dt", "percent_tna", "cusip", "permno"), class = c("data.table", "data.frame"), row.names = c(NA, -5L))
mutualhold <- rbind(mutualhold, structure(list(crsp_portno = c(1050207L, 1050207L, 1050207L, 1050207L, 1050207L), report_dt = c("30/11/2017", "30/11/2017", "30/11/2017", "30/11/2017", "30/11/2017"), eff_dt = c("21/12/2017", "21/12/2017", "21/12/2017", "21/12/2017", "21/12/2017"), percent_tna = c(0.03, 0.03, 0.03, 0.03, 0.02), cusip = c("92553P20", "65122910", "90187B40", "05722G100", "G5785G10"), permno = c(91063L, 60986L, 93070L, NA, 14011L)), .Names = c("crsp_portno", "report_dt", "eff_dt", "percent_tna", "cusip", "permno"), class = c("data.table", "data.frame"), row.names = c(NA, -5L)))

【讨论】:

这太棒了!作为比较:使用 lapply,仅使用 50-100 个 ID 处理完全相同的事情需要更长的时间。使用 split 时,这只是几秒钟的事情。我对 data.table 包的效率感到惊讶,感谢您的快速解决方案:)

以上是关于lapply 在大型 data.table 上使用大型列表的主要内容,如果未能解决你的问题,请参考以下文章

Lapply 随着循环次数的增加而减慢

data.table方式与.SDcols

write.csv 用于大型 data.table

将一行中的项目与所有其他行进行比较,并使用 data.table - R 遍历所有行

无法使用数据表的一部分

R:如何在 data.table 中标记特定时间范围内的观察结果?