我需要从 R中的一系列大型向量(实际上是数据帧列,但我认为这不相关)中创建频率表。当我运行时cache.set
,内存使用量稳步攀升,直到系统耗尽内存, R 崩溃并重新启动(16GB)。矢量本身非常大(5.9m obs),但显然远不及16gb - 我不太明白为什么table()
使用了这么多的记忆。我从bigtable包中尝试过table()
,从plyr尝试bigtabulate()
,但没有区别。我写了自己的小功能(下图),但速度非常慢。有没有一种不同的做法比我粗略的尝试更快但没有使用count()
或table()
那么多的内存?
count()
答案 0 :(得分:0)
我创建了一个示例向量并运行table
。这代表标准
set.seed(1)
# this works with 16 GB
V <- sample(1:100, 6e6, replace=TRUE)
table(V)
# V
# 1 2 3 4 5 6 7 8 9 10 11 12 13
# 59851 60360 60662 60097 59978 59894 60252 60106 60075 59636 59926 60069 60007
# 14 15 16 17 18 19 20 21 22 23 24 25 26
# 59576 60052 59912 59804 59861 59737 59903 60055 59877 60259 60090 59856 60660
# 27 28 29 30 31 32 33 34 35 36 37 38 39
# 60157 60137 59653 60323 59649 60017 59616 60060 60004 60116 60157 60360 59860
# 40 41 42 43 44 45 46 47 48 49 50 51 52
# 59957 59892 59813 59986 60009 60457 59875 59464 59806 60302 60002 59938 60079
# 53 54 55 56 57 58 59 60 61 62 63 64 65
# 59876 59940 60059 60245 59949 60089 59942 60001 59973 60661 60157 60210 60189
# 66 67 68 69 70 71 72 73 74 75 76 77 78
# 59770 59948 60333 59601 60353 59344 60089 60316 59529 59617 59694 59969 59790
# 79 80 81 82 83 84 85 86 87 88 89 90 91
# 59743 60141 59975 59990 59658 60147 60389 60472 60111 60094 60102 60050 59612
# 92 93 94 95 96 97 98 99 100
# 59911 60022 60228 59780 60153 59691 60041 59992 59810
请尝试以下操作来拆分数据并汇总列表结果
L <- split(V, rep(1:10, each=(6e6/10)))
# you could use as well: cut(V, breaks=10)
# in place of rep(...)
Ts <- lapply(L, table) # table of each split
# merge results
merge_tables <- function(L) {
require(dplyr)
DF <- do.call(rbind, lapply(L, data.frame))
ans <- DF %>%
group_by(Var1) %>%
summarise(Freq = sum(Freq))
return(ans)
}
merge_tables(Ts)
# A tibble: 100 x 2
# Var1 Freq
# <fctr> <int>
# 1 1 59851
# 2 2 60360
# 3 3 60662
# 4 4 60097
# 5 5 59978
# 6 6 59894
答案 1 :(得分:0)
由于您正在处理data.frame
,因此您可以循环使用tabulate()
代替table()
。 tabulate()
通常要快得多。由于您提到自己遇到内存问题,因此可以使用简单的for
循环。
以下是100列data.frame
的示例,其中包含590万行。
set.seed(1)
mydf <- data.frame(replicate(100, sample(100, 59e5, TRUE, prob = (1 / 1:100)/sum(1/1:100))))
使用预期唯一值的数量创建一个空向量。在这里,我将其硬编码为100,但您可以通过不同方式有效地找到它。
x <- vector(mode = "integer", length = 100)
使用for
循环和tabulate
,在每次迭代时将值添加到向量中。
for (i in seq_along(mydf)) {
a <- tabulate(mydf[[i]], nbins = 100)
x <- x + a
}
结果如下:
x
# [1] 113728224 56869605 37921007 28438216 22749305 18957822 16246750 14217145 12635554 11371434
# [11] 10336993 9476935 8754409 8127218 7580889 7108428 6688372 6318092 5988240 5685836
# [21] 5420640 5167806 4949677 4742169 4552045 4375381 4213460 4062181 3918424 3791238
# [31] 3667651 3554914 3444016 3343632 3248479 3157525 3073123 2993397 2914555 2843628
# [41] 2773669 2709270 2647620 2582847 2524157 2476936 2418578 2367692 2322076 2274352
# [51] 2229395 2187669 2148847 2107710 2068427 2030564 1996654 1962316 1927702 1894340
# [61] 1863165 1834852 1807164 1776901 1747323 1722719 1694721 1672816 1646864 1623807
# [71] 1602506 1579049 1556790 1535832 1517130 1495177 1476688 1457067 1437976 1421363
# [81] 1404197 1386446 1372361 1354048 1338653 1321241 1308175 1292688 1278896 1264299
# [91] 1249357 1237313 1222000 1210713 1198957 1186282 1172569 1161049 1148689 1136921
如果您希望将命名向量作为结果,则可以使用setNames(x, 1:100)
。
测试它的性能。这一次,我没有对预期的矢量长度进行硬编码:
myfun <- function(mydf) {
maxint <- max(vapply(mydf, max, 1L))
x <- vector(mode = "integer", length = maxint)
for (i in seq_along(mydf)) {
a <- tabulate(mydf[[i]], nbins = maxint)
x <- x + a
}
x
}
system.time(myfun(mydf))
# user system elapsed
# 1.200 0.000 1.201
与CPak的方法进行比较,后者使用table
代替。
# merge results
merge_tables <- function(L) {
require(dplyr)
DF <- do.call(rbind, lapply(L, data.frame))
ans <- DF %>%
group_by(Var1) %>%
summarise(Freq = sum(Freq))
return(ans)
}
cPakFun <- function(mydf) {
Ts <- lapply(mydf, table) # table of each split
merge_tables(Ts)
}
system.time(cPakFun(mydf))
# user system elapsed
# 150.937 1.041 152.872